背景


今天本来是想给大家写一下高级面试问题答案的,题目:如果一个进程自己调用自己的跨进程接口是否会通过binder,但是刚好这部分又要涉及到Service,那么就来给大家刚好源码级别分析一下bindService。

首先贴出对应流程图:

手机安装samba服务 安卓 samba server_手机安装samba服务

1、客户端调用bindService源码


一般我们发起bindService来绑定远程服务Service,调用如下:

Intent intent = new Intent(MainActivity.this,MyService.class);
            //    startService(intent);
                bindService(intent, new ServiceConnection() {},BIND_AUTO_CREATE);

这里就直接调用了context的bindService方法来绑定,那么接下来继续分析就会调用到
ContextWrapper.java

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

这里会调用mBase,mBase其实本质是ContentImpl类型变量:
ActivityThread.java可以看出

/**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //省略部分
        ContextImpl appContext = createBaseContextForActivity(r);
   //省略部分
    }

所以接下来看ContextImpl.java中的bindService方法:

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

这里又调用bindServiceCommon:

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        //省略部分
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            //这里是核心,调用了AMS的bindIsolatedService
            int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

这个方法最重要就是调用了服务systemserver的AMS bindIsolatedService方法,到此调用端就暂时发起的调用就结束了,当然后面肯定还要继续,因为我们传递了ServiceConnection,通过它我们才可以获取到真正的远端进程的Service

2、SystemServer的AMS处理bindService

下面我们来看
ActivityManagerService的bindIsolatedService方法:

public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String instanceName,
            String callingPackage, int userId) throws TransactionTooLargeException {
       //省略部分

        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, instanceName, callingPackage, userId);
        }
    }

这里调用了mServices的bindServiceLocked方法,mServices是ActiveServices类型:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
      //省略部分
      //AMS中调用retrieveServiceLocked把对应ServiceRecord创建
        ServiceLookupResult res =
            retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
                    callerFg, isBindExternal, allowInstant);
       //省略部分
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                //重要方法,会调用到真正Service对应的服务端进程进行onCreate onBind
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }
              //省略部分
        return 1;
    }

这个方法实在太长,我们主要来分析一下bringUpServiceLocked,因为他才是真正与远端进程交互的方法:

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
                //省略部分
        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
        ProcessRecord app;

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    //核心方法
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } 
            }
        } 
        //省略部分

        return null;
    }

这里我们只分析已经有了远端进程存在情况,这里会调用到一个核心方法realStartServiceLocked:

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
       //省略部分
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            //调用远端进程的scheduleCreateService
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            r.postNotification();
            created = true;
        }
         //省略部分
       当Service Create调用后,会调用要求bind的方法
        requestServiceBindingsLocked(r, execInFg);

       //省略部分
    }

这里我们看到了 app.thread.scheduleCreateService这里就代表AMS会跨进程调用到远端进程CreateService方法,这里具体远端进程由下面分析。
这里CreateService执行后又会调用requestServiceBindingsLocked:

private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

这里又会调用requestServiceBindingLocked:

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
         //省略部分
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                //调用到Service进程执行bind修改
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.getReportedProcState());
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            }
            //省略部分
        }
        return true;
    }

这里最重要方法就是scheduleBindService,他就是让远端执行onBind相关,那么相当于到了这里服务端的任务就完成了一大部分,因为它已经触发了远程Service执行onCreate和onBind,接下来AMS就只需要等待着远程Service进程执行完毕,回调到publishServiceLocked方法:

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
   //省略大部分
                    //会调用到最开始bindService那个客户端进程,而且带有了IBinder service参数
                                c.conn.connected(r.name, service, false);
                           //省略大部分
    }

注意这里publishServiceLocked是由远程Service进程进行主动调用的,然后它干的事就是调用connected方法,其实他就是调用到我们最开始ServiceConnection回调

3、远端服务进程处理

AMS分析时候就说过远端Service执行onCreate,onBind方法
那么从onCreate先开始分析:
这里我们原来课程就分析过这里AMS调用到是在ActivityThread中:
这里我们来看ActivityThread.java的scheduleCreateService方法:

public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }

这里主要创建了一个CreateServiceData,然后就发消息让主线程处理消息:

case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

这里调用是handleCreateService:

private void handleCreateService(CreateServiceData data) {
        //省略部分
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } 
          //省略部分
    }

这里其实和实战课程讲解的Activity创建非常像,主要就是创建出Service这个类然后调用对应onCreate方法,这个就是到了我们app层面Service的onCreate执行,执行完成后这里还会调用AMS的serviceDoneExecuting方法通知到AMS

那接下来Service已经onCreate了,那就要执行onBind了,来看:

public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;

            if (DEBUG_SERVICE)
                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
            sendMessage(H.BIND_SERVICE, s);
        }

这里其实和onCreate一致发消息到主线程:

case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

调用到了handleBindService:

private void handleBindService(BindServiceData data) {
       //省略
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
             //省略
    }

这里handleBindService就更加简单,执行Service的onBind方法后,在调用ActivityManager.getService().publishService方法,并且把onBind返回的IBinder对象也传递进去了,这里就是为什么远端的onBind返回的binder对象会传递到客户端的onServiceConnected方法中

new ServiceConnection() {
                    @Override
                    public void onServiceConnected(ComponentName name, IBinder service) {}