https://www.bilibili.com/video/BV1zb4y187MW/
一、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代码了。