Bootstrap

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

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


1.前言

Binder service入门系列:

上一篇介绍了如何创建应用层binder service,本篇将综合先前介绍的native binder service,framework binder service,应用层binder service等知识,讲述如何使用native 的client,framework层的client,应用层的client测试native 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

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;