一、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可以转换成ResourceDto
List<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_node
struct binder_node *node = t->buffer->target_node;
//判断这次Binder调用是不是oneway
bool oneway = !!(t->flags & TF_ONE_WAY);
//初始化为false,用于标记当前Server端的对应Binder服务是否正在执行oneway的方法
bool pending_async = false;
binder_node_lock(node);
//oneway == true
if (oneway) {
if (node->has_async_transaction) {
//发现对应Binder服务正在执行oneway的方法,设置pending_async为true
pending_async = true;
} else {
//发现对应Binder服务没有执行oneway的方法,设置has_async_transaction为1
node->has_async_transaction = 1;
}
}
binder_inner_proc_lock(proc);
//oneway的调用thread为空,第1次oneway调用,pending_async为false
if (!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 work
binder_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 ClientTransactionHandler
implements 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;
}
}