美文网首页
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