Binder java层实现原理

https://www.bilibili.com/vide...

一、aidl文件
下面是自己写的一个aidl文件

package android.os;

interface IHelloService
{
void setVal(int val);
int getVal();
}
注意,这是一个aidl文件,编译后会生成一个IHelloService.java。我们来看一下这个文件的内容隐藏着什么奥秘,可以这么神奇地支持进程间通信。

在java中有一个aidl文件,让我们省去了很多工作,其实下了下面这段将aidl文件展开其实很c++很像。

/*

This file is auto-generated. DO NOT MODIFY.
Original file: frameworks/base/core/java/android/os/IHelloService.aidl
/
package android.os;
public interface IHelloService extends android.os.IInterface
{
/* Local-side IPC implementation stub class. /
public static abstract class Stub extends android.os.Binder implements android.os.IHelloService//相当于是一个Server端,需要一个子类来继续继承它,完成接口的实现
{
private static final java.lang.String DESCRIPTOR = "android.os.IHelloService";
/ Construct the stub at attach it to the interface. /
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/* Cast an IBinder object into an android.os.IHelloService interface, generating a proxy if needed. / public static android.os.IHelloService asInterface(android.os.IBinder obj)//和c++类似,如果在client端才去new一个proxy { if ((obj==null)) { return null; } android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof android.os.IHelloService))) { return ((android.os.IHelloService)iin); } return new android.os.IHelloService.Stub.Proxy(obj); } public android.os.IBinder asBinder() { return this; } @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_setVal: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); this.setVal(_arg0); reply.writeNoException(); return true; } case TRANSACTION_getVal: { data.enforceInterface(DESCRIPTOR); int _result = this.getVal(); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements android.os.IHelloService//这个内部类,相当于一个client端和C++类似 { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } public void setVal(int val) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(val); mRemote.transact(Stub.TRANSACTION_setVal, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } public int getVal() 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); mRemote.transact(Stub.TRANSACTION_getVal, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_setVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void setVal(int val) throws android.os.RemoteException;
public int getVal() throws android.os.RemoteException;
}
这里我们可以看到IHelloService.aidl这个文件编译后的真面目,原来就是根据IHelloService接口的定义生成相应的Stub和Proxy类,这个就是我们熟悉的Binder机制的内容了,即实现这个HelloService的Server必须继续于这里的IHelloService.Stub类,而这个HelloService的远程接口就是这里的IHelloService.Stub.Proxy对象获得的IHelloService接口。接下来的内容,我们就可以看到IHelloService.Stub和IHelloService.Stub.Proxy是怎么创建或者使用的。
二. HelloService的启动过程
在讨论HelloService的启动过程之前,我们先来看一下实现HelloService接口的Server是怎么定义的。

我们在frameworks/base/services/java/com/android/server目录下新增了一个HelloService.java文件:

package com.android.server;

import android.content.Context;
import android.os.IHelloService;
import android.util.Slog;

public class HelloService extends IHelloService.Stub {//实现aidl文件解析后,里面的内部类
private static final String TAG = "HelloService";

HelloService() { init_native(); } public void setVal(int val) { setVal_native(val); } public int getVal() { return getVal_native(); } private static native boolean init_native(); private static native void setVal_native(int val); private static native int getVal_native();

}
这里,我们可以看到,HelloService继续了IHelloService.Stub类,它通过本地方法调用实现了getVal和setVal两个函数。
有了HelloService这个Server类后,下一步就是考虑怎么样把它启动起来了。在frameworks/base/services/java/com/android/server/SystemServer.java文件中,定义了SystemServer类。SystemServer对象是在系统启动的时候创建的,它被创建的时候会启动一个线程来创建HelloService,并且把它添加到Service Manager中去。
我们来看一下这部份的代码:

class ServerThread extends Thread {
......

@Override public void run() { ...... Looper.prepare(); ...... try { Slog.i(TAG, "Hello Service"); ServiceManager.addService("hello", new HelloService());//加入serviceManager中 } catch (Throwable e) { Slog.e(TAG, "Failure starting Hello Service", e); } ...... Looper.loop(); ...... }

}

......

public class SystemServer
{
......

/* This method is called from Zygote to initialize the system. This will cause the native services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back up into init2() to start the Android services. */ native public static void init1(String[] args); ...... public static final void init2() { Slog.i(TAG, "Entered the Android system server!"); Thread thr = new ServerThread(); thr.setName("android.server.ServerThread"); thr.start(); } ......

}

三. Client获取HelloService的Java远程接口的过程
我们看看它是如何借助Service Manager这个Java远程接口来获得HelloService的远程接口的。在Hello这个Activity的onCreate函数,通过IServiceManager.getService函数来获得HelloService的远程接口:

public class Hello extends Activity implements OnClickListener {
......

private IHelloService helloService = null; ...... @Override public void onCreate(Bundle savedInstanceState) { helloService = IHelloService.Stub.asInterface( ServiceManager.getService("hello"));//调用自定义的helloservice,不过需要自己asInterface转成自己的接口 } ......

}
至于,java调用c++的那些JNI就不分析了。

四、在c层service中实现java层回调
还有有时候我们自己写了一个c层的binder service,然后通过java调用service中代码,然后其实又需要在c层中注册回调。这个时候可以在c层service的注册接口中增加binder参数,然后在java中实现aidl文件,再把binder参数通过service调用传入c层service,到时候就可以在c层service中回调java代码了。

你可能感兴趣的:(Binder java层实现原理)