• android10Binder(六)java世界的binder:App进程间Binder通信


    java世界的binder:App进程间Binder通信

    一、一个实例:development/samples/ApiDemos

    不会用aidl的先去学会怎么使用aidl再来读这篇文章。

    aidl使用之官方指导文档:Android Interface Definition Language (AIDL)

    网上不错的例子:Android AIDL使用详解

    不过我们今天不打算用自己写的app,而是用aosp里的demo:ApiDemos,考虑是这个例子是官方提供的,经典全面,且一直没怎么变动,上次提交是在Date: Thu May 5 18:00:07 2016......

    1.1 通信两端的关键代码之Client端

    客户端要发起通信关键两步,

    1、通过bindService方法发起绑定;

    2、实现回调方法。ServiceConnection接口的onServiceConnected和onServiceDisconnected。

    先看下客户端代码位置。是一个Activity里。

    development/samples/ApiDemos/AndroidManifest.xml

     619         <activity android:name=".app.RemoteService$Binding"
     620                 android:label="@string/activity_remote_service_binding">
     621             <intent-filter>
     622                 <action android:name="android.intent.action.MAIN" />
     623                 <category android:name="android.intent.category.SAMPLE_CODE" />
     624             </intent-filter>
     625         </activity>
    

    development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java

    260     /**
    261      * Example of binding and unbinding to the remote service.
    262      * This demonstrates the implementation of a service which the client will
    263      * bind to, interacting with it through an aidl interface.</p>
    264      *.
    265      * <p>Note that this is implemented as an inner class only keep the sample
    266      * all together; typically this code would appear in some separate class.
    267      */
    268  // BEGIN_INCLUDE(calling_a_service)
    269     public static class Binding extends Activity {
    273         ISecondary mSecondaryService = null;
    

    注释第一段说明了这个叫Binding的Activity是用来作为客户端。第二段解释,这个Activity之所以放在内部类里,是为了演示方便。一般的跨进程调用是在不同apk里,例如微信暴露给你个aidl接口,例如你们公司开发了一堆apk,需要做沟通。

    看下两步重点的代码的第一步,1、通过bindService方法发起绑定

    development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java

    269     public static class Binding extends Activity {
    365         private OnClickListener mBindListener = new OnClickListener() {
    366             public void onClick(View v) {
    367                 // Establish a couple connections with the service, binding
    368                 // by interface names.  This allows other applications to be
    369                 // installed that replace the remote service by implementing
    370                 // the same interface.
    371                 Intent intent = new Intent(Binding.this, RemoteService.class);
    372                 intent.setAction(IRemoteService.class.getName());
    373                 bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    374                 intent.setAction(ISecondary.class.getName());
    375                 bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE);
    376                 mIsBound = true;
    377                 mCallbackText.setText("Binding.");
    378             }
    379         };
    

    372、373行的绑定我们不管,我们这次跟的是ISecondary这个aidl。因为他简单。

    371行第一个参数是我们Activity自己,然后374行传入目标的className,指定要找某个远程组件。

    375行发起绑定。第二个参数是一个实现ServiceConnection接口的匿名内部类,下面贴。参数三是一个flag,BIND_AUTO_CREATE标志着,服务进程不在时要把他拉起来,就是新建进程。

    下面是ServiceConnection接口的实现。

    development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java

    269     public static class Binding extends Activity {
    347         /**
    348          * Class for interacting with the secondary interface of the service.
    349          */
    350         private ServiceConnection mSecondaryConnection = new ServiceConnection() {
    351             public void onServiceConnected(ComponentName className,
    352                     IBinder service) {
    353                 // Connecting to a secondary interface is the same as any
    354                 // other interface.
    355                 mSecondaryService = ISecondary.Stub.asInterface(service);
    356                 mKillButton.setEnabled(true);
    357             }
    358
    359             public void onServiceDisconnected(ComponentName className) {
    360                 mSecondaryService = null;
    361                 mKillButton.setEnabled(false);
    362             }
    363         };
    

    ServiceConnection接口就俩回调方法,都给他实现了。

    第一个方法351行的onServiceConnected。传进来的参数看不懂不要紧,我们后面会走流程分析到。355行ISecondary.Stub.asInterface是不是眼前一亮。又是熟悉的套路,返回给我们一个Ixxx.Stub.Proxy对象。这个对象保存了355行的入参service,也就是一个BinderProxy对象,其transact方法能穿越jni使用native的IPCThreadState同binder驱动对话,talkWithdriver。

    当然入参service是BinderProxy对象这个事情我们现在还是不知道的,等回调发生,我们就明白IBinder service是BinderProxy还是Binder对象了。(IBinder是个接口,要么实现为Binder代表server,要么实现为BinderProxy代表client)。

    第二个方法onServiceDisconnected是断开连接的回调,可以在这里处理一些事情。

    另外聪明如你肯定也关注到了mKillButton这个东东,可以猜测我们客户端是要杀掉谁。要杀掉的是服务端的进程,按钮代码如下。

    development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java

    269     public static class Binding extends Activity {
    285         protected void onCreate(Bundle savedInstanceState) {
    296             mKillButton.setOnClickListener(mKillListener);
    300             mCallbackText.setText("Not attached.");
    301         }
    //---------------------------------------------------------------------------
    405         private OnClickListener mKillListener = new OnClickListener() {
    406             public void onClick(View v) {
    410                 if (mSecondaryService != null) {
    411                     try {
    412                         int pid = mSecondaryService.getPid();
    421                         Process.killProcess(pid);
    422                         mCallbackText.setText("Killed service process.");
    423                     } catch (RemoteException ex) {
    430                     }
    431                 }
    432             }
    

    412行是binder调用,跨进程调用服务端的getPid()方法,然后服务端再次跨进程返回给我们数据。

    421行在客户端进程里杀掉服务端,由于我们的client和server都在一个app里uid一样所以是可以做到的,此处只是为了演示。一般没有这么无聊跨进程拿到pid再杀了谁,直接给他发消息,让他自己exit更方便。。。

    客户端的代码就罗列到这里,下面看看服务端的关键代码。

    1.2 通信两端的关键代码之Server端

    上面我们提到,为了演示方便,没有新建app写服务端,但是我们可以改组件的进程名在AndroidManifest.xml中。这个大家应该都懂。

    development/samples/ApiDemos/AndroidManifest.xml

     608         <service android:name=".app.RemoteService" android:process=":remote" />
    

    上面的activity是这个service的内部类。但是不影响,因为我们指定了另外的进程android:process。反直觉的就是同一个java文件里的东西竟然不在同一进程O(∩_∩)O哈哈~,这又要从Activity、Service组件的启动流程说起了。可以参考:

    startActivity启动过程startServie启动过程

    简单的说就是字面意思,指定了就新建进程,即走的冷启动流程。组件的这个process属性系统如何拿到的呢?

    是在安装app时,PMS扫描AndroidManifest.xml的Activity配置,保存了process名称

    frameworks/base/core/java/android/content/pm/PackageParser.java

    7361         public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
    7362             this(args, (PackageItemInfo)outInfo);
    7367             if (args.processRes != 0) {
    7368                 CharSequence pname;
    7369                 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
    7370                     pname = args.sa.getNonConfigurationString(args.processRes,
    7371                             Configuration.NATIVE_CONFIG_VERSION);
    7372                 }
    7378                 outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
    7379                         owner.applicationInfo.processName, pname,
    7380                         args.flags, args.sepProcesses, args.outError);
    7381             }
    

    这个方法是parseActivity$Component类的构造函数,在PackageParser.java的parseActivity方法里会new一个parseActivity$Activity实例,这个Activity是parseActivity$Component类的子类。所以在这个父类的构造函数里就把android::process属性拿到了,放到ActivityInfo的processName里存储。当然这个Activity会放到packageInfo里,packageInfo又会放到package里层层存储。

    frameworks/base/core/res/res/values/attrs_manifest.xml

     470     <!-- Specify a specific process that the associated code is to run in.
     471          Use with the application tag (to supply a default process for all
     472          application components), or with the activity, receiver, service,
     473          or provider tag (to supply a specific icon for that component).
     474
     475          <p>Application components are normally run in a single process that
     476          is created for the entire application.  You can use this tag to modify
     477          where they run.  If the process name begins with a ':' character,
     478          a new process private to that application will be created when needed
     479          to run that component (allowing you to spread your application across
     480          multiple processes).  If the process name begins with a lower-case
     481          character, the component will be run in a global process of that name,
     482          provided that you have permission to do so, allowing multiple
     483          applications to share one process to reduce resource usage. -->
     484     <attr name="process" format="string" />
    

    这块代码是上面7370行的参数1,也就是这个东东R.styleable.AndroidManifestActivity_process,这你应该很熟悉,R类嘛

    跑题了,把android:process属性发散了一下。现在看server的服务端代码吧。

    development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java

     58 public class RemoteService extends Service {
    106     @Override
    107     public IBinder onBind(Intent intent) {
    114         if (ISecondary.class.getName().equals(intent.getAction())) {
    115             return mSecondaryBinder;
    116         }
    117         return null;
    118     }
    //---------------------------------------------------------------------
    135     private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
    136         public int getPid() {
    137             return Process.myPid();
    138         }
    142     };
    

    关键点1、实现onBind回调函数,当client调用bindService方法时,通过系统的中转,会回调到这里,我们作为服务端会把这个Stub实现类返回去。

    1.3 ISecondary的aidl代码

    最后别忘了我们一直在使用的接口ISecondary,是定义在aidl文件里的,编译时才会转换成java文件里的interface。

    由于我们的client和server都在同一个工程同一个包里,所以aidl只需要放一份就够了,也不用import。当然,将所有使用到的包和field显示地列在import里是非常好的编码习惯。

    development/samples/ApiDemos/src/com/example/android/apis/app/ISecondary.aidl

     17 package com.example.android.apis.app;
     18
     19 /**
     20  * Example of a secondary interface associated with a service.  (Note that
     21  * the interface itself doesn't impact, it is just a matter of how you
     22  * retrieve it from the service.)
     23  */
     24 interface ISecondary {
     25     /**
     26      * Request the PID of this service, to do evil things with it.
     27      */
     28     int getPid();
     36 }
    

    看26行注释,要做点邪恶的事情。这个aidl很简单,只有简单数据类型int的方法。

    我们的重点是关注流程,关注主干的流程,所以用简单的例子突出重点。

    二、大回调的细节:bindService-->onBind-->onServiceConnected

    关键代码贴完了,我们会自然的产生这样一个疑问:

    1、为什么Client端bindService就可以到达Server端onBind?

    2、然后又能回调到Client端的onServiceConnected方法呢?

    3、这一个来回都传递了什么数据?

    2.1 了解一下Context家族

    bindService是Context的方法,由于我们的Activity继承了Context所以能调用到ContextImpl里的bindService方法实现。

    Context家族应用了Decorator设计模式,详细的可以参考一下两篇文章:

    Android深入理解Context(一)Context关联类和Application Context创建过程

    Android深入理解Context(二)Activity和Service的Context创建过程

    问你个android八股题,APP里有多少个Context实现类?你可能都会抢答了:Activity 数量+ Service数量 + 1,1是application。

    但是很不幸,这是错的。。。

    如果你认真跟过context创建流程的话,你会得出另一个正确的答案,(Context数量+ Service数量 + 1) x 2。因为每个组件创建的时候都会new一个contextImpl。。。

    以Activity的创建为例

    frameworks/base/core/java/android/app/ActivityThread.java

    3159     private Activity performLaunchActivity(...) {
    3178         ContextImpl appContext = createBaseContextForActivity(r);
    3179         Activity activity = null;
    3182             activity = mInstrumentation.newActivity(
    3183                     cl, component.getClassName(), r.intent);
    //----------------------------------------------------------------------
    3347     private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    3355         ContextImpl appContext = ContextImpl.createActivityContext(
    3356                 this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
    

    frameworks/base/core/java/android/app/ContextImpl.java

    2467     static ContextImpl createActivityContext(...) {
    2488         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
    2489                 activityToken, null, 0, classLoader, null);
    

    可以看到3182行new了一个Activity实例,2488行new了一个ContextImpl实例,也就是俩。Application和Service的创建也是一样。

    题外话结束,我们了解了Context家族,现在走进bindService方法,开始client:bindService-->server:onBind旅程。

    2.2 bindService:发起者app进程-->ams

    从RemoteService.java方法的onClick里出发

    365         private OnClickListener mBindListener = new OnClickListener() {
    366             public void onClick(View v) {
    371                 Intent intent = new Intent(Binding.this, RemoteService.class);
    37374               intent.setAction(ISecondary.class.getName());
    375                 bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE);
    

    frameworks/base/core/java/android/content/ContextWrapper.java

     702     @Override
     703     public boolean bindService(Intent service, ServiceConnection conn,
     704             int flags) {
     705         return mBase.bindService(service, conn, flags);
     706     }
    

    705行mBase是ContextImpl实例,不知道为什么的说明没学习上一小节的context创建流程。

    frameworks/base/core/java/android/app/ContextImpl.java

    1647     @Override
    1648     public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    1649         warnIfCallingFromSystemProcess();
    1650         return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
    1651                 getUser());
    1652     }
    

    Calling a method in the system process without a qualified user这句log是不是老熟悉了,就是1649行方法打印的。

    frameworks/base/core/java/android/app/ContextImpl.java

    1707     private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
    1708             String instanceName, Handler handler, Executor executor, UserHandle user) {
    1709         // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
    1710         IServiceConnection sd;
    1717         if (mPackageInfo != null) {
    1718             if (executor != null) {
    1719                 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
    1720             } else {
    1721                 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    1722             }
    1727         try {
    1734             service.prepareToLeaveProcess(this);
    1735             int res = ActivityManager.getService().bindIsolatedService(
    1736                 mMainThread.getApplicationThread(), getActivityToken(), service,
    1737                 service.resolveTypeIfNeeded(getContentResolver()),
    1738                 sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
    1743             return res != 0;
    1744         } catch (RemoteException e) {}
    1747     }
    

    1735行的方法调用需重点关注这几个参数。

    2.2.1 bindIsolatedService的参数

    参数1,mMainThread.getApplicationThread()

    获取APP进程的binder服务端Stub实例,这个服务端之后用来接收ams的binder调用。我们简单看下这个服务端的样貌。

    frameworks/base/core/java/android/app/ActivityThread.java

     219 public final class ActivityThread extends ClientTransactionHandler {
     293     final ApplicationThread mAppThread = new ApplicationThread();
     904     private class ApplicationThread extends IApplicationThread.Stub {
     911         public final void scheduleReceiver(Intent intent, ActivityInfo info,
     943         public final void scheduleCreateService(IBinder token,
    //---------------------------------------------------------------------------
     954         public final void scheduleBindService(IBinder token, Intent intent,
     955                 boolean rebind, int processState) {
     956             updateProcessState(processState, false);
     957             BindServiceData s = new BindServiceData();
     958             s.token = token;
     959             s.intent = intent;
     960             s.rebind = rebind;
     965             sendMessage(H.BIND_SERVICE, s);
     966         }
    //---------------------------------------------------------------------------
     968         public final void scheduleUnbindService(IBinder token, Intent intent) {
     969             BindServiceData s = new BindServiceData();
     970             s.token = token;
     971             s.intent = intent;
     973             sendMessage(H.UNBIND_SERVICE, s);
     974         }
    //---------------------------------------------------------------------------
     1665         public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    

    219行和904行可以看出,ApplicationThread是ActivityThread的内部类,是一个binder服务端,提供的服务是什么呢?

    是一些操作app进程的方法,例如1665行转换activity的生命周期,854行、968行的绑定解绑Service,也就是我们本文关注的内容,911行的分发广播等等。

    这些方法的实现也都是类似的,有套路的。像我们看到的654行scheduleBindService,968行scheduleUnbindService一样,先拿到system_server进程发过来的数据,然后解析,然后sendMessage给主线程的handler大H类。这个类你当然也知道,上面有讲过。

    需要注意这里的sendMessage是自封装的,里面的实现仍然是mH.sendMessage,不要被迷惑。

    frameworks/base/core/java/android/app/ActivityThread.java

    3118     private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
    3123         Message msg = Message.obtain();
    3124         msg.what = what;
    3125         msg.obj = obj;
    3126         msg.arg1 = arg1;
    3127         msg.arg2 = arg2;
    3131         mH.sendMessage(msg);
    3132     }
    
    参数2,getActivityToken()

    这个参数简单说下吧,其实是比较复杂的。他沟通了AMS和WMS还有app进程,是一个activity的唯一标志。代表唯一window的windowToke是基于activityToke产生的。

    本文我们不关注这个。

    参数5,sd

    这个很重要,和我们的bindService流程有莫大的关系。bind成功后ams会跨进程回调mSecondaryConnection对象的回调函数OnServiceConnected。

    需要注意区分我们APP里new的ServiceConnection接口,和此处的IServiceConnection接口。一个是普通的回调接口,另一个是binder的interface

    //frameworks/base/core/java/android/content/ServiceConnection.java
     28 public interface ServiceConnection {
    //-------------------------------------------------------------------------------
    //out/soong/.intermediates/frameworks/base/framework/android_common/gen/aidl/frameworks/base/core/java/android/app/IServiceConnection.java
    6 public interface IServiceConnection extends android.os.IInterface
     20   public static abstract class Stub extends android.os.Binder implements android.app.IServiceConnection
     100     private static class Proxy implements android.app.IServiceConnection
    

    我们深入分析下这个binder接口。从这里开始

    frameworks/base/core/java/android/app/ContextImpl.java

    1719                 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
    

    frameworks/base/core/java/android/app/LoadedApk.java

    1654     public final IServiceConnection getServiceDispatcher(ServiceConnection c,
    1655             Context context, Handler handler, int flags) {
    1656         return getServiceDispatcherCommon(c, context, handler, null, flags);
    1657     }
    //----------------------------------------------------------------------------------
    1659     public final IServiceConnection getServiceDispatcher(ServiceConnection c,
    1660             Context context, Executor executor, int flags) {
    1661         return getServiceDispatcherCommon(c, context, null, executor, flags);
    1662     }
    //----------------------------------------------------------------------------------
    1664     private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
    1665             Context context, Handler handler, Executor executor, int flags) {
    1666         synchronized (mServices) {
    1667             LoadedApk.ServiceDispatcher sd = null;
    1668             ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
    1669             if (map != null) {
    1671                 sd = map.get(c);
    1672             }
    1673             if (sd == null) {
    1674                 if (executor != null) {
    1675                     sd = new ServiceDispatcher(c, context, executor, flags);
    1676                 } else {
    1677                     sd = new ServiceDispatcher(c, context, handler, flags);
    1678                 }
    1680                 if (map == null) {
    1681                     map = new ArrayMap<>();
    1682                     mServices.put(context, map);
    1683                 }
    1684                 map.put(c, sd);
    1685             } else {
    1686                 sd.validate(context, handler, executor);
    1687             }
    1688             return sd.getIServiceConnection();
    1689         }
    1690     }
    

    走到1664行的getServiceDispatcherCommon方法。我们只看初始化的流程,也就是map未做缓存。

    1675行new一个ServiceDispatcher实例,将ServiceConnection实例也就是app里那个回调放进来。

    frameworks/base/core/java/android/app/LoadedApk.java

    1756     static final class ServiceDispatcher {
    1757         private final ServiceDispatcher.InnerConnection mIServiceConnection;
    //------------------------------------------------------------------------------------
    1776         private static class InnerConnection extends IServiceConnection.Stub {
    1778             final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
    1780             InnerConnection(LoadedApk.ServiceDispatcher sd) {
    1781                 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
    1782             }
    1783
    1784             public void connected(ComponentName name, IBinder service, boolean dead)
    1785                     throws RemoteException {
    1786                 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    1787                 if (sd != null) {
    1788                     sd.connected(name, service, dead);
    1789                 }
    1790             }
    1791         }
    //------------------------------------------------------------------------------------
    1797         ServiceDispatcher(ServiceConnection conn,
    1798                 Context context, Handler activityThread, int flags) {
    1799             mIServiceConnection = new InnerConnection(this);
    1800             mConnection = conn;
    1801             mContext = context;
    1802             mActivityThread = activityThread;
    1803             mActivityExecutor = null;
    1804             mLocation = new ServiceConnectionLeaked(null);
    1805             mLocation.fillInStackTrace();
    1806             mFlags = flags;
    1807         }
    //------------------------------------------------------------------------------------
    1862         IServiceConnection getIServiceConnection() {
    1863             return mIServiceConnection;
    1864         }
    

    InnerConnection类是真正的binder的服务实现,继承了IServiceConnection.Stub。现在我们可以回答本小节的题目,参数5sd是什么。

    sd = new ServiceDispatcher(c, context, executor, flags)-->getServiceDispatcherCommon()-->sd = new ServiceDispatcher.getIServiceConnection()-->mIServiceConnection。

    即一个ServiceDispatcher.InnerConnection对象,这个对象可以实现跨进程回调。目前我们在发起者APP进程里,后续这个对象会跨进程传到ams保存。之后Service进程会onBind-->publishService再次回到ams,下一步就会跨进程回调回来了。

    2.2.2 bindIsolatedService

    上面针对参数,尤其是针对IServiceConnection这个binder服务,这个跨进程的回调实现澄清了一下。

    frameworks/base/core/java/android/app/ContextImpl.java

    1707     private boolean bindServiceCommon(
    1735             int res = ActivityManager.getService().bindIsolatedService
    

    现在出发,发给AMS,让系统服务做处理。1735的ActivityManager.getService()调用就不细说了,在之前的java世界的binder里有分析,我们直接跳转到服务端实现代码。

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    14068     public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
    14069             String resolvedType, IServiceConnection connection, int flags, String instanceName,
    14070             String callingPackage, int userId) throws TransactionTooLargeException {
    14071         enforceNotIsolatedCaller("bindService");
    14094         synchronized(this) {
    14095             return mServices.bindServiceLocked(caller, token, service,
    14096                     resolvedType, connection, flags, instanceName, callingPackage, userId);
    14097         }
    14098     }
    

    14095行继续跳转。mServices是ActiveServices类实例。

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    mServices = hasHandlerThread ? new ActiveServices(this) : null;
    

    frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

    1557     int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
    1558             String resolvedType, final IServiceConnection connection, int flags,
    1559             String instanceName, String callingPackage, final int userId)
    1560             throws TransactionTooLargeException {
    
    bindServiceLocked的参数

    这些参数来自bindService发起的app进程,我们做下解析。

    • IApplicationThread caller

    是发起者app进程中的ApplicationThread 的BinderProxy代理对象

    • IBinder token

    是发起者app进程中那个getActivityToken拿到的mToken,目前在ams进程里就是Binder对象了。

    • Intent service

    虽然叫service但是是一个Intent对象,即我们发起bindeService时传的参

    • final IServiceConnection connection

    我们花了一个小节分析的ServiceDispatcher.InnerConnection对象,他是ServiceDispatcher的内部类。ServiceDispatcher实例持有这俩容易混淆的成员对象。

    1811             mIServiceConnection = new InnerConnection(this);
    1812             mConnection = conn;
    

    1811是binder的服务端实例,1812只是个普通的回调实例,我们在app代码里new ServiceConnection()创建出来的。

    现在是在ams进程里,所以是个代理对象BinderProxy。

    题外话:为什么Binder对象跨进程了就变成了BinderProxy对象了?

    这是binder驱动和用户空间共同作用的结果。从前文的surfaceflinger注册服务和bootanimation获取服务提炼一下。

    1、发起端进程在writeStrongBinder方法里将BBinder对象拍扁为flat_binder_obj结构体。

    2、在驱动的binder_transaction方法中,会translate服务端node成为一个ref,计算出handle给目的端进程持有。

    3、到了目的端进程用户空间,会使用对应于writeStrongBinder的readStrongBinder方法,unflat拿到handle创建一个BpBinder对象:BpBinder::create(handle)。

    我们从这个BBinder对象到BpBinder的转化流程可以了解到binder驱动与libbinder库的分工。

    binder驱动仅记录一个进程为node,根据BC和BR命名码对ioctl传下来的数据做操作,提供node和ref的互相转换、数据拷贝功能。

    我们的libbinder为了编码方便,用parcel、flat_binder_obj结构体封装数据。如果本次传输想传递BBinder对象,那么程序员就需要在发起端调用writeStrongBinder方法,就需要在接收端调用readStrongBinder根据驱动传回的ref,handle转化为一个BpBinder::create(handle)对象。反映到java层就是Binder对象到BinderProxy对象的转换。

    驱动解决了基础的机制问题,而用户空间的代码libbinder,更多是关注业务,即更方便的让使用者编码。

    这里有篇文章很不错,扩展地讲了这个问题:Android Binder框架实现之Parcel详解之read/writeStrongBinder实现

    bindServiceLocked

    参数的部分解析完毕,下面走入bindServiceLocked方法。

    frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

    1557     int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
    1558             String resolvedType, final IServiceConnection connection, int flags,
    1559             String instanceName, String callingPackage, final int userId)
    1560             throws TransactionTooLargeException {
    1634         ServiceLookupResult res =
    1635             retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
    1636                     Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
    1637                     callerFg, isBindExternal, allowInstant);
    1644         ServiceRecord s = res.record;
    1724         try {
    1754             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
    1755             ConnectionRecord c = new ConnectionRecord(b, activity,
    1756                     connection, flags, clientLabel, clientIntent,
    1757                     callerApp.uid, callerApp.processName, callingPackage);
    1758
    1759             IBinder binder = connection.asBinder();
    1760             s.addConnection(binder, c);
    1761             b.connections.add(c);
    1765             b.client.connections.add(c);
    1766             c.startAssociationIfNeeded();
    1785
    1786             if ((flags&Context.BIND_AUTO_CREATE) != 0) {
    1787                 s.lastActivity = SystemClock.uptimeMillis();
    1788                 if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
    1789                         permissionsReviewRequired) != null) {}
    1792             }
    1815             if (s.app != null && b.intent.received) {
    1816                 // Service is already running, so we can immediately
    1817                 // publish the connection.
    1818                 try {
    1819                     c.conn.connected(s.name, b.intent.binder, false);
    1820                 } catch (Exception e) {}
    1832             }else if (!b.intent.requested) {
    1833                 requestServiceBindingLocked(s, b.intent, callerFg, false);
    1834             }
    1838         } finally {}
    1842         return 1;
    

    这个方法里有两处重点。1788行将对端的Service拉起来,如果他的进程不存在的话,这是Service启动流程,可以看这篇文章:startServie启动过程

    由于我们的service进程新启动的,所以不会走入1815行分支,而是走到1833行的Service的onBind流程,明显,这又是一次binder跨进程通信。ams-->Service进程。

    2.3 requestServiceBindingLocked:ams-->服务提供者app进程

    frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

    2294     private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
    2295             boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    2302         if ((!i.requested || rebind) && i.apps.size() > 0) {
    2303             try {
    2306                 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
    2307                         r.app.getReportedProcState());
    

    2306行,r.app.thread是指向服务提供者app进程的IApplicationThread的Stub.Proxy对象,ams通过这个对象与服务提供者app进程通信。

    所以scheduleBindService方法就调用我们直接走到服务提供者app进程进程里。

    out/soong/.intermediates/frameworks/base/framework/android_common/gen/aidl/frameworks/base/core/java/androi
    d/app/

     182   public static abstract class Stub extends android.os.Binder implements android.app.IApplicationThread{
    437     @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{
     658         case TRANSACTION_scheduleBindService:
     659         {
     660           data.enforceInterface(descriptor);
     661           android.os.IBinder _arg0;
     662           _arg0 = data.readStrongBinder();
     663           android.content.Intent _arg1;
     664           if ((0!=data.readInt())) {
     665             _arg1 = android.content.Intent.CREATOR.createFromParcel(data);
     666           }
     667           else {
     668             _arg1 = null;
     669           }
     670           boolean _arg2;
     671           _arg2 = (0!=data.readInt());
     672           int _arg3;
     673           _arg3 = data.readInt();
     674           this.scheduleBindService(_arg0, _arg1, _arg2, _arg3);
     675           return true;
     676         }
    

    662行_arg0是一个BinderProxy对象,readStrongBinder的实现我们之前分析过,可以回顾前文。

    674行,这里的this是谁?是ApplicationThread类实例,服务端进程里的。走进去

    frameworks/base/core/java/android/app/ActivityThread.java

     954         public final void scheduleBindService(IBinder token, Intent intent,
     955                 boolean rebind, int processState) {
     956             updateProcessState(processState, false);
     957             BindServiceData s = new BindServiceData();
     958             s.token = token;
     959             s.intent = intent;
     960             s.rebind = rebind;
     965             sendMessage(H.BIND_SERVICE, s);
     966         }
    

    此时我们处于binder线程,所以需要通过handler将消息发给mH,在主线程中处理组件的生命周期onBind方法。

    frameworks/base/core/java/android/app/ActivityThread.java

    1853         public void handleMessage(Message msg) {
    1855             switch (msg.what) {
    1878                 case BIND_SERVICE:
    1880                     handleBindService((BindServiceData)msg.obj);
    1882                     break;
    

    frameworks/base/core/java/android/app/ActivityThread.java

    3970     private void handleBindService(BindServiceData data) {
    3971         Service s = mServices.get(data.token);
    3975             try {
    3976                 data.intent.setExtrasClassLoader(s.getClassLoader());
    3977                 data.intent.prepareToEnterProcess();
    3978                 try {
    3979                     if (!data.rebind) {
    3980                         IBinder binder = s.onBind(data.intent);
    3981                         ActivityManager.getService().publishService(
    3982                                 data.token, data.intent, binder);
    3983                     }
    3988                 } catch (RemoteException ex) {}
    3991             } catch (Exception e) {}
    3999     }
    

    3980行,调用Service的onBind生命周期方法,我们知道,aidl的服务端Service实现了这个方法,并且return 一个准备好的ISecondary.Stub mSecondaryBinder对象。所以这里的3980行IBinder binder就是一个Binder对象。
    下一步3981行,将Service发布到ams。

    2.4 publishService:服务提供者app进程-->ams

    现在走到ams所在进程里

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    14112     public void publishService(IBinder token, Intent intent, IBinder service) {
    14118         synchronized(this) {
    14122             mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    

    frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

    1845     void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    1847         try {
    1850             if (r != null) {
    1851                 Intent.FilterComparison filter
    1852                         = new Intent.FilterComparison(intent);
    1853                 IntentBindRecord b = r.bindings.get(filter);
    1854                 if (b != null && !b.received) {
    1855                     b.binder = service;
    1856                     b.requested = true;
    1857                     b.received = true;
    1858                     ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
    1859                     for (int conni = connections.size() - 1; conni >= 0; conni--) {
    1860                         ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
    1861                         for (int i=0; i<clist.size(); i++) {
    1862                             ConnectionRecord c = clist.get(i);
    1863                             if (!filter.equals(c.binding.intent.intent)) {
    1870                                 continue;
    1871                             }
    1873                             try {
    1874                                 c.conn.connected(r.name, service, false);
    1875                             } catch (Exception e) {
    

    1874行我们见过,在onBind流程那里,只不过没有走进去。现在我们onBind走完了,走到publish的流程。正是在此处触发的发起者app进程里onServiceConnected回调方法。

    1859行和1861行是两层遍历,遍历什么呢?遍历ArrayMap<IBinder, ArrayList<ConnectionRecord>>这个map,找到和我们的intent匹配的ConnectionRecord。c.conn对象存放了IServiceConnection类型Stub.Proxy对象。还记得new InnerConnection(this)吗,可以回顾下前文创建流程。

    2.5 最后的旅途:ams-->发起者app进程onServiceConnected回调

    走进c.conn.connected方法的服务端实现,现在我们把视角转回发起者app进程

    out/soong/.intermediates/frameworks/base/framework/android_common/gen/aidl/frameworks/base/core/java/androi
    d/app/IServiceConnection.java

     20   public static abstract class Stub extends android.os.Binder implements android.app.IServiceConnection{
     67     @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
     77         case TRANSACTION_connected:
     78         {
     79           data.enforceInterface(descriptor);
     80           android.content.ComponentName _arg0;
     81           if ((0!=data.readInt())) {
     82             _arg0 = android.content.ComponentName.CREATOR.createFromParcel(data);
     83           }
     84           else {
     85             _arg0 = null;
     86           }
     87           android.os.IBinder _arg1;
     88           _arg1 = data.readStrongBinder();
     89           boolean _arg2;
     90           _arg2 = (0!=data.readInt());
     91           this.connected(_arg0, _arg1, _arg2);
     92           return true;
     93         }
     98       }
    

    91行的this是InnerConnection对象,所以走进LoadedApk.java的内部类ServiceDispatcher的内部类InnerConnection的connected方法。

    frameworks/base/core/java/android/app/LoadedApk.java

    1776         private static class InnerConnection extends IServiceConnection.Stub {
    1778             final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
    1779
    1780             InnerConnection(LoadedApk.ServiceDispatcher sd) {
    1781                 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
    1782             }
    1784             public void connected(ComponentName name, IBinder service, boolean dead)
    1785                     throws RemoteException {
    1786                 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    1787                 if (sd != null) {
    1788                     sd.connected(name, service, dead);
    

    1788行,此处sd是其外部类ServiceDispatcher,继续走

    frameworks/base/core/java/android/app/LoadedApk.java

    1878         public void connected(ComponentName name, IBinder service, boolean dead) {
    1879             if (mActivityExecutor != null) {
    1880                 mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
    1881             } else if (mActivityThread != null) {
    1882                 mActivityThread.post(new RunConnection(name, service, 0, dead));
    1883             } else {
    1884                 doConnected(name, service, dead);
    1885             }
    1886         }
    

    当初ServiceDispatcher类实例化时,参数ActivityExecutor是null,Handler不是,所以走到1882行。

    frameworks/base/core/java/android/app/LoadedApk.java

    1970         private final class RunConnection implements Runnable {
    1978             public void run() {
    1979                 if (mCommand == 0) {
    1980                     doConnected(mName, mService, mDead);
    1981                 } else if (mCommand == 1) {
    

    frameworks/base/core/java/android/app/LoadedApk.java

    1898         public void doConnected(ComponentName name, IBinder service, boolean dead) {
    1899             ServiceDispatcher.ConnectionInfo old;
    1900             ServiceDispatcher.ConnectionInfo info;
    1901
    1902             synchronized (this) {
    1914                 if (service != null) {
    1916                     info = new ConnectionInfo();
    1917                     info.binder = service;
    1918                     info.deathMonitor = new DeathMonitor(name, service);
    1919                     try {
    1920                         service.linkToDeath(info.deathMonitor, 0);
    1921                         mActiveConnections.put(name, info);
    1922                     } catch (RemoteException e) {}
    1929                 } else {
    1931                     mActiveConnections.remove(name);
    1932                 }
    1937             }
    1946             // If there is a new viable service, it is now connected.
    1947             if (service != null) {
    1948                 mConnection.onServiceConnected(name, service);
    1949             } else {
    

    1918行和1920行是注册死亡监听,又是一次binder调用,此处按下不表,以后分析。

    关键点是1948行,调用我们activity里ServiceConnection mSecondaryConnection的回调方法onServiceConnected。这里的参数name是服务端Service的ComponentName,service是BinderProxy对象,是服务提供者app进程的代理。

    回来了O(∩_∩)O哈哈~。

    至此,activity就可以使用这个ISecondary.Stub.Proxy(BinderProxy)对象同进程外的Service通信了,binder-ipc通信。

    总结

    在发起者app进程里:

    1、new一个ServiceConnection实例,实现回调方法。(普通回调接口无关binder)

    2、在bindService的流程里ContextImpl中,new一个IServiceConnection类型Binder对象,填入上面的回调对象和其他关键信息。

    3、通过IActivityManager的接口bindIsolatedService跨进程将上面准备的东西发给AMS。

    在AMS进程里:

    4、AMS进程里处理这些信息,找到提供Service的app进程(进程不在则创建),走入其onBind方法

    在Service提供者app进程里:

    6、收到AMS的数据,走进ApplicationThread-->handleBindService方法。在这个方法里

    ​ 6.1执行onBind回调方法,拿到一个ISecondary.Stub mSecondaryBinder,Binder对象

    ​ 6.2发起binder通信ActivityManager.getService().publishService,传送这个Binder对象给ams

    在AMS的进程里:

    7、在publishServiceLocked方法里,发起binder通信,c.conn.connected,使用先前发起者APP进程传送,ams通过readStrongBinder拿到的IServiceConnection的BinderProxy对象,去沟通发起者APP进程,走入其onServiceConnected回调方法

    在发起者app进程里:

    8、执行了onServiceConnected回调方法,我们在这里会拿到代表Service提供者app进程的BinderProxy实例,经ISecondary.Stub.asInterface方法处理,得到一个Stub.Proxy(BinderProxy)对象。return new com.example.android.apis.app.ISecondary.Stub.Proxy(obj);

    现在一个漫长的binder调用去去回回结束了,我们的请求终于得到了答复。

    这样我们就可以使用这个Stub.Proxy(BinderProxy)对象直接和Service提供者app进程的Service进行binder通信了。

    作者:秋城 | 博客:https://www.cnblogs.com/houser0323 | 转载请注明作者出处
  • 相关阅读:
    浏览器页面呈现过程
    Function与Object
    前端性能优化方案
    CSS引入方式
    浏览器事件
    Js继承的实现方式
    H5页面 绝对定位元素被 软键盘弹出时顶起
    总结angular+ionic项目中的问题
    vue开发学习中遇到的问题以及解决方法
    css重修之书(一):如何用css制作比1px更细的边框
  • 原文地址:https://www.cnblogs.com/houser0323/p/14571890.html
Copyright © 2020-2023  润新知