AIDL使用及原理介绍

一、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;
      }
      
}

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值