Skip to main content
 首页 » 编程设计

Android Binder服务——java实现

2022年07月19日24sxdcgaq8080

一、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 LiangLiang!"); 
 
        while(true) { 
            try { 
                Thread.sleep(100);                     
            } catch(Exception e) {} 
        } 
    } 
}
转换: 
# 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; 
}

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) {} 
            } 
        } 
    } 
}

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){} 
        } 
         
    } 
}

编译:
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决定的*/ 
}

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: frameworks\base\cmds\app_process\app_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数据的构造和读写操作。


本文参考链接:https://www.cnblogs.com/hellokitty2/p/10852295.html