美文网首页
Android 进程通信bindService详解

Android 进程通信bindService详解

作者: 雷涛赛文 | 来源:发表于2020-12-17 11:00 被阅读0次

          Android系统涉及到许多进程间通信,也提供了实名及匿名Binder,例如:AMS是属于实名Binder,在系统启动中通过ServiceManager来启动并在ServiceManager中进行注册;如果两个非系统应用之间进行通信,那么可以通过AIDL和bindService来进行通信,一个做server端,一个做client端,server端提供匿名的Binder。本文通过一个实例来讲解一下AIDL和bindService的使用及流程分析。

    一.AIDL具体实现

    a.创建IData.aidl文件,定义Server端提供的能力
    interface IData {
        int getSharedDisplayNum(int currDisplay, int appType);
    }
    

          接着说一下在AIDL文件中支持的数据类型包括:
          1.基本数据类型
          2.String和CharSequence
          3.List:只支持ArrayList,里面的元素都必须被AIDL支持
          4.Map:只支持HashMap,里面的元素必须被AIDL 支持
          5.实现Parcelable接口的对象
          6.所有AIDL接口
          此时编译器会对aidl文件自动编译生成IData.java文件,该文件是Android为了快速能使用Binder而做的一个模板,即生成通信层代码模板,用户只用关心业务层的逻辑,降低开发难度。

    b.IData.java文件
    public interface IData extends android.os.IInterface {
        /** Local-side IPC implementation stub class. */
        //Stub继承了Binder,实现了IData接口,内部的方法需要在Service创建Stub时实现
        public static abstract class Stub extends android.os.Binder implements com.hly.learn.IData {
            //用来区分binder
            private static final java.lang.String DESCRIPTOR = "com.hly.learn.IData";
            /** Construct the stub at attach it to the interface. */
            //本地创建Stub时,会将DESCRIPTOR传到Binder里面,后续可以通过queryLocalInterface()来查询到对应的Binder实体
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
            public static com.hly.learn.IData asInterface(android.os.IBinder obj) {
                if ((obj==null)) {
                    return null;
                }
                 //去查找 Binder 本地对象,如果找到了就说明 Client 和 Server 在同一进程,那么这个binder本身就是 Binder本地对象,可以直接使用
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin!=null)&&(iin instanceof com.hly.learn.IData))) {
                    return ((com.hly.learn.IData)iin);
                 }
                //否则返回的是实现了IData接口的Proxy对象,但不是Binder
                return new com.hly.learn.IData.Stub.Proxy(obj);
           }
           @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            //client调用后,server端需要的逻辑处理
            ........
            }
            //代理对象是IData,不是Binder
            private static class Proxy implements com.hly.learn.IData {
                 private android.os.IBinder mRemote;
                 //client获取到这个代理对象时,传参是Binder引用,最终是通过该引用来与server进行通信
                 Proxy (android.os.IBinder remote) {
                       mRemote = remote;
                 }
                 .......
                 //由于是实现了IData接口,需要实现其方法
                @Override public int getSharedDisplayNum(int currDisplay, int appType) throws   android.os.RemoteException {
                ........
                }
        }
        //本地Stub需要实现的方法
        public int getSharedDisplayNum(int currDisplay, int appType) throws android.os.RemoteException;
    }
    
    c.Server端实现Binder
    public class DataService extends Service {
        private static final String TAG = DataService.class.getSimpleName();
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            super.onStartCommand(intent, flags, startId);
            return Service.START_STICKY;
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            FLog.d(TAG, "data service is bound");
            return mBinder;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            return super.onUnbind(intent);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    
        private IData.Stub mBinder = new IData.Stub() {
            @Override
            public int getSharedDisplayNum(int currDisplay, int appType) {
                if (mService != null) {
                    return mService.getInSharedDisplayNum(currDisplay, appType);
                }
                return 0;
            }
        };
    }
    
    d.Client端绑定服务
    public class MainActivity extends AppCompatActivity {
    
        private ServiceConnection mConnection;
        private IData mDataService;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            TextView tv = findViewById(R.id.bind_service);
            tv.setOnClickListener(v -> bindServer());
        }
    
        private void bindServer() {
            mConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    try {
                        mDataService = IMyAidlInterface.Stub.asInterface(service);
                    } catch (Exception e) {
                    }
                }
    
                @Override
                public void onServiceDisconnected(ComponentName name) {
                    try {
                        mDataService = null;
                    } catch (Exception e) {
    
                    }
                }
            };
            Intent intent = new Intent("com.hly.action.DataService");
            intent.setClassName("com.hly.server", "com.hly.server.DataService");
            bindService(intent, mFlowConnection, Service.BIND_AUTO_CREATE);
    
        }
    }
    
    e.IData.java文件详解

          Client端调用Server端的方法:

    @Override public int getSharedDisplayNum(int currDisplay, int appType) throws  android.os.RemoteException {
        //Client进程创建传输数据的Parcel对象
        android.os.Parcel _data = android.os.Parcel.obtain();
        //client进程创建返回数据的Parcel对象,目标方法执行后的结果
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            //1.将需要传送的数据写入到Parcel对象中
            _data.writeInt(currDisplay);
            _data.writeInt(appType);
            //2.调用mRemote[Binder引用]的transact()将上述数据发送到Binder驱动
            mRemote.transact(Stub.TRANSACTION_getSharedDisplayNum, _data, _reply, 0);
            //在发送数据后,Client进程的该线程会暂时被挂起
            // 所以,若Server进程执行的耗时操作,请不要使用主线程,以防止ANR
            // 3. Binder驱动根据 mRemote 找到对应的真身Binder对象所在的Server 进程(系统自动执行)
            // 4. Binder驱动把数据发送到Server 进程中,并通知Server进程执行解包(系统自动执行)
            _reply.readException();
            _result = _reply.readInt();
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
    static final int TRANSACTION_getSharedDisplayNum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    

          Server端收到调用后处理:

    // 1. 收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法
    @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 INTERFACE_TRANSACTION:{
            reply.writeString(descriptor);
            return true;
        }
        case TRANSACTION_getSharedDisplayNum:{
             // 解包Parcel中的数据
            data.enforceInterface(descriptor);
            // 获得目标方法的参数
            int _arg0;
            _arg0 = data.readInt();
            int _arg1;
            _arg1 = data.readInt();
            //调用本地已实现的方法
            int _result = this.getSharedDisplayNum(_arg0, _arg1);
            reply.writeNoException();
            //返回结果
            reply.writeInt(_result);
            return true;
        }
        default:{
            return super.onTransact(code, data, reply, flags);
        }
    }
    

          Server进程将结果返回client进程:

    mRemote.transact(Stub.TRANSACTION_getSharedDisplayNum, _data, _reply, 0);
            // 1. Binder驱动根据 代理对象 沿原路 将结果返回 并通知Client进程获取返回结果
            // 2. 通过代理对象接收结果(之前被挂起的线程被唤醒)
            _reply.readException();
            _result = _reply.readInt();
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    

          以上就是通过AIDL和bindService()来进行进程通信。

    二.bindService()执行流程

          Client端通过bindService()来与Server端进行了绑定,从而可以跟本地调用接口一样调用Server端的接口,先画出bindService的流程图,主要总结了以下几种场景的流程图:

    a.基于Server端进程已经启动,Service未启动的场景
    image.png
    b.基于Server端进程已经启动,service已经启动和service已经启动且被bind()的场景
    image.png

    三.源码分析

          从上述流程图可以看到,在activity、service或通过context来进行bindService(),最终会通过ActivityManagerService来进行调用:

    a.ContextImpl.bindServiceCommon
        private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
                handler, UserHandle user) {
            // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
            IServiceConnection sd;
            if (conn == null) {
                throw new IllegalArgumentException("connection is null");
            }
            if (mPackageInfo != null) {
                //该方法是通过传入的ServiceConnection获取到IServiceConnection
                //后续绑定成功后,会通过该实例回调client的onServiceConnected()方法
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            } else {
                throw new RuntimeException("Not supported in system context");
            }
            validateServiceIntent(service);
            try {
                ......
                //调用ActivityManagerService的方法
                int res = ActivityManager.getService().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier());
                .....
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
    

          首先通过LoaderApk里面getServiceDispatcher()将ServiceConnection转换为IServiceConnection对象,里面进行了多层封装,当绑定成功后,会一层层的执行到client端的onServiceConnected();
          最后会调用ActivityManagerServce的bindService()方法,其中bindService的入参mMainThread.getApplicationThread()方法返回的是ApplicationThread对象, 该对象继承于ApplicationThread.Stub(Binder服务端),这个ApplicationThread对象串联起了后续AMS对发起端进程ActivityThread的交互(如果把ApplicationThread当作服务端,那么此时AMS相关于ApplicationThread而言就是客户端)。

    b.ActivityManagerService.bindService
    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) {
                return mServices.bindServiceLocked(caller, token, service,
                        resolvedType, connection, flags, callingPackage, userId);
    

          通过以上可以看到,ActivityManagerService将事务委托给ActiveServices类实例对象进行处理。

    c.ActiveServices.bindServiceLocked
    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                String resolvedType, final IServiceConnection connection, int flags,
                String callingPackage, final int userId) throws TransactionTooLargeException {
            ......
            ......
            //创建对象ConnectionRecord,此处connection来自发起方
                ConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent);
            //保存ConnectionRecord省略......
            .......
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                    s.lastActivity = SystemClock.uptimeMillis();
                    //启动service
                    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                            permissionsReviewRequired) != null) {
                        return 0;
                    }
                }
           ......
           ......
           //Service进程启动,且Service启动,且该Service已经被绑定过,直接将binder回调给client端
           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.shortName
                                + " 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) {
                    //Service进程启动,且Service启动,会调用以下逻辑
                    requestServiceBindingLocked(s, b.intent, callerFg, false);
                }
    

          在bindServiceLocked()里面会根据发起端创建对应的ConnectionRecord对象的成员变量c,该ConnectionRecord对象里面存储了IServiceConnection,再通过clist.add( c ),将该ConnectionRecord对象添加到clist队列,后面便可以通过clist来查询发起方的信息,当绑定成功后,会通过该ConnectionRecord.IServiceConnection.connected()进行回调。然后调用bringUpServiceLocked()来启动进程及创建service,如果之前有绑定过,则会直接将binder返回给client端。

    d.ActiveServices.bringUpServiceLocked
    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
                boolean whileRestarting, boolean permissionsReviewRequired)
                throws TransactionTooLargeException {
            //Service进程已经启动,Service已经启动
            if (r.app != null && r.app.thread != null) {
                sendServiceArgsLocked(r, execInFg, false);
                return null;
            }
    
            final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
            final String procName = r.processName;
            String hostingType = "service";
            ProcessRecord app;
    
            if (!isolated) {
                app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
                //Service进程已经启动,Service未启动,来启动Service
                if (app != null && app.thread != null) {
                    try {
                        app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                        realStartServiceLocked(r, app, execInFg);
                        return null;
                    } catch (TransactionTooLargeException e) {
                        throw e;
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                    }
    
                    // If a dead object exception was thrown -- fall through to
                    // restart the application.
                }
            }
    
            //Service进程未启动,先启动进程
            //AMS--->Process.start()--->ZygoteProcess.startxx()--------->AcitivityThread.main()---->attach()-------
            if (app == null && !permissionsReviewRequired) {
                if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                        hostingType, r.name, false, isolated, false)) == null) {
                    String msg = "Unable to launch app "
                            + r.appInfo.packageName + "/"
                            + r.appInfo.uid + " for service "
                            + r.intent.getIntent() + ": process is bad";
                    Slog.w(TAG, msg);
                    bringDownServiceLocked(r);
                    return msg;
                }
                if (isolated) {
                    r.isolatedProc = app;
                }
            }
            .......
            //把要绑定的service加入到mPendingServices里面,后续在进程启动完成后,会attach()
            //继而调用到attachAppliactionLocked()在里面启动service
            if (!mPendingServices.contains(r)) {
                mPendingServices.add(r);
            }
    }
    

          当需要创建新的进程时候,会调用AMS.startProcessLocked启动进程,然后通过AMS--->Process.start()--->ZygoteProcess.startxx()--------->AcitivityThread.main()---->attach()调用到attachApplicationLocked方法,进而调用realStartServiceLocked()方法。
          若不用创建进程,则直接调用realStartServiceLocked方法,进行启动service的工作。

    e.ActiveServices.realStartServiceLocked
    private final void realStartServiceLocked(ServiceRecord r,
                ProcessRecord app, boolean execInFg) throws RemoteException {
             .......
            r.app = app;
            r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
    
            final boolean newService = app.services.add(r);
            //发送延迟消息,如果在20s内没有收到service onCreate()完毕的ServiceDoneExecuting
            //则会报timeout error
            bumpServiceExecutingLocked(r, execInFg, "create");
            mAm.updateLruProcessLocked(app, false, null);
            updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
            mAm.updateOomAdjLocked();
    
            boolean created = false;
            try {
                ......
                synchronized (r.stats.getBatteryStats()) {
                    r.stats.startLaunchedLocked();
                }
                mAm.notifyPackageUse(r.serviceInfo.packageName,
                                     PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
                app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                //在service进程创建要绑定的service
                app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                        app.repProcState);
                r.postNotification();
                created = true;
            }
            .......
            //执行bind()
            requestServiceBindingsLocked(r, execInFg);
    
           .......
    }
    

          在bumpServiceExecutingLocked会发送一个延迟处理的消息SERVICE_TIMEOUT_MSG。在方法scheduleCreateService执行完成,也就是onCreate回调执行完成之后收到ServiceDoneExecuting便会remove掉该消息。但是如果没能在延时时间之内remove该消息,则会进入执行service timeout流程触发ANR,这就是为啥Android四大组件不能执行耗时操作的原因。
          在执行app.thread.scheduleCreateService后,会进行requestServiceBindingsLocked()来进行service的绑定。

    f.ActivityThread
    private void handleCreateService(CreateServiceData data) {
            ......
            Service service = null;
            try {
                //通过反射创建service对象
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                service = (Service) cl.loadClass(data.info.name).newInstance();
            }
            ......
            }
    
            try {
                .......
                service.attach(context, this, data.info.name, data.token, app,
                        ActivityManager.getService());
                //调用service的onCreate()
                service.onCreate();
                mServices.put(data.token, service);
                try {
                    ///调用AMS发送service创建完成,在ActiveServices里面将ANR消息除去
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
    }
    

          在handleCreateService()里面,通过反射创建对应的service,然后调用onCreate()方法,最后通过AMS发送serviceDoneExecuting()来告知service已经create完成,消除TIME_OUT消息。

    g.ActiveServices.requestServiceBindingLocked
    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
                boolean execInFg, boolean rebind) throws TransactionTooLargeException {
            //如果service没有启动,直接返回false,在serivice进程没有启动,进行bind时,有的分支会调用到这里
            if (r.app == null || r.app.thread == null) {
                // If service is not currently running, can't yet bind.
                return false;
            }
            ......
            if ((!i.requested || rebind) && i.apps.size() > 0) {
                try {
                    //发送bind开始的消息,跟create是类似的
                    bumpServiceExecutingLocked(r, execInFg, "bind");
                    r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                    //回调service进程来执行onBind
                    r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                            r.app.repProcState);
                    if (!rebind) {
                        i.requested = true;
                    }
                    i.hasBound = true;
                    i.doRebind = false;
                }
                ........
            }
            return true;
        }
    

          在该方法中,首先也是先发送TIME_OUT消息,跟create()是类似的,接着与service进程的ActivityThread的ApplicationThread进行通信执行scheduleBindService(),会执行service的onBind()方法。

    h.ActivityThread
    private void handleBindService(BindServiceData data) {
            Service s = mServices.get(data.token);
            if (s != null) {
                try {
                    data.intent.setExtrasClassLoader(s.getClassLoader());
                    data.intent.prepareToEnterProcess();
                    try {
                        if (!data.rebind) {
                            //执行Service.onBind()回调方法获取到binder
                            IBinder binder = s.onBind(data.intent);
                           //通过AMS将onBind返回值传递回去
                            ActivityManager.getService().publishService(
                                    data.token, data.intent, binder);
                        }
                        ......
                }
        }
    

          上步讲到执行r.app.thread.scheduleBindService(),最终会通过sendMessage()调用到ActivityThread内的handleBindService(),先通过执行service的onBind()方法获取到本地实现的Binder,然后通过ActivityManagerService的publishService()来将binder传递。

    i.ActiveServices.publishServiceLocked
    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;
                        for (int conni=r.connections.size()-1; conni>=0; conni--) {
                            ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                            for (int i=0; i<clist.size(); i++) {
                                ConnectionRecord c = clist.get(i);
                                if (!filter.equals(c.binding.intent.intent)) {
                                    ......
                                    continue;
                                }
                                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                                try {
                                    //回调connected方法,最终会回调client端的onServiceConnected(),将service(binder)返回给client端。
                                    c.conn.connected(r.name, service, false);
                                } catch (Exception e) {
                                    Slog.w(TAG, "Failure sending service " + r.name +
                                          " to connection " + c.conn.asBinder() +
                                          " (in " + c.binding.client.processName + ")", e);
                                }
                            }
                        }
                    }
    
                    serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
    

          ActivityManagerService内的publishService会调用到ActiveServices里面的publishServiceLocked(),从clist里面获取到对应的client对应的ConnectionRecord,然后回调内部变量connection的connected()方法,该方法最终会调用到LoaderApk里面的逻辑,前面在bindService的getServiceDispatcher()已经埋下了伏笔。

    j.LoadedApk.ServiceDispatcher
        public final IServiceConnection getServiceDispatcher(ServiceConnection c,
                Context context, Handler handler, int flags) {
            synchronized (mServices) {
                LoadedApk.ServiceDispatcher sd = null;
                ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
                //先从map里面获取
                if (map != null) {
                    if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                    sd = map.get(c);
                }
                //如果没有获取到,则创建对象,然后加入map
                if (sd == null) {
                    sd = new ServiceDispatcher(c, context, handler, flags);
                    if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                    if (map == null) {
                        map = new ArrayMap<>();
                        mServices.put(context, map);
                    }
                    map.put(c, sd);
                } else {
                    sd.validate(context, handler);
                }
                //调用ServiceDispatcher的方法返回IServiceConnection对象。
                return sd.getIServiceConnection();
            }
        }
    

          再看一下ServiceDispatcher这个内部类:

    static final class ServiceDispatcher {
            private final ServiceDispatcher.InnerConnection mIServiceConnection;
            private final ServiceConnection mConnection;
            .......
    
            //构造方法
            ServiceDispatcher(ServiceConnection conn,
                    Context context, Handler activityThread, int flags) {
                //构造方法中创建InnerConnection,,即IServiceConnection实例
                mIServiceConnection = new InnerConnection(this);
                //构造方法中将client的ServiceConnection传进来
                mConnection = conn;
                .......
            }
    
            //返回创建的IServiceConnection对象
            IServiceConnection getIServiceConnection() {
                return mIServiceConnection;
            }
    

          ServiceDispatcher内部会创建ServiceDispatcher.InnerConnection实例,该InnerConnection继承IServiceConnection.Stub,该binder用来跟AMS进行通信的,在bindSerice时作为参数传入的,当被bind的service准备好时,会通过该binder回调onConnected()方法。

            //内部类继承IServiceConnection.Stub
            private static class InnerConnection extends IServiceConnection.Stub {
                final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
    
                InnerConnection(LoadedApk.ServiceDispatcher sd) {
                    mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
                }
                //1.绑定成功后会先调用该connected()方法
                public void connected(ComponentName name, IBinder service, boolean dead)
                        throws RemoteException {
                    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                    if (sd != null) {
                        sd.connected(name, service, dead);
                    }
                }
            }
    

          ServiceDispatcher.InnerConnection内部的onConnected()内部又会调用到ServiceDispatcher自身的onConnected()方法,通过mActivityThread.post()[RunConnection内部command为1,表示执行doConnected();command为0,表示执行doDeath()]来最终调用doConnected()方法,再最终调用到本地bindService时实现的onServiceConnected()方法。

            //2.通过InnerConnection.connected()来调用ServiceDispatcher的connected()方法
            public void connected(ComponentName name, IBinder service, boolean dead) {
                if (mActivityThread != null) {
                    mActivityThread.post(new RunConnection(name, service, 0, dead));
                } else {
                    doConnected(name, service, dead);
                }
            }
    
            //3.再调用doConnected()方法
            public void doConnected(ComponentName name, IBinder service, boolean dead) {
                .......
                ........
                // If there is a new service, it is now connected.
                if (service != null) {
                    //最终会回调ServiceConnection的onServiceConnected()方法。
                    mConnection.onServiceConnected(name, service);
                }
            }
    

          以上就是client进行bindService()的整个流程。

    四.其他

          1.假设被bind的service出现异常导致crash,那本地应该如何操作呢?
          2.假设本地执行unBindService时,那server端的service会如何处理呢?
          跟着问题1,我们一起看一下源码实现,看一下LoadedApk中的ServiceDispatcher这个类的实现:

            public void doConnected(ComponentName name, IBinder service, boolean dead) {
                ServiceDispatcher.ConnectionInfo old;
                ServiceDispatcher.ConnectionInfo info;
    
                synchronized (this) {
                    ......
                    old = mActiveConnections.get(name);
                    if (old != null && old.binder == service) {
                        return;
                    }
    
                    if (service != null) {
                        info = new ConnectionInfo();
                        info.binder = service;
                        info.deathMonitor = new DeathMonitor(name, service);
                        try {
                            service.linkToDeath(info.deathMonitor, 0);
                            mActiveConnections.put(name, info);
                        } catch (RemoteException e) {
                            mActiveConnections.remove(name);
                            return;
                        }
    
                    } else {
                        // The named service is being disconnected... clean up.
                        mActiveConnections.remove(name);
                    }
    
                    if (old != null) {
                        old.binder.unlinkToDeath(old.deathMonitor, 0);
                    }
                }
    
                // If there was an old service, it is now disconnected.
                if (old != null) {
                    mConnection.onServiceDisconnected(name);
                }
                if (dead) {
                    mConnection.onBindingDied(name);
                }
                // If there is a new service, it is now connected.
                if (service != null) {
                    mConnection.onServiceConnected(name, service);
                }
            }
    

          通过以上可以看到,在bind成功后,先执行了service.linkToDeath(info.deathMonitor, 0),然后才会回调本地实现的onServiceConnected()方法,接下来看一下DeathMonitor的逻辑,实现了IBinder.DeathRecipient,当binder异常后,会回调binderDied()方法:

        private final class DeathMonitor implements IBinder.DeathRecipient
            {
                DeathMonitor(ComponentName name, IBinder service) {
                    mName = name;
                    mService = service;
                }
    
                public void binderDied() {
                    death(mName, mService);
                }
    
                final ComponentName mName;
                final IBinder mService;
            }
        }
    
        public void death(ComponentName name, IBinder service) {
                if (mActivityThread != null) {
                    mActivityThread.post(new RunConnection(name, service, 1, false));
                } else {
                    doDeath(name, service);
                }
            }
    
        public void doDeath(ComponentName name, IBinder service) {
                synchronized (this) {
                    ConnectionInfo old = mActiveConnections.get(name);
                    if (old == null || old.binder != service) {
                        return;
                    }
                    mActiveConnections.remove(name);
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
    
                mConnection.onServiceDisconnected(name);
            }
    

          在server端出现异常crash时,会调用IBinder.DeathRecipient的binderDied()方法,即DeathMonitor的binderDied(),然后调用death()--->runnable--->doDeath(),先调用unlinkToDeath(),最后调用本地实现的onServiceDisconnected(),所以我们本地实现时,不需要自己手动执行service.linkToDeath()了,直接在onServiceDisconnected()内部重新进行bindService()就可以了。
          跟着问题2,本地在执行unBindService()后,会调用到AMS,然后还是交由ActiveServices来进行处理:

        boolean unbindServiceLocked(IServiceConnection connection) {
            IBinder binder = connection.asBinder();
            ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
            ......
            final long origId = Binder.clearCallingIdentity();
            try {
                while (clist.size() > 0) {
                    ConnectionRecord r = clist.get(0);
                    removeConnectionLocked(r, null, null);
                    if (clist.size() > 0 && clist.get(0) == r) {
                        clist.remove(0);
                    }
                    .....
                    .....
               }
            } 
            return true;
        }
    

          在unbindServiceLocked()内部会执行removeConnectionLocked(),看一下实现:

        void removeConnectionLocked(
            ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
            IBinder binder = c.conn.asBinder();
            AppBindRecord b = c.binding;
            ServiceRecord s = b.service;
            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
            if (clist != null) {
                clist.remove(c);
                if (clist.size() == 0) {
                    s.connections.remove(binder);
                }
            }
            b.connections.remove(c);
            if (c.activity != null && c.activity != skipAct) {
                if (c.activity.connections != null) {
                    c.activity.connections.remove(c);
                }
            }
            if (b.client != skipApp) {
                b.client.connections.remove(c);
                ......
            }
            clist = mServiceConnections.get(binder);
            if (clist != null) {
                clist.remove(c);
                if (clist.size() == 0) {
                    mServiceConnections.remove(binder);
                }
            }
    
            mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);
    
            if (b.connections.size() == 0) {
                b.intent.apps.remove(b.client);
            }
    
            if (!c.serviceDead) {
                if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                        && b.intent.hasBound) {
                    try {
                        bumpServiceExecutingLocked(s, false, "unbind");
                        ......
                        b.intent.hasBound = false;
                        b.intent.doRebind = false;
                        s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                    } catch (Exception e) {
                        Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
                        serviceProcessGoneLocked(s);
                    }
                }
                ......
                if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
                    boolean hasAutoCreate = s.hasAutoCreateConnections();
                    .......
                    bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
                }
            }
        }
    

          在执行removeConnectionLocked()内部会先将删除对应的ConnectionRecord,接下来会调用server端的scheduleUnbindService(),会回调到ActivityThread中的handleUnbindService(),内部调用如下:

        private void handleUnbindService(BindServiceData data) {
            Service s = mServices.get(data.token);
            if (s != null) {
                try {
                    data.intent.setExtrasClassLoader(s.getClassLoader());
                    data.intent.prepareToEnterProcess();
                    //默认为false
                    boolean doRebind = s.onUnbind(data.intent);
                    try {
                        if (doRebind) {
                            ActivityManager.getService().unbindFinished(
                                    data.token, data.intent, doRebind);
                        } else {
                            ActivityManager.getService().serviceDoneExecuting(
                                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                        }
                    }
                    .........
            }
        }
    

          在handleUnbindService()内部先取到被绑定的service,然后调用service的onUnbind()方法,该方法一般不会做操作,直接super.onUnbind(),返回false,即执行跟AMS通信调用serviceDoneExecuting()来清除队列消息。
          接着上面分析,最后会调用到bringDownServiceIfNeededLocked(s, true, hasAutoCreate),判断是否需要关闭service,如果没有绑定的,需要关闭service,会调用到bringDownServiceLocked(),看一下该方法:

    private final void bringDownServiceLocked(ServiceRecord r) {
         ......
         .......
         if (r.app != null) {
                synchronized (r.stats.getBatteryStats()) {
                    r.stats.stopLaunchedLocked();
                }
                r.app.services.remove(r);
                if (r.whitelistManager) {
                    updateWhitelistManagerLocked(r.app);
                }
                if (r.app.thread != null) {
                    updateServiceForegroundLocked(r.app, false);
                    try {
                        bumpServiceExecutingLocked(r, false, "destroy");
                        mDestroyingServices.add(r);
                        r.destroying = true;
                        mAm.updateOomAdjLocked(r.app, true);
                        r.app.thread.scheduleStopService(r);
                    }
              }
              ............
         }
              ......
    }
    

          内部会调用到server端的ActivityThread来执行scheduleStopService()来关闭service。即如果一个service通过bindService()来启动后,如果没有client端都执行了unBindService(),那么这个server端对应的service也就没有必要一直运行了,就需要关闭。

    五.流程概括

          客户端在绑定服务端的service时,主要经历了六个过程,概括如下:

    a.客户端进程与ServiceManager通信获取AMS对应的IBinder
    image.png
    b.客户端进程通过AMS的IBinder与AMS通信,请求执行bindService()
    c.AMS与服务端进程进行通信,执行scheduleBindService(),继而会执行Service的onBind()
    image.png
    d.服务端进程与ServiceManager通信获取AMS对应的IBinder
    image.png
    e.服务端进程通过AMS的IBinder与AMS通信,执行publishService(),将IBinder给AMS
    f.AMS与客户端进程进行通信,将服务端的IBinder转发给客户端
    image.png
          bindService涉及到的类主要为ContextImpl,LoadedApk,ActivityManagerService,ActiveServices,ActivityThread等,需要进一步深入还需要看源码。

    相关文章

      网友评论

          本文标题:Android 进程通信bindService详解

          本文链接:https://www.haomeiwen.com/subject/pcqogktx.html