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代码了。