首页 > 编程语言 > 详细

Binder服务——java实现

时间:2019-05-12 15:13:47      阅读:125      评论:0      收藏:0      [点我收藏+]

一、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: 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数据的构造和读写操作。

 

Binder服务——java实现

原文:https://www.cnblogs.com/hellokitty2/p/10852295.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!