###前言
进程间通信十分重要,在Android Framework中随处可见。
进程间通信的时候,我们经常使用的是AIDL的方式,下面先给出一个简单的栗子:
首先定义我们的AIDL文件,在Android Studio创建一个AIDL文件:
定义如下:
package com.nan.testbinder;
interface IAidlInterface {
String pay(int pwd);
}
复制代码
在这个AIDL里面,我们定义一个接口,里面有一个pay方法来模拟支付宝的支付。输入参数是支付密码,返回支付结果。然后我们rebuild一下项目,AS就会自动为我们定义的AIDL文件生成一个Java文件,这里我们先不详细介绍这个文件:
然后创建我么的远程服务:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.nan.testbinder.IAidlInterface;
public class MyService3 extends Service {
public static final String TAG = MyService3.class.getSimpleName();
public MyService3() {
Log.e(TAG, "MyService3");
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return new Interface();
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate");
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
}
public class Interface extends IAidlInterface.Stub {
@Override
public String pay(int pwd) throws RemoteException {
if (pwd == 123) {
return "支付成功";
}
return "支付失败";
}
}
}
复制代码
在这个服务里面,我们创建了一个接口类Interface,继承了自动生成的Java文件里面的Stub类。并且复写里面的pay方法。 最后在Service的onBind方法里面返回这个类的对象。
我们在清单文件中把这个服务定义为远程服务,即指定了服务所在的进程为:remote
<service
android:name=".service.MyService3"
android:enabled="true"
android:exported="true"
android:process=":remote">
</service>
复制代码
然后在Activity中定义一个ServiceConnection类,用于跟远程服务连接。这里通过Stub的asInterface方法把IBinder对象转换为AIDL的接口。 转换成功之后,我们就尝试调用接口的pay方法,成功/失败的时候通过一个Toast来打印支付结果。
class MyRemoteServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//通过Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类
mRemoteInterface = IAidlInterface.Stub.asInterface(service);
if (mRemoteInterface != null) {
String result;
try {
result = mRemoteInterface.pay(123);
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//连接因为异常而终止才会调用
}
}
复制代码
最后在Activity中绑定服务/解绑服务:
mRemoteConn = new MyRemoteServiceConnection();
Intent intent4 = new Intent(MainActivity.this, MyService3.class);
//绑定
bindService(intent4, mRemoteConn, BIND_AUTO_CREATE);
//解绑
unbindService(mRemoteConn);
复制代码
###为什么要使用AIDL?
我们在进行进程间通信的时候,我们是无法拿到另外一个进程的类的对象,因为两个进程不在一个内存里面,它们都分配在不同的虚拟机中。这样的话,即使我们的类使用了静态变量,编译通过了,也无法进行通信。
如下图所示,两个进程就像是一个中国人跟一个日本人,假设双方都不懂对方的语言。比如现在中国人要发送一句话”不要“给日本人,但是在日语里面”不要“就是”雅蠛蝶“,因此正常情况下是不能正常沟通的(程序直接不能直接通过变量、函数来访问)。那么AIDL就是我们的中间者,比如说AIDL是英语,假设中国人和日本人都懂英语,那么两者之间就可以间接地沟通了。
下图是跨进程通信的基本架构:
Android系统会单独地分配一块内存,这块内存专门用于进程间的通信的。一旦我们的远程进程(服务)启动以后,就会在这块内存注册一个IBinder的引用。但是这个引用跟两个进程没有程序上的关系,不能直接把对象扔进来,他只保存了服务的包名、类名、这个服务有哪些变量等等。IBinder的引用的出现也就代表着客户端可以与该服务进行通信了。
进程间通信是类似于C/S架构的,一个AIDL的接口包括Stub以及Proxy,分别叫做存根,代理。Stub主要跟服务端交互,Proxy主要跟客户端交互。进程间通信最基本的概念就是数据的读写,客户端向IBinder中写数据,Stub从IBinder读数据。IBinder就相当于即时通信中的中间服务器。
###自动生成的接口类分析
package com.nan.testbinder;
public interface IAidlInterface extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.nan.testbinder.IAidlInterface {
//包名
private static final java.lang.String DESCRIPTOR = "com.nan.testbinder.IAidlInterface";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.nan.testbinder.IAidlInterface))) {
return ((com.nan.testbinder.IAidlInterface) iin);
}
return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);
}
@Override
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_pay: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.pay(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.nan.testbinder.IAidlInterface {
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 java.lang.String pay(int pwd) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(pwd);
mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_pay = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String pay(int pwd) throws android.os.RemoteException;
}
复制代码
下面开始分析,如下图所示,这是Android Studio给出的整个类的结构图,这个接口有两个内部类Stub和Proxy。其中Stub是将来要从IBinder读数据的,Proxy将要从IBinder写数据的。
其中DESCRIPTOR是本类的包名。因为要保证两边能够通信,需要确保两边要知道对方的类名。 private static final java.lang.String DESCRIPTOR = "com.nan.testbinder.IAidlInterface";
下面是Stub的构造函数,里面调用了父类的attachInterface函数:
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
复制代码
这里把this(IAidlInterface AIDL的引用,也就是自己)以及DESCRIPTOR描述绑定到Binder里面, 如果是同一个进程之间的通信的话,比如说Activity与同一个进程的Service通信,那么就会直接利用本地的接口引用。
当我们的远程服务启动的时候,就会注册一个IBinder引用,一旦Service绑定成功以后就会回传IBinder引用。但是拿到IBinder并不能马上通信,实际上最终还要拿到AIDL实现类的对象,这样才能通信。也就是说,拿到IBinder并且根据描述DESCRIPTOR来产生我们需要的AIDL的实现类。
例如上述栗子中的代码:
//通过Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类
mRemoteInterface = IAidlInterface.Stub.asInterface(service);
复制代码
下面我们看asInterface的源码,刚刚已经解释过了,如果是同一个进程之间的通信的话,那么就直接使用本地的AIDL实现类引用,因此下面的代码是先通过IBinder的queryLocalInterface方法去找本地的引用。
public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//先通过IBinder的queryLocalInterface方法去找本地的引用
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.nan.testbinder.IAidlInterface))) {
return ((com.nan.testbinder.IAidlInterface) iin);
}
return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);
}
复制代码
由于IBinder只是一个接口,那么如果要看queryLocalInterface的实现的话,就需要去看Binder的源码:
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
复制代码
这段代码很明确了,就是如果Stub构造的时候保存的DESCRIPTOR与我们需要的descriptor是一致的话,说明是同一个进程的,那就直接返回本地的AIDL实现类(mOwner)。
如果本地没有,那么就是不同进程的,那么这时候就需要通过IBinder引用去初始化我们的AIDL对象:
return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);
复制代码
下面就需要去看Proxy的构造函数:
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
复制代码
再来看一下Proxy的类,它并没有继承Binder,而是直接实现了AIDL的接口:
private static class Proxy implements com.nan.testbinder.IAidlInterface
复制代码
也就是说,Proxy构造的时候,就是通过IBinder引用转换为AIDL的接口的实现类的过程。
下面继续分析Stub的onTransact方法:
@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_pay: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.pay(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
复制代码
Stub相当于服务端,以后IBinder要向Stub进行写数据。通信的时候会回调onTransact方法。
进程间通信无非就是“函数的间接调用”,下面这是我在AIDL里面定义的pay方法,如果客户端的pay方法被调用,那么远程的相应的方法也会被调用。
整个过程是这样的,先是客户端通过Proxy向IBinder写数据,Parcel与序列化有关。
@Override
public java.lang.String pay(int pwd) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
//把描述和数据写到一个Parcel对象,描述用于控制将来数据发送到哪个对象。
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(pwd);
//写数据,但是不知道是哪一个函数,只知道是第几个函数,先去调用IBinder的transact
//然后IBinder去连接远程Stub对象,最后回调远程Stub的onTransact方法
mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);
//读取是否有异常
_reply.readException();
//读取结果(返回值),同步读取的
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
复制代码
下面我们看Binder中transact方法的实现
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
复制代码
池的概念,先进先出的队列的方法:
public static Parcel obtain() {
final Parcel[] pool = sOwnedPool;
synchronized (pool) {
Parcel p;
for (int i=0; i<POOL_SIZE; i++) {
p = pool[i];
if (p != null) {
pool[i] = null;
if (DEBUG_RECYCLE) {
p.mStack = new RuntimeException();
}
return p;
}
}
}
return new Parcel(0);
}
复制代码
远程Stub的onTransact方法实现:
@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_pay: {
//把DESCRIPTOR传进来作为验证,如果与本地的描述一样的话,下面继续执行。
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
//回调自己的pay方法
java.lang.String _result = this.pay(_arg0);
//把结果返回IBinder,然后再回传给客户端
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
复制代码
###bindService的全过程源码分析
要看bindService的话,先要找到Context的实现类ContextImpl。
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();//与系统的安全有关,如果你从系统调用的话,就需要关注这个方法
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
复制代码
######Android Studio中可以通过Ctrl+H 打开类的继承关系图。
bindService调用了bindServiceCommon,核心代码:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
try {
service.prepareToLeaveProcess(this);
//核心代码,开始了进程间通信
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
复制代码
ActivityManagerNative继承了Binder,并且实现了IActivityManager接口,因此与进程通信有关。
public abstract class ActivityManagerNative extends Binder implements IActivityManager{
}
复制代码
对比
public static abstract class Stub extends android.os.Binder implements com.nan.testbinder.IAidlInterface{
}
复制代码
发现ActivityManagerNative就是一个Stub对象,仔细观察这个类就会发现下面的Proxy。与系统服务进行通信。
继续分析:
static public IActivityManager getDefault() {
return gDefault.get();
}
复制代码
拿到系统服务IBinder的引用,通过asInterface方法把IBinder引用转换为需要的IActivityManager接口(实质上是AIDL接口):
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
//通过
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
return am;
}
};
复制代码
所以说,下面这句代码实际上是通过进程间通信,向ServiceManager获取名字为"activity"的系统服务,并且通过asInterface方法把IBinder引用转换为需要的IActivityManager接口的引用,然后调用这个引用的bindService方法。
ActivityManagerNative.getDefault()//这就是一个ActivityManagerService(AMS)
.bindService();
复制代码
######系统服务,进程之间的通信
ServiceManager--管理所有系统服务。ServiceManager相当于总台,我们通过打电话(我们的进程与系统进程进行进程间通信)的方式,就可以拿到对应的服务的AIDL引用。
所有系统服务启动的时候都需要向ServiceManager注册自己的引用:就是把自己的IBinder引用给ServiceManager。在AIDL创建Stub的时候会通过调用父类Binder的构造函数,通过NDK的方式去注册。
而IActivityManager的实现类是ActivityManagerService(AMS),AMS是四大组件进行进程间通信的一个比较重要的类。(因为他实现类AIDL接口:ActivityManagerNative)
public final class ActivityManagerService extends ActivityManagerNative implements ... {
}
复制代码
而AMS里面bindService是这样实现的,注意:现在已经是在系统服务(AMS)的进程里面了。由系统进程继续后续操作:
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
synchronized(this) {
//最后是通过mServices(ActiveService)对象的bindServiceLocked,这里开始了进程间通信
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
复制代码
最后是通过mServices(ActiveServices)对象的bindServiceLocked,这里开始了进程间通信,这个方法比较长,只看核心的代码:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
//判断进程
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
//ActivityRecord用于记录Activity,然后是为了方便处理
ActivityRecord activity = null;
if (token != null) {
activity = ActivityRecord.isInStackLocked(token);
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
}
int clientLabel = 0;
PendingIntent clientIntent = null;
final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;
//判断是不是在本进程
if (isCallerSystem) {
service.setDefusable(true);
clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT);
if (clientIntent != null) {
clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
if (clientLabel != 0) {
service = service.cloneFilter();
}
}
}
//一些权限的检测
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"BIND_TREAT_LIKE_ACTIVITY");
}
//这个跟Service的生命周期有关
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
try {
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
//把我们的connection对象保存(注册)起来,服务绑定成功以后用于回调
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
if (s.app != null && b.intent.received) {
try {
//连接回调给MainActivity
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
}
//如果是第一次绑定的时候,就会调用这里
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
复制代码
然后我们看ActiveServices中的requestServiceBindingLocked的实现,先通过forceProcessStateUpTo去启动另外一个进程的ActivityThread的进程(即通过C++的方式反射调用了ActivityThread的main方法,并且启动了消息循环)。(先启动进程,然后启动进程里面的服务,没毛病!ApplicationThread的启动代表APP的启动,即Application的启动)
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
//启动ActivityThread
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//r是ServiceRecord对象,专门用来保存Service的记录,与ActivityRecord类似
//app是ServiceRecord的一个成员变量ProcessRecord,专门用来保存进程的记录
//thread是ProcessRecord的一个成员变量IApplicationThread,是整个Android组件启动的核心类
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
} catch (RemoteException e) {
}
}
return true;
}
复制代码
IApplicationThread的实现类ApplicationThread是整个Android组件启动的核心类,也是跟进程间通信有关的类,根据下面的类的关系分析:
public interface IApplicationThread extends IInterface {
}
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread {
}
private class ApplicationThread extends ApplicationThreadNative {
}
复制代码
最终发现IApplicationThread的实现类是ActivityThread的一个内部类:ApplicationThread!!!
因此调用ApplicationThread的bindService的时候就会启动另外一个ActivityThread,并且发送消息给系统Handler(H),启动Service:
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
//保存关于Service的一些参数
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
//发送消息给系统Handler,启动Service
sendMessage(H.BIND_SERVICE, s);
}
复制代码
系统Handler接受消息以后:
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
复制代码
handleBindService:
private void handleBindService(BindServiceData data) {
//mServices是在handleCreateService的时候通过反射创建的
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
//绑定一个Service,回调onBind方法
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
//然后又通过进程间通信,把这个服务的IBinder对象放到Binder驱动里面
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
复制代码
来到这里,就会回调ServiceConnection的onServiceConnected方法,拿到IBinder引用以后,就需要去创建用于通信的AIDL接口的引用。
class MyRemoteServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteInterface = IAidlInterface.Stub.asInterface(service);
if (mRemoteInterface != null) {
String result;
try {
result = mRemoteInterface.pay(123);
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//连接因为异常而终止才会调用
}
}
复制代码
首先去初始化Stub,在Stub构造的时候,并且把描述保存起来。
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
复制代码
我们bindService的时候,先会找到系统服务,由系统服务创建相应的进程和服务,然后回调的时候传回IBinder。 Service的创建是通过反射的方式的,当AIDL引用被创建的时候,首先会调用Stub的构造函数创建Stub,因为Stub继承了Binder,根据Java的语法,这时候先会调用Binder的构造init方法,注册IBinder引用到专门用于进程通信的内存里面:
public Binder() {
init();
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Binder> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
}
复制代码
其中这里的init方法是一个native方法:
private native final void init();
复制代码
在这个init方法里面就会进行IBinder的注册。
然后通过我们手动调用Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类:
//通过Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类
mRemoteInterface = IAidlInterface.Stub.asInterface(service);
复制代码
先在自己的进程找IBinder引用,如果有,就直接返回自身,没有的话,就创建代理Proxy:
public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//先通过IBinder的queryLocalInterface方法去找本地的引用
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.nan.testbinder.IAidlInterface))) {
return ((com.nan.testbinder.IAidlInterface) iin);
}
return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);
}
复制代码
我们在MainActivity拿到引用以后,就可以调用我们自己实现的pay方法进行进程间通信了。
###数据是怎么写倒IBinder里面的呢?
我们知道数据是通过Proxy写到IBinder里面的,例如我们刚刚看过的代码:
@Override
public java.lang.String pay(int pwd) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(pwd);
//把数据写到IBinder驱动里面
mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
复制代码
这是我们自定义AIDL类里面的自定义pay方法,这里我们深入分析mRemote.transact(...)这个方法。 首先从上面的分析知道,mRemote是在Proxy构造的时候传进来的(在不同进程里的时候)。 ######这里再强调一次,如果是同一个进程的话,Binder就是自身,因为Stub这个类本身就是继承了Binder。
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {
//...
return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);
}
复制代码
所以说我们要看transact的实现,实际上就要看他的实现类Binder内部类的BinderProxy的transact:
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
if (Binder.isTracingEnabled()) {
Binder.getTransactionTracker().addTrace();
}
return transactNative(code, data, reply, flags);
}
复制代码
里面调用了native方法transactNative,也就是说IBinder的底层驱动是通过C++来实现的,通过底层代码把数据写到IBinder驱动里面。
返回的时候通过Binder的onTransact函数,通过dump方法把数据拿回来:
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (code == INTERFACE_TRANSACTION) {
reply.writeString(getInterfaceDescriptor());
return true;
} else if (code == DUMP_TRANSACTION) {
ParcelFileDescriptor fd = data.readFileDescriptor();
String[] args = data.readStringArray();
if (fd != null) {
try {
//通过dump方法把数据拿回来
dump(fd.getFileDescriptor(), args);
} finally {
IoUtils.closeQuietly(fd);
}
}
// Write the StrictMode header.
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
return true;
} else if (code == SHELL_COMMAND_TRANSACTION) {
ParcelFileDescriptor in = data.readFileDescriptor();
ParcelFileDescriptor out = data.readFileDescriptor();
ParcelFileDescriptor err = data.readFileDescriptor();
String[] args = data.readStringArray();
ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
try {
if (out != null) {
shellCommand(in != null ? in.getFileDescriptor() : null,
out.getFileDescriptor(),
err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
args, resultReceiver);
}
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(err);
// Write the StrictMode header.
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
}
return true;
}
return false;
}
复制代码
###IBinder引用什么时候放到共享内存时候?
AIDL中Stub构造的时候,就会调用父类Binder的构造,调用NDK的init方法,进行注册。
###源码分析相关
源码分析的两种方法:架构上面分析(类的关系)、流程上面的分析
源码分析的时候需要不断去找接口的实现类 源码分析的推荐学习顺序: Binder、Handler消息机制、VIew、事件分发、系统服务(ServiceManager代表着系统服务、AMS代表着应用程序启动流程)、四大组件的架构 、WindowManager、学习系统应用源码(Launcher等)
如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:
我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)。