一、AIDL使用及理解
介绍参考官方文档:https://developer.android.com/develop/background-work/services/aidl?hl=zh-cn
1.1、aidl文件的产物
1.1.1 aidl文件
interface IDownloadIpc {//开始下载DownloadResponse start(in DownloadInfoParcel downloadInfo);//暂停下载DownloadResponse pause(in DownloadInfoParcel downloadInfo);//取消下载DownloadResponse cancel(in DownloadInfoParcel downloadInfo);//获取下载信息, DownloadInfo可以转换成ResourceDtoList<DownloadInfoParcel> getDownLoadInfo();//注册下载监听回调void registerDownloadCallback(IDownloadIpcCallback callback);//反注册下载监听回调void unregisterDownloadCallback(IDownloadIpcCallback callback);//中心cta是否通过boolean isCtaPass();
}
1.1.2 aidl文件编译后后文件
分为三部分
Default实现
Stub实现
接口定义
1.2、线程及时序问题
1.2.1 client与server的一次连接中,任务是顺序执行的
/*** binder_proc_transaction() - sends a transaction to a process and wakes it up* @t: transaction to send* @proc: process to send the transaction to* @thread: thread in @proc to send the transaction to (may be NULL)*/
static bool binder_proc_transaction(struct binder_transaction *t,struct binder_proc *proc,struct binder_thread *thread)
{//找到Server端的对应Binder服务在Binder驱动中对应的对象binder_nodestruct binder_node *node = t->buffer->target_node;//判断这次Binder调用是不是onewaybool oneway = !!(t->flags & TF_ONE_WAY);//初始化为false,用于标记当前Server端的对应Binder服务是否正在执行oneway的方法bool pending_async = false;binder_node_lock(node);//oneway == trueif (oneway) {if (node->has_async_transaction) {//发现对应Binder服务正在执行oneway的方法,设置pending_async为truepending_async = true;} else {//发现对应Binder服务没有执行oneway的方法,设置has_async_transaction为1node->has_async_transaction = 1;}}binder_inner_proc_lock(proc);//oneway的调用thread为空,第1次oneway调用,pending_async为falseif (!thread && !pending_async)thread = binder_select_thread_ilocked(proc);if (thread) {binder_enqueue_thread_work_ilocked(thread, &t->work);} else if (!pending_async) {binder_enqueue_work_ilocked(&t->work, &proc->todo);} else {//这次Binder work放到Binder Node的async_todo队列中,不会立刻执行binder_enqueue_work_ilocked(&t->work, &node->async_todo);}if (!pending_async)//需要唤醒thread执行工作队列中的Binder workbinder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);binder_inner_proc_unlock(proc);binder_node_unlock(node);return true;
}
可以看到这里有两把锁:binder_inner_proc_lock和binder_node_lock,对于一次连接,服务端都有唯一的binder_node,由于binder_node_lock的存在,所以通信是顺序执行的。
1.2.2 Binder线程池
参考:进程的Binder线程池工作过程
默认地,每个进程的binder线程池的线程个数上限为15。
Binder设计架构中,只有第一个Binder主线程(也就是Binder_1线程)是由应用程序主动创建,Binder线程池的普通线程都是由Binder驱动根据IPC通信需求创建
1.3、Binder通信的最大容量限制
参考:一次Binder通信最大可以传输多大的数据?
一次Binder通信最大可以传输是1MB-8KB(PS:8k是两个pagesize,一个pagesize是申请物理内存的最小单元)
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)//这里的限制是1MB-4KB*2
ProcessState::ProcessState(const char *driver)
{if (mDriverFD >= 0) {// mmap the binder, providing a chunk of virtual address space to receive transactions.// 调用mmap接口向Binder驱动中申请内核空间的内存mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);if (mVMStart == MAP_FAILED) {// *sigh*ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());close(mDriverFD);mDriverFD = -1;mDriverName.clear();}}
}
1.4、oneway 以及in、out、inout参数的理解
参考: https://blog.csdn.net/anlian523/article/details/98476033
oneway: 该关键字修饰的方法在服务端是异步执行的,往往没有返回值
in:客户端传递给服务端的参数,服务端需要获取参数的具体内容
out:客户端不用将参数的具体内容传递给服务端,服务端需要返回具体内容,客户端收到该内容后填充到参数中。
inout:in和out的融合
二、binder通信过程
2.1、获取远程Binder
Server提供服务往往以Service的形式,在onBind是将提供的服务以Binder形式返回给Client端:
override fun onBind(intent: Intent?): IBinder {LogUtility.i(TAG, "onBind")return downloadBinder
}private val downloadBinder: Binder = object : IDownloadIpc.Stub() {override fun start(downloadInfo: DownloadInfoParcel?): DownloadResponse {val ctaPass = AppUtil.isCtaPass()LogUtility.w(TAG, "start ctaPass: $ctaPass, downloadInfo: $downloadInfo")if (!ctaPass) {return DownloadResponse(Constants.DOWNLOAD_FAILE_NO_CTA, "cta not pass")}(downloadProxy.getDownloadInfo(downloadInfo?.pkgName) as? LocalDownloadInfo)?.let {downloadProxy.download(it)}return DownloadResponse(0, "success")}//...
}
可以看到服务端返回的Binder对象实现了IDownloadIpc.Stub的接口,那Client是如何获取到Server的Binder的呢?
首先是Client发起绑定:
//ContextImpl.java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,String instanceName, Handler handler, Executor executor, UserHandle user) {。。。if (mPackageInfo != null) {if (executor != null) {sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);} else {sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);}}try {。。。int res = ActivityManager.getService().bindIsolatedService(mMainThread.getApplicationThread(), getActivityToken(), service,service.resolveTypeIfNeeded(getContentResolver()),sd, flags, instanceName, getOpPackageName(), user.getIdentifier());return res != 0;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}
}
sd包装了ServiceConnection 对象,用于服务绑定成功后的回调。ActivityManager.getService()获取到ActivityManagerService,是一次IPC调用。ActivityManagerService将绑定逻辑放在ActiveServices中处理:
//ActiveServices
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,String resolvedType, final IServiceConnection connection, int flags,String instanceName, String callingPackage, final int userId)throws TransactionTooLargeException {。。。if ((flags&Context.BIND_AUTO_CREATE) != 0) {s.lastActivity = SystemClock.uptimeMillis();needOomAdj = true;if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,permissionsReviewRequired, packageFrozen, true) != null) {mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);return 0;}}。。。if (s.app != null && b.intent.received) {// Service is already running, so we can immediately// publish the connection.try {c.conn.connected(s.name, b.intent.binder, false);} catch (Exception e) {Slog.w(TAG, "Failure sending service " + s.shortInstanceName+ " to connection " + c.conn.asBinder()+ " (in " + c.binding.client.processName + ")", e);}// If this is the first app connected back to this binding,// and the service had previously asked to be told when// rebound, then do so.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);}}return 1;
}
//ActiveServices
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,boolean enqueueOomAdj)throws TransactionTooLargeException {。。。if (!isolated) {app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid+ " app=" + app);if (app != null) {final IApplicationThread thread = app.getThread();final int pid = app.getPid();final UidRecord uidRecord = app.getUidRecord();if (thread != null) {try {app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,mAm.mProcessStats);realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,enqueueOomAdj);return null;} }}} 。。。return null;
}
在bringUpServiceLocked中调用realStartServiceLocked创建Service,创建成功后Service会回调onCreate()。创建完Service后,会调用requestServiceBindingLocked()方法绑定已经创建的服务,并回调ServiceConnection的onServiceConnected(name: ComponentName?, service: IBinder?)方法,将binder回传给Client。
//ActiveServices
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",OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);r.app.getThread().scheduleBindService(r, i.intent.getIntent(), rebind,r.app.mState.getReportedProcState());if (!rebind) {i.requested = true;}i.hasBound = true;i.doRebind = false;}}return true;
}
r.app.getThread()返回IApplicationThread类型对象,IApplicationThread是AIDL生产的对象,因此这里也是IPC通信,最终调用到ApplicationThread的scheduleBindService()方法,最终调用handleBindService()方法:
//ActivityThread.java
public final class ActivityThread extends ClientTransactionHandlerimplements ActivityThreadInternal {private class ApplicationThread extends IApplicationThread.Stub {public final void scheduleBindService(IBinder token, Intent intent,boolean rebind, int processState) {updateProcessState(processState, false);BindServiceData s = new BindServiceData();s.token = token;s.intent = intent;s.rebind = rebind;sendMessage(H.BIND_SERVICE, s);
}}private void handleBindService(BindServiceData data) {CreateServiceData createData = mServicesData.get(data.token);Service s = mServices.get(data.token);if (s != null) {try {data.intent.setExtrasClassLoader(s.getClassLoader());data.intent.prepareToEnterProcess(isProtectedComponent(createData.info),s.getAttributionSource());try {if (!data.rebind) {IBinder binder = s.onBind(data.intent);ActivityManager.getService().publishService(data.token, data.intent, binder);} else {s.onRebind(data.intent);ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);}} } }
}
}
通过data.rebind判断是否是重新绑定,不是重新绑定则调用Service的onBind()方法,是重新绑定则调用Service的bind()方法。这点通过onBind()方法并获取一个Binder对象,并通过publishService()方法将该binder回调返回给客户端:
//ActivityManagerService
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {final long origId = Binder.clearCallingIdentity();try {if (r != null) {Intent.FilterComparison filter= new Intent.FilterComparison(intent);IntentBindRecord b = r.bindings.get(filter);if (b != null && !b.received) {b.binder = service;b.requested = true;b.received = true;ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();for (int conni = connections.size() - 1; conni >= 0; conni--) {ArrayList<ConnectionRecord> clist = connections.valueAt(conni);for (int i=0; i<clist.size(); i++) {ConnectionRecord c = clist.get(i);c.conn.connected(r.name, service, false);}}}}serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false);}} finally {Binder.restoreCallingIdentity(origId);}
}
2.2、客户端调用服务端
参考:https://cloud.tencent.com/developer/article/2360820
绑定成后onServiceConnected()方法会回调
//CenterDownloadConnectionManager
private val con: ServiceConnection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {downloadService = IDownloadIpc.Stub.asInterface(service)}
service是远程服务端的Binder代理对象,实际是一个BinderProxy对象。
//IDownloadIpc
public static com.nearme.gamespace.bridge.download.IDownloadIpc asInterface(android.os.IBinder obj)
{if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.nearme.gamespace.bridge.download.IDownloadIpc))) {return ((com.nearme.gamespace.bridge.download.IDownloadIpc)iin);}return new com.nearme.gamespace.bridge.download.IDownloadIpc.Stub.Proxy(obj);
}
BinderProxy#queryLocalInterface()方法返回为null,因此会返回一个Proxy对象。
//IDownloadIpc
private static class Proxy implements com.nearme.gamespace.bridge.download.IDownloadIpc
{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 com.nearme.gamespace.bridge.download.DownloadResponse start(com.nearme.gamespace.bridge.download.DownloadInfoParcel downloadInfo) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();com.nearme.gamespace.bridge.download.DownloadResponse _result;try {_data.writeInterfaceToken(DESCRIPTOR);if ((downloadInfo!=null)) {_data.writeInt(1);downloadInfo.writeToParcel(_data, 0);}else {_data.writeInt(0);}boolean _status = mRemote.transact(Stub.TRANSACTION_start, _data, _reply, 0);if (!_status && getDefaultImpl() != null) {return getDefaultImpl().start(downloadInfo);}_reply.readException();if ((0!=_reply.readInt())) {_result = com.nearme.gamespace.bridge.download.DownloadResponse.CREATOR.createFromParcel(_reply);}else {_result = null;}}finally {_reply.recycle();_data.recycle();}return _result;}
这里的mRemote是一个BinderProxy对象,其transact()方法会通过JNI调用到Binder驱动层,然后调用的Server端的DownloadIpcService,调用Binder的transact()方法:
//Binder
public final boolean transact(int code, @NonNull Parcel data, @Nullable 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;
}
Stud继承了Binder并重写了onTransact()方法:
public static abstract class Stub extends android.os.Binder implements com.nearme.gamespace.bridge.download.IDownloadIpc
{private static final java.lang.String DESCRIPTOR = "com.nearme.gamespace.bridge.download.IDownloadIpc";@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{java.lang.String descriptor = DESCRIPTOR;switch (code){case TRANSACTION_start:{data.enforceInterface(descriptor);com.nearme.gamespace.bridge.download.DownloadInfoParcel _arg0;if ((0!=data.readInt())) {_arg0 = com.nearme.gamespace.bridge.download.DownloadInfoParcel.CREATOR.createFromParcel(data);}else {_arg0 = null;}com.nearme.gamespace.bridge.download.DownloadResponse _result = this.start(_arg0);reply.writeNoException();if ((_result!=null)) {reply.writeInt(1);_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}return true;}}