Binder service入门—框架层、应用层调用native binder service

2014/04/21

本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接

1.前言

上一篇介绍了如何创建应用层binder service,本篇将综合先前介绍的native binder service,framework binder service,应用层binder service等知识,讲述如何使用native 的client,framework层的client,应用层的client测试native binder service。

Binder service入门系列:

2.程序构成

因为编译native的binder service,framework层的client都需要在源码环境下编译,故此本篇讲述的工程需要在源码环境下编译。

整个工程可以在github上下载:

https://github.com/cloudchou/NativeBinderJavaClientDemo

程序由4个部分组成:

1) native_bserver 创建并注册native binder service的本地服务端 2) native_bclient 测试native binder service的本地客户端 3) fclient和fclient.jar测试native binder service的框架层客户端 4) NativeBinderServiceTest 测试native binder service的应用层客户端

3.程序源码构成

源程序目录结构如下所示:

nativetest_f

顶层Android.mk只是简单包含各个子目录的Android.mk,BServer目录存放本地服务端和本地客户端源码,FClient存放框架层客户端源码,NatviveBinderServiceTest存放应用层客户端源码。

本地服务端和本地客户端

1) BServer的Android.mk源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
LOCAL_PATH := $(call my-dir)
 
#生成binder service的本地服务端
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := \\
    libcutils \\
    libutils \\
    libbinder       
LOCAL_MODULE    := native_bserver
LOCAL_SRC_FILES := \\
    ICloudManager.cpp \\
    TestServer.cpp   
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
 
#生成binder service的本地客户端
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := \\
    libcutils \\
    libutils \\
    libbinder
LOCAL_MODULE    := native_bclient
LOCAL_SRC_FILES := \\
    ICloudManager.cpp \\
    TestClient.cpp
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)

2) binder service接口ICloudManager(ICloudManager.h):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace android
{
    class ICloudManager : public IInterface
    {
    public:
        DECLARE_META_INTERFACE(CloudManager); // declare macro
        virtual void test()=0;
        virtual void print(const char* str)=0;
        virtual int add(int a, int b)=0;
    };

    enum
    {
        TEST = IBinder::FIRST_CALL_TRANSACTION+1,
        PRINT = IBinder::FIRST_CALL_TRANSACTION+2,
        ADD = IBinder::FIRST_CALL_TRANSACTION+3,
    };

    class BpCloudManager: public BpInterface<ICloudManager> {
    public:
        BpCloudManager(const sp<IBinder>& impl);
        virtual void test();
        virtual void print(const char* str);
        virtual int add(int a, int b);
    };
}

3) 实现实现ICloudManager接口的方法(ICloudManager.cpp)

1
2
3
4
namespace android
{
    IMPLEMENT_META_INTERFACE(CloudManager, "com.cloud.test.ICloudManager");
}

4) 实现服务端(TestServer.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
 namespace android
{
     //binder service 实体类
    class BnCloudManager : public BnInterface<ICloudManager>
    {
    public:
        virtual status_t
        onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
        virtual void   test();
        virtual void   print(const char* str);
        virtual int   add(int a, int b);
    };

    status_t
    BnCloudManager::onTransact(uint_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
        switch (code)
            {
        case TEST:
            {
                CHECK_INTERFACE(ICloudManager, data, reply);
                test();
                reply->writeInt32(0);
                return NO_ERROR;
            }
            break;
        case PRINT:
            {
                CHECK_INTERFACE(ICloudManager, data, reply);
                String16 str = data.readString16();
                String8 str8 = String8(str);
                print(str8.string());
                reply->writeInt32(0);
                return NO_ERROR;
            }
            break;
        case ADD:
            {
                CHECK_INTERFACE(ITest, data, reply);
                int a;
                int b;
                data.readInt32(&a);
                data.readInt32(&b);
                int c = add(a,b);
                reply->writeInt32(0);
                reply->writeInt32(c);
                return NO_ERROR;
            }
            break;
        default:
            break;
            }
        return NO_ERROR;
    }

    void
    BnCloudManager::test() {
        printf("Now server receive requset from client: [call test]\\n");
    }

    void
    BnCloudManager::print(const char* str) {
        printf("Now server receive requset from client: [call print %s]\\n", str);
    }

    int
    BnCloudManager::add(int a, int b) {
        printf("Now server receive requset from client: [call add %d %d]\\n", a, b);
        return a + b;
    }

}
int
main() {
    sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
//注册binder service
    sm->addService(String16("cloudservice"), new BnCloudManager());
    printf("Native binder server starts to work\\n");
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

5) 实现客户端(TestClient.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
namespace android
{
    BpCloudManager::BpCloudManager(const sp<IBinder>& impl) :
            BpInterface<ICloudManager>(impl) {
    }
    void
    BpCloudManager::test() {
        printf("Client call server test method\\n");
        Parcel data, reply;
        data.writeInterfaceToken(ICloudManager::getInterfaceDescriptor());
        remote()->transact(TEST, data, &reply);
        int code = reply.readExceptionCode();
        printf("Server exepction code: %d\\n", code);
    }

    void
    BpCloudManager::print(const char* str) {
        printf("Client call server print method\\n");
        Parcel data, reply;
        data.writeInterfaceToken(ICloudManager::getInterfaceDescriptor());
        data.writeString16(String16(str));
        remote()->transact(PRINT, data, &reply);
        int code = reply.readExceptionCode();
        printf("Server exepction code: %d\\n", code);
    }

    int
    BpCloudManager::add(int a, int b) {
        printf("Client call server add method\\n");
        Parcel data, reply;
        data.writeInterfaceToken(ICloudManager::getInterfaceDescriptor());
        data.writeInt32(a);
        data.writeInt32(b);
        remote()->transact(ADD, data, &reply);
        int code = reply.readExceptionCode();
        int result;
        reply.readInt32(&result);
        printf("Server exepction code: %d\\n", code);
        return result;
    }

}

int
main() {
sp<IServiceManager> sm = defaultServiceManager();
//查询服务
sp<IBinder> binder = sm->getService(String16("cloudservice"));
//转换接口
sp<ICloudManager> cs = interface_cast<ICloudManager>(binder);
//测试接口方法
    cs->test();
    cs->print("Hello world");
    int result=cs->add(2,3);
    printf("client receive add result from server : %d\\n",result);
    return 0;
}

框架层客户端

1) Android.mk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
#生成fclient.jar
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := fclient 
LOCAL_MODULE_TAGS := optional
include $(BUILD_JAVA_LIBRARY)
#生成fclient
include $(CLEAR_VARS)
LOCAL_MODULE := fclient
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT)/bin
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_SRC_FILES := fclient
include $(BUILD_PREBUILT)

2) 定义接口类(ICloudManager.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface ICloudManager extends IInterface {
    //接口描述字符串
    static final java.lang.String DESCRIPTOR = "com.cloud.test.ICloudManager";

    void test() throws RemoteException;

    void print(String str) throws RemoteException;

    int add(int a, int b) throws RemoteException;

    static final int TRANSACTION_test = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_print = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}

3) 定义接口代理类(CloudManagerProxy.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class CloudManagerProxy implements ICloudManager {
    private android.os.IBinder mRemote;

    public CloudManagerProxy(android.os.IBinder remote) {
        mRemote = remote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

    @Override
    public void print(String str) throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeString(str);
            mRemote.transact(TRANSACTION_print, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }

    @Override
    public int add(int a, int b) throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int result = 0;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeInt(a);
            _data.writeInt(b);
            mRemote.transact(TRANSACTION_add, _data, _reply, 0);
            _reply.readException();
            result = _reply.readInt();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
        return result;
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }

    @Override
    public void test() throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain(); 
        try {
            _data.writeInterfaceToken(DESCRIPTOR); 
            mRemote.transact(TRANSACTION_test, _data, _reply, 0);
            _reply.readException(); 
        } finally {
            _reply.recycle();
            _data.recycle();
        }

    }
}

4) 客户端(FClient.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class FClient { 

    /**
     * Command-line entry point.
     * 
     * @param args
     *            The command-line arguments
     * @throws RemoteException
     */
    public static void main(String[] args) throws RemoteException {
        System.out.println("==========Client starts===========");
        IBinder binder = ServiceManager.getService("cloudservice");
        ICloudManager manager = new CloudManagerProxy(binder);
        System.out.println("========== client call server  test ===========");
        manager.test();
        System.out.println("========== client call server print ===========");
        manager.print("Hello world");
        System.out.println("========== client call server add ===========");
        int result = manager.add(2, 3);
        System.out.println("manager.add(2, 3)=" + result);
    }
}

5) 客户端脚本fclient

1
2
3
4
5
6
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/fclient.jar
exec app_process $base/bin com.cloud.test.FClient "$@"

应用层客户端

先前我们有讲到在应用层是不能直接使用ServiceManager这个类的,因为Sdk并未包含该类,应用层只能通过bind service去使用binder service,但是我们的native service并不是使用应用层的Service子类创建的,这样看来貌似应用层不能使用native的binder service。

这里介绍一个技巧,其实我们的应用在运行时可以使用系统隐藏的类,比如ServiceManager,SystemProperties,只是编译时Sdk并未提供这些类,我们若使用这些类就无法编译。但是我们可以创建这些类所在的包,并创建这些类,在类里定义我们要使用的那些方法,我们就可以通过编译了。比如ServiceManager这个类,我们就可以为之创建android.os这个package,并在这个package下创建ServiceManager类,定义我们需要的方法getService。也许读者会担心运行时使用的ServiceManger类就是我们创建的ServiceManager类,但实际上运行时使用的ServiceManager类是framework.jar里的ServiceManager类,这是因为classloader在查找类时优先使用系统的类。

1) Android.mk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_PACKAGE_NAME := NativeBinderServiceTest  
#LOCAL_PROGUARD_FLAG_FILES := proguard.flags

include $(BUILD_PACKAGE)

# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH)) 

2) 我们创建的ServiceManager源码

1
2
3
4
5
6
7
public class ServiceManager {

    public static IBinder getService(String name) {
        return null;
    }

} 

3) 定义接口ICloudManager

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface ICloudManager extends IInterface {
    static final java.lang.String DESCRIPTOR = "com.cloud.test.ICloudManager";

    void test() throws RemoteException;

    void print(String str) throws RemoteException;

    int add(int a, int b) throws RemoteException;

    static final int TRANSACTION_test = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_print = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
} 

4) 定义代理类CloudManagerProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class CloudManagerProxy implements ICloudManager {
    private android.os.IBinder mRemote;

    public CloudManagerProxy(android.os.IBinder remote) {
        mRemote = remote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

    @Override
    public void print(String str) throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeString(str);
            mRemote.transact(TRANSACTION_print, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }

    @Override
    public int add(int a, int b) throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int result = 0;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeInt(a);
            _data.writeInt(b);
            mRemote.transact(TRANSACTION_add, _data, _reply, 0);
            _reply.readException();
            result = _reply.readInt();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
        return result;
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }

    @Override
    public void test() throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain(); 
        try {
            _data.writeInterfaceToken(DESCRIPTOR); 
            mRemote.transact(TRANSACTION_test, _data, _reply, 0);
            _reply.readException(); 
        } finally {
            _reply.recycle();
            _data.recycle();
        }

    }

} 

5) 测试用的Activity(TestAc.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class TestAc extends Activity {

    private static final String TAG = TestAc.class.getSimpleName();
    private ICloudManager manager = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.d(TAG, "[ThreadId " + Thread.currentThread().getId() 
                  + "] [ProcessId" + Process.myPid() + "]  onCreate");
        findViewById(R.id.btn_print).setOnClickListener(
          new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.d(TAG, "=========== Client call CloudService"
                               +" print function");
                    manager.print("Hello world");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        findViewById(R.id.btn_add).setOnClickListener(
        new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.d(TAG, "======Client call CloudService"
                               +" add function");
                    int a = manager.add(3, 2);
                    Log.d(TAG, "======Client add function reuslt : "
                                + a);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        findViewById(R.id.btn_test).setOnClickListener(
          new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.d(TAG, "======Client call CloudService"
                               +" test function");
                    manager.test();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        IBinder binder = ServiceManager.getService("cloudservice");
        manager = new CloudManagerProxy(binder);
        findViewById(R.id.btn_print).setEnabled(true);
        findViewById(R.id.btn_add).setEnabled(true);
        findViewById(R.id.btn_test).setEnabled(true);
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {

        super.onDestroy();

    }
} 

4.测试

上传程序:

1
2
3
4
5
6
7
adb push native_bclient /system/bin
adb push native_bserver /system/bin
adb push fclient /system/bin
adb push fclient.jar /system/framework
adb shell chmod 755 /system/bin/native_bserver
adb shell chmod 755 /system/bin/native_bclient
adb shell chmod 755 /system/bin/fclient

使用native_client测试:

nativetest

使用框架层的client测试:

frameworktest

使用应用层的client测试:

服务端:

apptest_server

客户端:

apptest_client

¥打赏5毛

取消

感谢您的支持,我会继续努力的!

扫码支持
赏个5毛,支持我把

打开支付宝扫一扫,即可进行扫码打赏哦

本篇目录