zoukankan      html  css  js  c++  java
  • Binder服务——java实现

    一、Android系统中运行没有GUI的java程序的方法

    1.Android系统中的虚拟机不是java了,而是dalvikvm,它接收的是.dex格式的文件,所有.class文件需要转换成.dex
    文件后才能在Android上运行。使用dx命令可以将.class文件转换为.dex格式的文件,这个命令是Android编译环境自带的,使用前需要先配置
    Android的编译环境。

    测试程序Hello.java

    public class Hello {
        public static void main(String args[]) {
            System.out.println("Hello SunFaliang!");
    
            while(true) {
                try {
                    Thread.sleep(100);                    
                } catch(Exception e) {}
            }
        }
    }
    View Code
    转换:
    # dx --dex --output=Hello.jar Hello.class
    执行:
    # dalvikvm -cp ./Hello.jar Hello    //-cp: 指定class path
    
    另一种方法是使用app_process去执行:
    # CLASSPATH=./Hello.jar app_process    ./ Hello //可以-h查看帮助,‘./’是指定父目录
    
    app_process的用法:
    # app_process [java-options] cmd-dir start-class-name [options]
    
    cmd-dir: 指定要读取文件时基于此目录。
    CLASSPATH:指定需要的类从哪里找。
    
    # dx --dex --output=Hello.jar .  //将当前目录下的所有class都打包成Hello.jar

    2.若多个java文件,简易的编译方法如下

    参考frameworks/base/cmds/am/Android.mk
    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES := $(call all-subdir-java-files)
    LOCAL_MODULE := your_jar_file_name
    include $(BUILD_JAVA_LIBRARY)

    编译成库是可以的,若是指定编译成可执行文件,报AndroidManifest.xml找不到(适合编译AS写的App)

    3.使用dalvikvm和app_process运行程序的区别
    可以看其进程的/proc文件,使用app_process启动的进程里面会创建2个binder线程(comm为binder_1和binder_2),而dalvikvm是没有的。最常用的也是app_process做测
    试。app_process对应的源码文件是frameworks/base/cmds/app_process/app_main.cpp

    二、Java实现Hello服务的Demo

    1.实现Hello.aidl文件,作为一个接口来使用,编译生成的文件中会包含声明的接口,定义了Stub类,定义了Proxy类。Service和Client都要
    基于它来实现。Service端需要继承于Stub类. Client端直接使用Proxy类。

    2.编写IHelloService.aidl文件编译生成IHelloService.java文件
    参考core/java/android/os/ILedService.aidl实现,目的是生成的IHelloService.java
    在Service收到数据后就会调用其onTransaction(),根据参数code值来决定是调用其提供的哪个服务函数。
    注意到Stub类中并没有实现服务提供的接口里面的函数,所以Service继承Stub类后要去实现。
    IHelloService.java里面实现了代理类,之后我们写Client程序的时候就不用去实现代理类了,直接使用就可以了。

    3.参考SystemServer.java怎么打印log信息,System.out.println();会把log打印到串口,Slog.i();会把log打印到日志中。

    4.自己实现的HelloService.java的while(1)循环中就可以什么都不做,app_process在启动HelloService的时候创建了两个线程binder_1和
    binder_2,这两个线程负责读数据,解析数据,处理和reply。

    5.代码路径:
    git clone https://github.com/weidongshan/APP_0005_Binder_JAVA_App.git
    Android.mk参考:frameworks/base/cmds/am/Android.mk

    IHelloService.java

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: frameworks/base/core/java/android/os/IHelloService.aidl
     */
    /** {@hide} */
    public interface IHelloService extends android.os.IInterface
    {
        /** Local-side IPC implementation stub class. */
        /*
         * extends一个,implements一个,约等于多继承
         * 静态内部类的唯一好处就是可以直接访问外部类的static成员变量
         *
         */
        public static abstract class Stub extends android.os.Binder implements IHelloService
        {
            private static final java.lang.String DESCRIPTOR = "IHelloService";
            /** Construct the stub at attach it to the interface. */
            public Stub()
            {
                this.attachInterface(this, DESCRIPTOR);
            }
            /**
             * Cast an IBinder object into an IHelloService interface,
             * generating a proxy if needed.
             */
            public static IHelloService asInterface(android.os.IBinder obj)
            {
                if ((obj==null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin!=null) && (iin instanceof IHelloService))) {
                    return ((IHelloService)iin);
                }
                return new IHelloService.Stub.Proxy(obj);
            }
            
            @Override public android.os.IBinder asBinder()
            {
                return this;
            }
    
            /*
             * 这个是HelloService的onTransact实现体, 是供Service程序使用的,
             * HelloService收到数据后会调用这个函数。注意首先要确保,
             * HelloService能收到数据才行(与C/C++实现的数据格式一致才行)。
             */
            @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
            {
                switch (code)
                {
                    case INTERFACE_TRANSACTION:
                    {
                        reply.writeString(DESCRIPTOR);
                        return true;
                    }
                    case TRANSACTION_sayhello:
                    {
                        /*这面会读取出Client写入的DESCRIPTOR*/
                        data.enforceInterface(DESCRIPTOR);
                        this.sayhello(); /*调用Service的sayhello函数*/
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_sayhello_to:
                    {
                        data.enforceInterface(DESCRIPTOR);
                        java.lang.String _arg0;
                        _arg0 = data.readString(); /*读取Client发来的参数*/
                        int _result = this.sayhello_to(_arg0); /*调用Service的sayhello函数*/
                        /*
                         * 先写入异常值,然后才写入返回结果 
                         * Client端的实现也要先读取会异常值,判断没有异常发生时再调用获取结果的函数
                         */
                        reply.writeNoException(); 
                        reply.writeInt(_result); /*将执行结果写回给Client*/
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags); /*调用父类的onTransact函数回复数据*/
            }
    
    
            /*
             * Proxy类是IHelloService的实现类,是供Client端使用的.
             * 这个Proxy类已经实现好了,cilent程序直接使用就可以了。
             */
            private static class Proxy implements IHelloService
            {
                private android.os.IBinder mRemote;
                
                Proxy(android.os.IBinder remote)
                {
                    mRemote = remote;
                }
                @Override public android.os.IBinder asBinder()
                {
                    return mRemote;
                }
                public java.lang.String getInterfaceDescriptor()
                {
                    return DESCRIPTOR;
                }
                @Override public void sayhello() throws android.os.RemoteException
                {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        /*会先写入"IHelloService",Service端必须要先把它读取出来*/
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_sayhello, _data, _reply, 0);
                        /*还会在读取出一个异常,Service必须要写入一个uint_32的0,表示无异常*/
                        _reply.readException();
                    }
                    finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
                @Override public int sayhello_to(java.lang.String name) throws android.os.RemoteException
                {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeString(name); /*构造参数*/
                        /*会导致Service端的onTransact()被调用*/
                        mRemote.transact(Stub.TRANSACTION_sayhello_to, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt(); /*读回返回值*/
                    }
                    finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                        return _result;
                }
            }
    
            /*
             * 这个常量用于保证Client端和Service端相同,若是使用C/C++实现Service/Client,这个
             * 值要和Java值保持一致。
            */
            static final int TRANSACTION_sayhello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_sayhello_to = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
                
            /*Stub类中implements了IHelloService,但是没有实现其接口函数,留给HelloService来实现*/
        
        }
        
        public void sayhello() throws android.os.RemoteException;
        public int sayhello_to(java.lang.String name) throws android.os.RemoteException;
    }
    View Code

    TestClient.java

    import android.util.Slog;
    import android.os.ServiceManager;
    import android.os.IBinder;
    
    
    /* 1. getService
     * 2. 调用服务的sayhello,sayhello_to
     */
    
    /* test_client <hello|goodbye> [name] */
    
    public class TestClient {
        private static final String TAG = "TestClient";
    
        public static void main(String args[])
        {
            if (args.length == 0)
            {
                System.out.println("Usage: need parameter: <hello|goodbye> [name]");
                return;
            }
    
            if (args[0].equals("hello"))
            {
                /* 1. getService */
                IBinder binder = ServiceManager.getService("hello");
                if (binder == null)
                {
                    System.out.println("can not get hello service");
                    Slog.i(TAG, "can not get hello service");
                    return;
                }
    
                IHelloService svr = IHelloService.Stub.asInterface(binder);
    
                if (args.length == 1)
                {
                        try {
                        svr.sayhello();
                        System.out.println("call sayhello");
                        Slog.i(TAG, "call sayhello");
                      } catch (Exception e) {}
                }
                else
                {
                        try {
                        int cnt = svr.sayhello_to(args[1]);
                        System.out.println("call sayhello_to "+args[1]+" : cnt = "+cnt);
                        Slog.i(TAG, "call sayhello_to "+args[1]+" : cnt = "+cnt);
                      } catch (Exception e) {}
                }
            }
        }
    }
    View Code

    TestServer.java

    import android.util.Slog;
    import android.os.ServiceManager;
    
    /* 1. addService
     * 2. while(true) { read data, parse data, call function, reply }
     */
    
    public class TestServer {
        private static final String TAG = "TestServer";
    
        public static void main(String args[])
        {
            /* add Service */
            Slog.i(TAG, "add hello service");
            ServiceManager.addService("hello", new HelloService());
    
            /*
             * 这里什么都不用做,因为在使用app_process启动这个服务的时候会
             * 创建两个binder线程(/proc/../task/comm为binder_1和binder_2)
             * 然后由这两个线程支持read-parse-process-reply的流程。
             */
            while (true)
            {
                try {
                    Thread.sleep(100);
                  } catch (Exception e){}
            }
            
        }
    }
    View Code

    编译:
    a.先将IHelloService.aidl仿照Vibrator的放到frameworks/base/core/java/android/os下,执行mm编译后获得IHelloService.java.
    b.将测试程序放到frameworks/test目录下,mm .编译
    测试:
    将生成的文件是test_client.jar和test_service.jar拷贝到开发板上
    # logcat TestServer:* TestClient:* HelloService:* *:S &
    # CLASSPATH=./TestServer.jar app_process ./ TestServer &
    # CLASSPATH=./TestClient.jar app_process ./ TestClient hello
    # CLASSPATH=./TestClient.jar app_process ./ TestClient hello ZhangShan

    三、Binder系统分层

    1.对于同一个服务,在SM中的handle值和在Client中的handle值是不同的。handle是per进程的,每个进程获得的handle都是从1(0是SM特有的)开始的! 

    2.所有的服务在内核中都是使用binder_node结构表示的,不同服务的binder_node的区别是ptr和cookie域不同。因此client在使用对应服务时,binder驱动会将指定服务的binder_node的ptr和cookie赋值给Client传给Service的数据中的对应的域。

    3.Binder系统过程分析

    (1)addService("Hello", *ptr),在C实现的Demo中调用bio_put_obj(),将ptr赋值给flat_binder_object.binder,cookie赋值为0。内核中
    表示服务的binder_node结构的*ptr和*cookie的值就是由Service应用程序传参控制的,可用于区分不同的Service。

    void bio_put_obj(struct binder_io *bio, void *ptr)
    {
        /*内核中根据这个结构体创建binder_node结构体*/
        struct flat_binder_object *obj;
    
        obj = bio_alloc_obj(bio);
        if (!obj)
            return;
    
        obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
        obj->type = BINDER_TYPE_BINDER;
        obj->binder = (uintptr_t)ptr;
        obj->cookie = 0; /*这里的binder和cookie都是由Service决定的*/
    }
    View Code

    a.binder驱动收到flat_binder_object结构体,且其type = BINDER_TYPE_BINDER(表示Service),就会在内核中创建一个binder_node结构体,
    其target.ptr和cookie来自Service传入的flat_binder_object结构体。

    b.由于addService()时指定的handle=0,binder驱动会将收到的数据转发给SM进程,并为SM进程构造一个binder_ref结构体,其node指向Hello
    Service的binder_node结构体,其desc域为1(假设Hello Servie是系统中第一个向SM注册的服务)表示此Service是第一个注册进SM的服务。SM用
    户空间程序会在svlist链表上创建一个svcinfo结构记录下这个Hello服务,其name="hello",handle就等于binder_ref中的desc(就是1)。

    (2)getService("hello")

    c.cilent向SM获取服务(构造数据handle=0),SM在svlist通过名字"hello"进行查找,找到对应的Hello服务,其handle为1,然后就构造一个flat_binder_object结构体
    其type=BINDER_TYPE_HANDLE(表示引用),然后发给驱动。驱动检测数数据中有一个flat_binder_object结构体且type=BINDER_TYPE_HANDLE(表示引用)
    就会为Client进程也创建一个binder_ref结构体,其node域指向表示Hello服务的binder_node结构体,其desc为1(假定Hello服务是Client进程中获取
    的第一个服务),表示Hello服务是Client获取的第一个服务。然后返回handle=1给到Client用户空间程序,之后Client程序就可以通过handle来使用Hello
    服务了。

    (3)Client端使用Hello服务

    d.构造数据(handle=1, 要使用Service的函数编号,参数),然后发给驱动。驱动根据handle=1在本进程的binder_ref树中找到对应的binder_ref结构体,然后
    根据binder_ref.node找到表示Hello服务的binder_node结构体,然后根据binder_node.proc找到Hello服务的binder_proc结构体,然后根据binder_proc.tsk
    找到Hello服务进程。然后驱动构造一个binder_transaction_data,并使Hello服务的binder_node.ptr域赋值给binder_transaction_data.target.ptr,
    binder_node.cookie赋值给binder_transaction_data.cookie,然后binder驱动把数据发给Hello服务进程。

    e.Hello服务进程收到数据解析出binder_transaction_data结构,根据其target.ptr和(或)cookie域知道Client要使用哪个服务(因为一个进程可能注册多个服务,
    只不过这个Hello服务进程只注册了一个服务而已)。然后根据binder_transaction_data.code知道Client要调用服务的哪个函数。然后调用对应的函数,并把执行
    结果返回给Client。

    然后释放buffer。

    binder_ref是区分进程的,binder_node表示服务是不区分进程的。用户空间的handle来源于binder_ref,所以它也是per进程的(除了SM的恒为0)。

    4.Java的Binder系统分为3层

    服务层
    --------------
    RPC层
    -------------
    IPC层(最核心的类是IPCThreadState)
    -------------

    若是使用C++实现一个服务的话,只有IPC不需要自己写,RPC层和服务层都需要自己写。若是使用Java来实现一个服务我们就只需要实现服务层。

    ptr在C例子实现中用于区分同一进程中注册的不同服务。在framework中的C++实现中cookie保存的是BnBinder派生的HelloService对象,
    用于调用onTransact().

    Java的实现中发送数据也是通过IPCThreadState(C++实现)提供的函数来发送的,这就涉及到了JNI的使用。

    四、java实现内部机制_Client端

    1.Client端的实现
    包括TestServer向SM发送addService请求、TestClient向SM发送getService请求、TestClient向TestServer发送调用say_hello()的请求。
    
    (1)addService/getService请求
    
    ServiceManager.addService("hello", new HelloService());    //TestServer.java
        ServiceManagerProxy(obj).addService(name, service, false); //ServiceManagerNative.java
            mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0); //ServiceManagerNative.java 调用它发送数据
        
    
    IBinder binder = ServiceManager.getService("hello"); //TestClient.java
        ServiceManagerProxy(obj).getService(name); //ServiceManagerNative.java
            mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0); //ServiceManagerNative.java 调用它发送数据
    
    
    (2)Client使用sayhello()/sayhello_to()
    
    IHelloService svr = IHelloService.Stub.asInterface(binder); //TestClient.java 
        svr.sayhello(); //TestClient.java 
            IHelloService.Stub.Proxy(obj).sayhello(); //IHelloService.java
    
    
    Client端和Service端最终都是调用IBinder mRemote来发送数据,Client端和Service端就统一起来了。
    
    调用mRemote.transact(Stub.TRANSACTION_sayhello, _data, _reply, 0);来发送数据
    数据传输3要素:
    源:调用mRemote.transact的进程
    目的:mRemote
    数据本身:参数
    
    Binder中的目的是使用handle表示的,对于addService()/getService()这个mRemote中肯定有handle=0这个成员。
    
    mRemote是一个java BinderProxy对象(但是看代码是IBinder对象),它的
    mObject指向一个C++的BpBinder对象,这个BpBInder的mHandle=0表示要发给SM进程。
    
    
    对于Client使用sayhello()/sayhello_to(),mRemote是一个java BinderProxy对象(但是看代码是IBinder对象),它的
    mObject指向一个C++的BpBinder对象,这个BpBInder的mHandle=1(来自getService("hello"))表示要发给HelloService进程。
    
    
    1.ServiceManagerProxy中mRemote的构造 (用于addService/getService)
    猜测:使用0直接构造出一个java BinderProxy对象
    ServiceManager.addService("hello", new HelloService());    或 ServiceManager.getService("hello"); //TestServer.java
         getIServiceManager().addService(name, service, false); //ServiceManager.java
    
    a. getIServiceManager()
        ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    
    a1. 分析BinderInternal.getContextObject()    //BinderInternal.java,getContextObject()是一个native函数
        //这个函数最终得到一个java BinderProxy对象, 其中mObject指向new BpBinder(0);。
            android_os_BinderInternal_getContextObject //android_util_Binder.cpp
                sp<IBinder> b = ProcessState::self()->getContextObject(NULL); //android_util_Binder.cpp
                    return getStrongProxyForHandle(0); //ProcessState.cpp,直接指定的是handle=0,是SM
                        b = new BpBinder(0); //BpBinder.cpp  BpBinder.mHandle=0
                return javaObjectForIBinder(env, b); //android_util_Binder.cpp  b = new BpBinder(0), mHandle = 0
                    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); //android_util_Binder.cpp
                    //JNI代码中使用NewObject()来创建Java的BinderProxy对象。
                        const char* const kBinderProxyPathName = "android/os/BinderProxy";
                        clazz = env->FindClass(kBinderProxyPathName);
                        gBinderProxyOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); //调用的是BinderProxy的构造函数。
    
    
    a2.分析ServiceManagerNative.asInterface
        new ServiceManagerProxy(obj); // obj = BinderProxy对象
            mRemote = obj = BinderProxy对象, 其中mObject指向new BpBinder(0), 0表示是SM。
    
    所以getService/setService使用的mRemote已经构造出来了。
    
    
    
    2.Hello服务里面的mRemote如何构造的
    a. IBinder binder = ServiceManager.getService("hello");
       //猜测: 它的返回值就是一个java BinderProxy对象, 其中的mObject=new BpBinder(handle) 
            new ServiceManagerProxy().getService("hello"); //ServiceManagerNative.java
            //构造数据通过mRemote发送出去,从返回的结果中得到
            IBinder binder = reply.readStrongBinder(); //ServiceManagerNative.java
                return nativeReadStrongBinder(mNativePtr); //Parcel.java 它标注为native,是一个JNI函数
                    // 把java Parce对象转换为c++ Parcel对象
                    // client程序向sevice_manager发出getService请求,
                    // 得到一个回复reply, 它里面含有flat_binder_object
                    // 它被封装成一个c++ Parcel对象
                    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
                    //它应该会把上面的flat_binder_object转换成一个BpBinder对象。
                    //它会创建一个java BinderProxy对象, 其中的mObject=new BpBinder(handle)对象
                    return javaObjectForIBinder(env, parcel->readStrongBinder()); //android_os_Parcel.cpp
                    
    
    a1. parcel->readStrongBinder()返回一个 new BpBinder(handle)对象,其中handle是HelloService的handle
            unflatten_binder(ProcessState::self(), *this, &val); //Parcel.cpp
                finish_unflatten_binder //Parcel.cpp
                    b = new BpBinder(handle); 
                    
    b. IHelloService svr = IHelloService.Stub.asInterface(binder); //TestClient.java 
        return new IHelloService.Stub.Proxy(obj); //IHelloService.java
            mRemote = obj; //那么,a中返回的就是一个BinderProxy对象。
    
    
    3.现在知道了mRemote就是一个java的BinderProxy对象(定义在Binder.java中),mRemote.transact()的实现方法如下
    
    BinderProxy.transact(int code, Parcel data, Parcel reply, int flags); //Binder.java
        return transactNative(code, data, reply, flags); //它是一个JNI调用,对应android_os_BinderProxy_transact
            android_os_BinderProxy_transact //android_util_Binder.cpp
                //取出data和reply, 把java对象转换为C++对象。
                Parcel* data = parcelForJavaObject(env, dataObj);
                Parcel* reply = parcelForJavaObject(env, replyObj);
                //从java BinderProxy对象中把mObject取出, 它就是一个BpBinder对象
                IBinder* target = (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);
                //然后调用BpBinder的transact
                status_t err = target->transact(code, *data, reply, flags);
    
    4."怎么发"结论如下
    对于getService/setService,会得到一个ServiceManagerProxy代理类,对应Hello服务也会得到一个
    代理类IHelloService.Stub.Proxy。这些代理类中都有一个mRemote成员,
    它是一个java的BinderProxy对象,它的mObject成员指向一个C++的BpBinder对象,
    BpBinder中有一个mHandle(对于addService/getService它是0,对于Hello服务,它
    来自getService的结果)。
    
    发送数据时,调用mRemote.transact(),它会从mObject中取出BpBinder对象,调用它的
    transact函数,从而实现了Java实现的RPC对C++实现的IPC的调用。

    五、Java实现内部机制_Service端实现

    1. Server怎么读到数据
    
    看HelloService.java源码,它addService()之后就去睡眠去了,那是谁在读取处理数据呢,是使用app_process创建的两个binder线程binder_1和binder_2做的,
    源码:
    app_process: frameworksasecmdsapp_processapp_main.cpp
    
    app_process来启动server进程,它会先创建子线程:
    AppRuntime::onStarted()
        proc->startThreadPool();
            spawnPooledThread(true);
                sp<Thread> t = new PoolThread(isMain);
                t->run(name.string());
                    //它会创建子线程, 并执行threadLoop
                    IPCThreadState::self()->joinThreadPool(mIsMain);
                    {
                        do {
                            result = getAndExecuteCommand();
                                result = talkWithDriver();
                                result = executeCommand(cmd);
                                    对于BR_TRANSACTION数据,
                                    sp<BBinder> b((BBinder*)tr.cookie); //cookie来区分是哪个服务,一个进程可能注册了多个Service。
                                    error = b->transact(tr.code, buffer, &reply, tr.flags);
                        } while(...)
                    }
    
    
    
    
    
    2. server读到数据后怎么调用服务PRC层的onTransact函数
    
    a. 在addService时设置.ptr/.cookie
    ServiceManager.addService("hello", new HelloService());
    分析:
    a.1 new HelloService()是JAVA对象
    a.2 处理数据时把.cookie转换成BBinder对象, 它是c++对象
    所以: addService中肯定会把JAVA对象转换成一个BBinder派生类对象,存在.cookie里
    
    结论:
    a.1 addService会通过JNI调用c++函数:
            创建一个BBinder派生类JavaBBinder对象,
                它的.mObject指向JAVA对象: new HelloService()
                它含有onTransact函数
            把这个对象存入.cookie(最终存入binder驱动中该服务对应的binder_node.cookie)
    
    a.2 server进程从驱动中读到数据,里面含有.cookie
        把它转换为BBinder对象,
        调用它的transact函数 
        它会调用到派生类JavaBBinder中定义的onTransact函数
    
    a.3 JavaBBinder中定义的onTransact函数(c++)
        它通过JNI调用java Binder的execTransact方法,
        然后调用Binder派生类IHelloService.Stub中定义的onTransact函数(JAVA)
    
    a.4 IHelloService.Stub中定义的onTransact函数(JAVA):
            分析数据
            调用sayhello/sayhello_to
    
    源码阅读:
    a.1 ServiceManager.addService("hello", new HelloService());
        ServiceManagerProxy.addService:
            // Parcel.java
            data.writeStrongBinder(service);
                nativeWriteStrongBinder(mNativePtr, val); // val = service = new HelloService()
                它是一个JNI调用,对应android_os_Parcel_writeStrongBinder(c++实现)
    
    a.2 android_os_Parcel_writeStrongBinder(c++)
        它会构造一个JavaBBinder对象(c++),.mObject=new HelloService() JAVA对象
        然后让.cookie=JavaBBinder对象(c++)
        
        //把Java Parcel转换为c++ Parcel
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        
        //.cookie = ibinderForJavaObject(env, object)得到一个JavaBBinder对象
        parcel->writeStrongBinder(ibinderForJavaObject(env, object))
    
    a.3 ibinderForJavaObject(env, object) //object = new HelloService() 
        把一个Java对象(new HelloService())转换为c++ IBinder对象
        
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env, obj) : NULL;
             b = new JavaBBinder(env, obj); // obj = new HelloService() 
                mObject = new HelloService() 
    
    
    a.4 从驱动中得到.cookie, 它是一个JavaBBinder对象
        调用它的transact函数,导致JavaBBinder对象的onTransact被调用
        
        JavaBBinder::onTransact (调用java里的某个函数)
        
            // mObject指向 HelloService对象
            // gBinderOffsets.mExecTransact指向: java Binder类中的execTransact方法
            // 调用HelloService(派生自Binder)对象中的execTransact方法
            jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
                code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
    
    a.5 java Binder execTransact:  
            res = onTransact(code, data, reply, flags);
                调用HelloService中的onTransact方法(来自IHelloService.Stube)
                    分辨数据
                    调用sayhello/sayhello_to

    六、修改C/C++实现与Java实现兼容

    1.aidl文件生成的IHelloService.java的onTransact()是在Service收到数据后调用的。Client需要先获取IHelloService.java中的Proxy类,通过它来发送数据。

    2.ILedService在SystemServer.java中add_service的,SystemServer中没有read-parse-process-reply循环。system_server进程也是使用app_process进程来创建
    的,/proc/下也有binder_X线程执行循环。

    # cat init.zygote32.rc | grep app_process
    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server


    3.要是C/C++/Java程序实现的Client和Servie兼容,需要确保发送和接收的数据格式是一样的。由于IHelloService.java是根据aidl文件自动生成的,所以以java
    文件为准修改C/C++文件。

    要点:保证Service和Clicent双方数据(发送和获取)一致!

    4.Parcel.cpp主要用于对Binder数据的构造和读写操作。

  • 相关阅读:
    Yii2的深入学习--事件Event
    PHP的学习--可变函数
    PHP的学习--可变变量
    Yii2的深入学习--yiiaseObject 类
    xdotool模拟击键和鼠标移动
    Yii2的深入学习--继承关系
    Yii2的深入学习--自动加载机制
    用Qt写软件系列五:一个安全防护软件的制作(1)
    TinyOS和Deluge的安装模拟(二)
    TinyOS和Deluge的安装模拟(一)
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10852295.html
Copyright © 2011-2022 走看看