Android bindService流程

本文分析bindService的流程,首先我们通过阅读源码获取一个主线的调用地图,然后提出若干问题,包括:APP进程中如何获取AMS,AMS如何启动APP-service的进程,AMS中如何获取ApplicationThread并与之通讯,Service的启动及绑定流程;然后再通过源码一一解答。最后再整体总结梳理一下整体流程;

预先知识:

  • Binder通信机制

整体分析与总结

主线地图与问题提出

我们从bindService一路跟踪,初步绘制了如下的调用序列图,我们可以以下面的图作为一个主线地图,避免走失,然后根据具体问题进行细节分析。

Context.bindService frameworks/base/core/java/android/content/Context.java ContextImpl.bindService frameworks/base/core/java/android/app/ContextImpl.java ContextImpl.bindServiceCommon frameworks/base/core/java/android/app/ContextImpl.java IActivityManager.bindIsolatedService android/app/IActivityManager.java ActivityManagerService.bindIsolatedService com/android/server/am/ActivityManagerService.java ActiveServices.bindServiceLocked com/android/server/am/ActiveServices.java IApplicationThread.scheduleBindService android/app/IApplicationThread.java Binder.transact binder Binder. transact binder Binder. transact binder ApplicationThread.scheduleBindService frameworks/base/core/java/android/app/ActivityThread.java ActivityThread#handleBindService frameworks/base/core/java/android/app/ActivityThread.java IBinder = Service.onBinder() 自定义的Service实现类 IActivityManager#publishService android/app/IActivityManager.java ActivityManagerService#publishService android/app/IActivityManager.java ActiveServices#publishServiceLocked com/android/server/am/ActiveServices.java IServiceConnection#connected - ActiveServices.requestServiceBindingLocked com/android/server/am/ActiveServices.java APP-client APP进程 AMS-server system_process AMS-server system_process APP:server APP Service进程 1 2

从上图中,我们提出如下问题:

  1. bindServiceCommon到IActivityManager的调用中,是如何获取到ActivityManagerService的?
  2. AMS中如何获取ApplicationThread并与之通讯?
    • ApplicatoinThread的用途?ApplicationThread运行的进程是哪个?
  3. 进程如何启动-即AMS如何创建APP:server进程?
  4. Service如何启动?
  5. Service如何绑定?
    • ServiceConnection 的回调方法何时使用?

问题解答汇总

我们将相关问题的结论提前到此小节,便于后续从比较抽象的层次上来进行复习及预览;

APP进程如何获取AMS?

  • APP进程中通过 ServiceManager.getService(Context.ACTIVITY_SERVICE) 获取的ActivityManagerService的客户端操作代理对象(Proxy)。

    该对象位于APP进程中,可以使用此对象(通过Binder进程间通信)来要求(位于system_process中)的ActivityManagerService进行对应的服务操作;

AMS如何获取ApplicationThread?

  • APP进程在binderSerice时,将自己进程中的ApplicationThread取出,通过Binder机制传递给AMS进程,传递过程中会转换成一个Proxy对象;

    ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
    

服务如何绑定?服务如何启动?进程如何启动?

  • 进程启动
    • 在独立的进程中运行的服务需要先将进程启动,进程的启动是通过APP进程,请求系统进程中的AMS来执行,通过AMS的startProcessLocked方法启动进程,最终会通过socket接口请求zygote进程来启动进程。
    • 在启动时会指定java的入口点为ActivityThread,即进程启动后会运行ActivityThread的main方法;
    • AMS中会记录启动的进程记录(ProcessRecord),对应的ProcessRecord中会记录进程对应的ApplicationThread;
  • 服务启动
    • 服务的启动需要请求AMS来完成
    • 启动时需要先通过PID获取要启动到的ProcessRecord,通过ProcessRecord中记录的ApplicationThread来与对应的进程通信。
    • AMS通过ApplicationThread来通知对应的进程创建服务,ApplicationThread作为通信的接口,实际上最终会通过ActivityThread的handleCreateService来创建服务的实例;
    • 服务创建时,是在APP进程(可能是独立的进程)中进行的,需要通过类加载器加载对应的Service的类,同时构造相应的上下文及资源对象等,然后构造对应的实例;
    • 服务创建成功后,会记录到ActivityThread的一个Service列表中,以便后续管理;
  • 服务绑定
    • 服务绑定先在APP进程中,通过AMS代理对象发起请求,由AMS来安排bind(ActivityManagerService.bindIsolatedService);
    • 然后具体的绑定动作还是通过IApplicationThread安排到APP的Service进程中,最终执行的ActivityThread#handleBindService;
    • 在APP进程中,会将Service取出,然后调用其onBind方法来获取IBinder远程操作对象;
    • 之后再通过AMS调用 ActivityManagerService#publishService 来通知绑定成功的通知到对应的需要绑定服务的APP进程;
    • publishService中会调用ServiceConnection的onServiceConnected方法通知服务连接了;

整体流程总结

待补充

详细分析解答问题

APP进程中如何获取AMS?

说明:

  • 第一次先逐项查看各个小节,最后再看此处的总结;

  • 后续直接查看总结来快速获取结论;

总结:

  • APP进程中通过 ServiceManager.getService(Context.ACTIVITY_SERVICE) 获取的ActivityManagerService的客户端操作代理对象(Proxy)。
  • 该对象位于APP进程中,可以使用此对象(通过Binder进程间通信)来要求(位于system_process中)的ActivityManagerService进行对应的服务操作;

具体查看如下代码:

ContextImpl.bindServiceCommon

我们看 ContextImpl.bindServiceCommon 方法的实现,可以看到是调用了 ActivityManager.getService() 获取的;

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

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        
        if (executor != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
        } else {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        }
	    //
        int res = ActivityManager.getService().bindIsolatedService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, instanceName, getOpPackageName(), user.getIdentifier());

}

ActivityManager.getService()

如下代码,getService实际上是从ServiceManager获取一个ActivityService的Binder远程服务接口对象,并且这个会被设置为单例模式;

frameworks/base/core/java/android/app/ActivityManager.java:

private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
    @Override
    protected IActivityManager create() {
        // 直接通过 ServiceManager.getService 获取一个IBinder对象
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
        final IActivityManager am = IActivityManager.Stub.asInterface(b);
        return am;
    }
};

public static IActivityManager getService() {
    // 直接从IActivityManagerSingleton获取实例
    return IActivityManagerSingleton.get();
}

AMS如何获取到 ApplicatoinThread?

首先,AMS实际上位于系统进程(system_process),而ApplicationThread则位于我们的APP进程,那么为什么需要这个跨进程的操作呢?

  • Service的创建需要经过系统的管理,比方说鉴权及其他管理需要;
  • 而开发者定义的Service的实例的创建逻辑也还是需要开发者来实现,Service对应的类也应该只加载在开发者自己的进程之中,Service使用方实际上还是开发者自己,所以服务的真实实例的创建过程要在应用的进程中;

那么,系统进程(中的AMS)如何获取ApplicationThread呢?

ApplicationThread的来源?

查看 ContextImpl.bindServiceCommon 的代码,可以看到,是在调用AMS的bindService方法时,将自己进程中的ApplicationThreadActivityToken取出传递给了AMS服务;

// frameworks/base/core/java/android/app/ContextImpl.java
final @NonNull ActivityThread mMainThread;
private final @Nullable IBinder mToken;

public IBinder getActivityToken() {
    return mToken;
}

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        try {
            service.prepareToLeaveProcess(this);
            // 调用时传递了ApplicationThread和IBinder
            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();
        }
    }

实际上,上面的mMainThread.getApplicationThread()取出的是我们的APP进程中的ApplicationThread的服务端对象,然后经过IActivityManager进行binder传输(transact)前,会将其转换为一个Proxy代理对象,用于在AMS中请求我们进程的ApplicationThread来提供服务;

// android.app.IActivityManager.Stub#TRANSACTION_bindIsolatedService 
case TRANSACTION_bindIsolatedService:
        {
          data.enforceInterface(descriptor);
          android.app.IApplicationThread _arg0;
          // 这里将IApplicationThread的服务对象转换成一个Proxy代理对象
          _arg0 = android.app.IApplicationThread.Stub.asInterface(data.readStrongBinder());
          android.os.IBinder _arg1;
          _arg1 = data.readStrongBinder();
          android.content.Intent _arg2;
          if ((0!=data.readInt())) {
            _arg2 = android.content.Intent.CREATOR.createFromParcel(data);
          }
          else {
            _arg2 = null;
          }
          java.lang.String _arg3;
          _arg3 = data.readString();
          android.app.IServiceConnection _arg4;
          // 同理,这里将IServiceConnection的服务对象也转换成一个Proxy代理对象
          _arg4 = android.app.IServiceConnection.Stub.asInterface(data.readStrongBinder());
          int _arg5;
          _arg5 = data.readInt();
          java.lang.String _arg6;
          _arg6 = data.readString();
          java.lang.String _arg7;
          _arg7 = data.readString();
          int _arg8;
          _arg8 = data.readInt();
          int _result = this.bindIsolatedService(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8);
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
        }
        
// android.app.IApplicationThread.Stub
 /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements android.app.IApplicationThread
  {
    private static final java.lang.String DESCRIPTOR = "android.app.IApplicationThread";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an android.app.IApplicationThread interface,
     * generating a proxy if needed.
     */
    public static android.app.IApplicationThread asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof android.app.IApplicationThread))) {
        return ((android.app.IApplicationThread)iin);
      }
      // 这里构造成了Proxy
      return new android.app.IApplicationThread.Stub.Proxy(obj);
    }
  }

这里我们暂不考虑ApplicationThread由何处而来,每个进程中都对应一个ActivityThread,ActivityThread中有一个ApplicationThread对象。

ApplicationThread在bind流程中的使用

我们发现,最终是使用 ApplicationThreadrequestServiceBindingLocked 方法来绑定服务的(r.app.thread.scheduleBindService),我们先梳理一下ServiceRecord类同ApplicationThread的关系;

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
// com.android.server.am.ActiveServices#requestServiceBindingLocked
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        if (r.app == null || r.app.thread == null) {
            // If service is not currently running, can't yet bind.
            return false;
        }
	    // 调用ApplicationThread的绑定方法来进行绑定
        r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                                         r.app.getReportedProcState());
        return true;
    }

// frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
ProcessRecord app;          // where this service is running or null.

// frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
IApplicationThread thread;  // the actual proc...  may be null only if
                            // 'persistent' is true (in which case we
                            // are in the process of launching the app)

其中 ServiceRecord.app 的类型为 ProcessRecordServiceRecord.app.thread 的类型为 IApplicationThread,我们梳理下对应的几个类的关系,如下图:

ServiceRecord app:ProcessRecord isolatedProc: ProcessRecord + setProcess(ProcessRecord) IApplicationThread + scheduleBindService(IBinder, Intent, boolean rebind, int processState) + scheduleCreateService(IBinder, ServiceInfo info,… ) + bindApplication(…) IApplicationThread.Stub ApplicationThread ProcessRecord thread:IApplicationThread pid: int ActivityThread mAppThread:ApplicationThread

现在我们看下 ServiceRecord 是何时构造的,首先,根据方法的调用层次,我们可以看到:

  • ActiveServices.bindServiceLocked 方法中,参数中没有ServiceRecord,有的是IApplicationThread及一个IBinder。
  • ActiveServices.requestServiceBindingLocked 方法中,则变成了ServiceRecord类型。
image-20210410215833909

提示:上述调用层次可以在IDEA中选中ActiveServices.requestServiceBindingLocked方法,然后通过“Navigate|Call Hierarchy”(快捷键为ctrl+opt+H)弹出。

所以,接下来我们看下 ActiveServices.bindServiceLocked 方法如何将ApplicationThread存入到ServiceRecord对象中。

ActiveServices.bindServiceLocked
    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        // 这里获取了 ProcessRecord
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);

        final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
        final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
        final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;

        // 将IApplicationThread及IBinder放入到ServiceRecord中的过程在retrieveServiceLocked中
        ServiceLookupResult res =
            retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true,
                    callerFg, isBindExternal, allowInstant);
        // 此处获取ServiceRecord,故在上面
        ServiceRecord s = res.record;
        if (s.app != null && b.intent.received) {
            requestServiceBindingLocked(s, b.intent, callerFg, true);
        } else if (!b.intent.requested) {
            requestServiceBindingLocked(s, b.intent, callerFg, false);
        }
        return 1;
    }

到这里,我们可以发现ServiceRecord是通过retrieveServiceLocked方法获取到的ServiceLookupResult获取到的。

粗略看了下这个retrieveServiceLocked方法,其中逻辑比较多,我们这里转换下思路,直接查找 ServiceRecord.app 的赋值操作

ServiceRecord.app 的赋值

我们可以找到ServiceRecord.app(ProcessRecord)的赋值操作的调用方法为:com.android.server.am.ActiveServices#realStartServiceLocked

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
    	// 在此处赋值
        r.setProcess(app);
	    // ...
}

查看 realStartServiceLocked 的调用序列:

image-20210410224824691

也就是又回到了我们的 bindServiceLocked 方法,其中有一段逻辑是,如果需要创建服务,就执行 bringUpServiceLocked 方法。

// com.android.server.am.ActiveServices#bindServiceLocked   
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {   
        // ... 
			if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }
        // ... 
    }

也就是说,在绑定服务的时候,如果服务没有创建,就先使用bringUpServiceLocked-realStartServiceLocked 进行创建,创建过程中会将ServiceRecord中的app赋值,然后存储起来;

提示:我们可以通过如下IDEA操作来查找赋值操作

  1. 选中成员(这里是 app);

  2. Ctrl+B 或者 Command+鼠标单击,弹出使用列表弹窗;

  3. 然后在弹窗中设置仅查看write访问操作的;然后我们可以找到对应的赋值代码行;

    image-20210410223230694
  4. 通过勾选其中的方法图标,我们可以显示赋值的代码行所在的方法(这里是setProcess);

    image-20210410223820657
  5. 然后我们继续在方法上执行上述操作,可以获取到更加上一步的赋值调用在哪;

    image-20210410224023641

服务如何绑定?服务如何启动?进程如何启动?

  1. bringUpServiceLocked(ServiceRecord r,...) 第一个参数为ServiceRecord,其中的app属性可存储一个进程记录;
  2. 如传入的ServiceRecord参数中表明服务已经启动过,r.app(ProcessRecord) 不为null,且r.app.thread(IApplicationThread)也不为null,则不创建,直接更新参数;
  3. 结下来,则分为两种情况,1)服务为声明单独的进程,则可直接在当前进程中启动;2)服务声明了单独的进程,则需要先启动进程,然后再启动服务;
  4. 非单独进程
    • 进程记录获取:通过AMS直接查询,并未创建,因为进程已经存在了,具体代码为 app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false)
    • 服务启动:使用 realStartServiceLocked(r, app, execInFg); 方法启动
  5. 单独进程
    • 进程记录获取: 通过AMS.mAm.startProcessLocked 方法启动一个新的进程;
      • app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)
    • 服务启动:未在此方法中直接调用 realStartServiceLocked

这里我们可以看到,在单独进程的服务启动流程中,并没有即时调用realStartServiceLocked来启动服务,那么这里就又个问题,独立进程情况下服务何时启动?

  1. 单独进程服务启动: 将待启动的服务加入到mPendingServices(ArrayList<ServiceRecord>),在启动进程后再从此列表中读取需要启动的服务,然后启动;

总结:

  1. 进程记录如何获取?

    • 通过AMS的 startProcessLocked 方法创建(非独立进程的也应该是通过此方法创建,只是创建时机不是这里)
  2. 服务如何启动?

    • 通过 realStartServiceLocked 方法启动(独立进程的应该也是此方法启动,会等到进程启动之后再启动)

    • realStartServiceLocked 中通过 IApplicationThread 执行 scheduleCreateService 来启动服务,最终调用 android.app.ActivityThread.ApplicationThread#scheduleCreateService来启动;

进程创建

问题:

  1. 进程何时创建?- 已解决
  2. ApplicationThread(代理)对象何时设置到ProcessRecord中? - 已解决
  3. ActivityThread#main的入口点中,如何获取之前的结果? - 已解决

下面为创建进程的调用序列,注意如下序列中只是创建了一个ProcessRecord的对象,对应于Linux上的进程创建我们再起文章进行分析,对于我们的Service来说,拿到ProcessRecord对象即可供我们来创建服务;

ActivityManagerService#startProcessLocked com/android/server/am/ActivityManagerService.java ActivityManagerService#startProcessLocked startProcessLocked(hostingRecord, entryPoint) 带入口点 ProcessList#startProcess 带入口类 android.app.ActivityThread handleProcessStartedLocked 记录ProcessRecord(通过PID) android.os.ZygoteProcess#startViaZygote 带入口类 android.app.ActivityThread ZygoteProcess#zygoteSendArgsAndGetResult 带入口类 android.app.ActivityThread zygote zygote创建新的进程 ActivityThread#main() 进程创建后执行入口函数 ActivityThread#attach module ProcessList#startProcessLocked() com/android/server/am/ProcessList.java ProcessList#newProcessRecordLocked com/android/server/am/ProcessList.java ProcessList#newProcessRecordLocked new ProcessRecord(ams, info, proc, uid) ActiveServices#bringUpServiceLocked com/android/server/am/ActiveServices.java 创建进程 socket IActivityManager#attachApplication module ActivityManagerService#attachApplication module ActivityManagerService#attachApplicationLocked 获取之前缓存的ProcessRecord(app) ProcessRecord#makeActive app.makeActive(thread, mProcessStats) ; thread = _thread; transact binder
  • 进程创建的执行位于AMS所在的系统进程之中;
  • (AMS进程)首先,构建一个ProcessRecord记录,并将其记录到AMS中;
  • (AMS进程)AMS通过socket通信,通知zygote来创建一个新的进程,同时指定入口点为 android.app.ActivityThread ;
  • (APP进程)新的进程启动后,执行ActivityThread中的方法,通知AMS来执行attachApplication;
  • (AMS进程)AMS中,通过PID获取之前存储的ProcessRecord,然后将ApplicationThread(代理对象)赋值给ProcessRecord的成员变量thread;
  • 支持完成了关联;

构造ProcessRecord实例

com.android.server.am.ProcessList#startProcessLocked,简化下来就两句:

  • 构造ProcessRecord对象: app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord)
  • 启动进程:startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride)
// com.android.server.am.ProcessList#newProcessRecordLocked
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
            int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
            boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs,
            Runnable crashHandler) {
        long startTime = SystemClock.uptimeMillis();
        ProcessRecord app;
        if (app == null) {
            // 构造ProcessRecord对象
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord);
            app.crashHandler = crashHandler;
            app.isolatedEntryPoint = entryPoint;
            app.isolatedEntryPointArgs = entryPointArgs;
        } else {
            // If this is a new package in the process, add the package to the list
            app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
        }
	    // 启动进程
        final boolean success =
                startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
        checkSlow(startTime, "startProcess: done starting proc!");
        return success ? app : null;
    }

启动进程

startProcessLocked: 启动了一个进程,并指定了入口点为 android.app.ActivityThread,也就是进程启动后将会执行 android.app.ActivityThread的main方法。

// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
// com.android.server.am.ProcessList#startProcessLocked(com.android.server.am.ProcessRecord, com.android.server.am.HostingRecord, int, boolean, boolean, boolean, java.lang.String)
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
            int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
            boolean mountExtStorageFull, String abiOverride) {
        if (app.pendingStart) {
            return true;
        }
        long startTime = SystemClock.uptimeMillis();
        try {
            try {
                final int userId = UserHandle.getUserId(app.uid);
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }

            int uid = app.uid;
            int[] gids = null;
            // ... 
            
            app.mountMode = mountExternal;
            app.gids = gids;
            app.setRequiredAbi(requiredAbi);
            app.instructionSet = instructionSet;

            final String seInfo = app.info.seInfo
                    + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            // 指定入口点为ActivityThread,启动进程
            final String entryPoint = "android.app.ActivityThread";
            return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
                    runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
                    instructionSet, invokeWith, startTime);
        } catch (RuntimeException e) {
            return false;
        }
    }


boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
            int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
        app.pendingStart = true;
        app.killedByAm = false;
        app.removed = false;
        app.killed = false;
        final long startSeq = app.startSeq = ++mProcStartSeqCounter;
        app.setStartParams(uid, hostingRecord, seInfo, startTime);
        app.setUsingWrapper(invokeWith != null
                || Zygote.getWrapProperty(app.processName) != null);
        mPendingStarts.put(startSeq, app);

        if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
            return true;
        } else {
            try {
                // 启动进程,并传入entrypoint
                final Process.ProcessStartResult startResult = startProcess(hostingRecord,
                        entryPoint, app,
                        uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
                        requiredAbi, instructionSet, invokeWith, startTime);
                // 做启动后的操作
                handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                        startSeq, false);
            } catch (RuntimeException e) {
                
            }
            return app.pid > 0;
        }
    }

这里我们省略其他更加底层的步骤的分析,我们只需要知道到了这里之后,会启动一个进程,进程启动后会执行 android.app.ActivityThread#main 方法;

记录进程记录到AMS

ProcessList#handleProcessStartedLocked(com.android.server.am.ProcessRecord, int, boolean, long, boolean)

这个地方有个关键的代码将之前创建的进程记录存储到了AMS的进程记录表中。

// com.android.server.am.ProcessList#handleProcessStartedLocked(com.android.server.am.ProcessRecord, int, boolean, long, boolean)
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
ActivityManagerService mService = null;
boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
            long expectedStartSeq, boolean procAttached) {
    // 将ProcessRecord 存储到AMS中
    mService.addPidLocked(app);
}
  
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
void addPidLocked(ProcessRecord app) {
    synchronized (mPidsSelfLocked) {
        // 将进程记录添加到一个记录表中
        mPidsSelfLocked.doAddInternal(app);
    }
    synchronized (sActiveProcessInfoSelfLocked) {
        if (app.processInfo != null) {
            sActiveProcessInfoSelfLocked.put(app.pid, app.processInfo);
        } else {
            sActiveProcessInfoSelfLocked.remove(app.pid);
        }
    }
    mAtmInternal.onProcessMapped(app.pid, app.getWindowProcessController());
}
// 完整代码
// com.android.server.am.ProcessList#handleProcessStartedLocked(com.android.server.am.ProcessRecord, int, boolean, long, boolean)
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
            long expectedStartSeq, boolean procAttached) {
        mPendingStarts.remove(expectedStartSeq);
        final String reason = isProcStartValidLocked(app, expectedStartSeq);
        if (reason != null) {
            Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" +
                    pid
                    + ", " + reason);
            app.pendingStart = false;
            killProcessQuiet(pid);
            Process.killProcessGroup(app.uid, app.pid);
            noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
                    ApplicationExitInfo.SUBREASON_INVALID_START, reason);
            return false;
        }
        mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
        checkSlow(app.startTime, "startProcess: done updating battery stats");

        EventLog.writeEvent(EventLogTags.AM_PROC_START,
                UserHandle.getUserId(app.startUid), pid, app.startUid,
                app.processName, app.hostingRecord.getType(),
                app.hostingRecord.getName() != null ? app.hostingRecord.getName() : "");

        try {
            AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
                    app.seInfo, app.info.sourceDir, pid);
        } catch (RemoteException ex) {
            // Ignore
        }

        Watchdog.getInstance().processStarted(app.processName, pid);

        checkSlow(app.startTime, "startProcess: building log message");
        StringBuilder buf = mStringBuilder;
        buf.setLength(0);
        buf.append("Start proc ");
        buf.append(pid);
        buf.append(':');
        buf.append(app.processName);
        buf.append('/');
        UserHandle.formatUid(buf, app.startUid);
        if (app.isolatedEntryPoint != null) {
            buf.append(" [");
            buf.append(app.isolatedEntryPoint);
            buf.append("]");
        }
        buf.append(" for ");
        buf.append(app.hostingRecord.getType());
        if (app.hostingRecord.getName() != null) {
            buf.append(" ");
            buf.append(app.hostingRecord.getName());
        }
        mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid);
        app.setPid(pid);
        app.setUsingWrapper(usingWrapper);
        app.pendingStart = false;
        checkSlow(app.startTime, "startProcess: starting to update pids map");
        ProcessRecord oldApp;
        synchronized (mService.mPidsSelfLocked) {
            oldApp = mService.mPidsSelfLocked.get(pid);
        }
        // If there is already an app occupying that pid that hasn't been cleaned up
        if (oldApp != null && !app.isolated) {
            // Clean up anything relating to this pid first
            Slog.wtf(TAG, "handleProcessStartedLocked process:" + app.processName
                    + " startSeq:" + app.startSeq
                    + " pid:" + pid
                    + " belongs to another existing app:" + oldApp.processName
                    + " startSeq:" + oldApp.startSeq);
            mService.cleanUpApplicationRecordLocked(oldApp, false, false, -1,
                    true /*replacingPid*/);
        }
    // 注意这里 
        mService.addPidLocked(app);
        synchronized (mService.mPidsSelfLocked) {
            if (!procAttached) {
                Message msg = mService.mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                msg.obj = app;
                mService.mHandler.sendMessageDelayed(msg, usingWrapper
                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
            }
        }
        checkSlow(app.startTime, "startProcess: done updating pids map");
        return true;
    }

写入thread值到ProcessRecord

从上面的流程中,我们发现构造出来的ProcessRecord的thread(ApplicationThread)成员变量还是没有被赋值,那么这个thread何时被赋值呢?

查找ProcessRecordthread赋值的入口:

  1. 通过查找thread成员的赋值写入方法,可以确定起始点是,com.android.server.am.ProcessRecord#makeActive ,接下来查看调用这个方法的列表:

  2. image-20210411172323572
  3. 这里我们显然选择 com.android.server.am.ActivityManagerService#attachApplicationLocked

  4. android.app.ActivityThread#attach

  5. 这里我们遇到两个选择:

    image-20210411172524831
  6. 显然,应该选择第二个:android.app.ActivityThread#main

  7. 这里我们却无法直接通过IDEA的调用层次功能找到任何调用方法,说明可能是通过反射来调用的,所以直接通过全局字符串搜索android.app.ActivityThread,可以找到在 ProcessList.startProcessLocked 中调用的。

通过上面的分析,这里我们从ActivityThread的main函数开始。

ActivityThread#main
    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // Install selective syscall interception
        AndroidOs.install();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        // Call per-process mainline module initialization.
        initializeMainlineModules();

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        // 直接构造一个ActivityThread对象
        ActivityThread thread = new ActivityThread();
        // 执行attach方法
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
ActivityThread#attach
 private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            // 将当前ApplicationThread的Binder对象保存为一个静态成员
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            // 获取AMS
            final IActivityManager mgr = ActivityManager.getService();
            try {
                // 通知AMS来 attachApplication
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } else {
            
        }
}
ActivityManagerService#attachApplication & attachApplicationLocked
    @Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        if (thread == null) {
            throw new SecurityException("Invalid application interface");
        }
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

上面的方法只是调用了 attachApplicationLocked:

有个关键的步骤是,从 AMS的进程记录表中根据PID取出一个 ProcessRecord: app = mPidsSelfLocked.get(pid)

private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
        // Find the application record that is being attached...  either via
        // the pid if we are running in multiple processes, or just pull the
        // next app record if we are emulating process with anonymous threads.
        ProcessRecord app;
        long startTime = SystemClock.uptimeMillis();
        long bindApplicationTimeMillis;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                // 从进程记录中获取
                app = mPidsSelfLocked.get(pid);
            }
        }
        // Make app active after binding application or client may be running requests (e.g
        // starting activities) before it is ready.
        // 关联thread到app(ProcessRecord)
        app.makeActive(thread, mProcessStats);
        return true;
    }

经过上面的步骤,即完成了ProcessRecord到进程的ApplicationThread的关联。

启动服务

从AMS中调用ApplicationThread的方法来在Service自己应该所属的进程中创建Service对象的实例。

ActivityThread#main() 进程创建后执行入口函数 独立进程的Service 启动进程 ActivityThread#attach - IApplicationThread#scheduleCreateService android/app/IApplicationThread.java transact binder transact binder ApplicationThread#scheduleCreateService android/app/ActivityThread.java ActivityThread#handleCreateService android/app/ActivityThread.java IActivityManager#serviceDoneExecuting android/app/ActivityThread.java ActivityManagerService#serviceDoneExecuting android/app/ActivityThread.java ActiveServices#bringUpServiceLocked com/android/server/am/ActiveServices.java ActiveServices#realStartServiceLocked com/android/server/am/ActiveServices.java 启动服务 IActivityManager#attachApplication - ActivityManagerService#attachApplication - ActivityManagerService#attachApplicationLocked 获取之前存储的 mPendingServices - 待启动的服务列表 transact binder

ActiveServices#bringUpServiceLocked

// com.android.server.am.ActiveServices#bringUpServiceLocked
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        // 已经存在进程记录,并且进程记录中的IApplicationThread已经存在,则不创建服务,仅发送参数
        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;
        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;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } else {
            // 独立进程则先尝试使用之前保存的
            app = r.isolatedProc;
        }

        // 之前没有启动对应的进程,则开始创建,启动了,则无需进行赋值操作,因为ServiceRecord中已经有了
        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, 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) {
                // 独立进程,缓存进程信息到传入的ServiceRecord参数中,以便后续直接使用
                r.isolatedProc = app;
            }
        }
        // 将服务记录加入的mPendingServices中,由于非独立进程创建后已经直接返回,所以这里适用于独立进程的
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
	    // 创建成功或者之前已经又了缓存,则返回null
        return null;
    }

独立进程何时启动服务?

  • 一般来说,封装较好的代码会保证入口统一,如果非独立进程情况下服务的启动使用的是 realStartServiceLocked 方法来启动服务,那么独立进程情况下,服务的启动也应该使用此方法,所以我们查看 realStartServiceLocked 方法的调用层次,如下:

    图片版本:

    image-20210411112439961

    详细调用序列:

    • ActiveServices.attachApplicationLocked(ProcessRecord, String) (com.android.server.am)
      • ActivityManagerService.attachApplicationLocked(IApplicationThread, int, int, long) (com.android.server.am)
        • ActivityManagerService.attachApplication(IApplicationThread, long) (com.android.server.am)
    • ActiveServices.bringUpServiceLocked(ServiceRecord, int, boolean, boolean, boolean) (com.android.server.am)
      • ActiveServices.startServiceInnerLocked(ServiceMap, Intent, ServiceRecord, boolean, boolean) (com.android.server.am)
      • ActiveServices.bindServiceLocked(IApplicationThread, IBinder, Intent, String, IServiceConnection, int, String, ...) (com.android.server.am)
      • ActiveServices.performServiceRestartLocked(ServiceRecord) (com.android.server.am)

    也就是调用了 ActiveServices.attachApplicationLocked ,最终是通过AMS的ActivityManagerService.attachApplication来触发的;也就是只要找到mAm.startProcessLockedActivityManagerService.attachApplication的调用序列即可证明此猜想;

    我们可以找到如下调用序列,即最终实际上是从ActivityThread的main函数进入的,所以做出以下猜想:进程启动后,创建ActivityThread时,如果有需要创建的服务,就启动服务;

    image-20210411114715216

    我们再看attachApplicationLocked 的逻辑,可以发现,会检查mPendingServices中是否有待启动的服务,然后逐一处理,如果有需要启动的服务,则会调用realStartServiceLocked(sr, proc, sr.createdFromFg)来启动服务。

    // com.android.server.am.ActiveServices#attachApplicationLocked
    // frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
    boolean attachApplicationLocked(ProcessRecord proc, String processName)
                throws RemoteException {
            boolean didSomething = false;
            // Collect any services that are waiting for this process to come up.
            if (mPendingServices.size() > 0) {
                ServiceRecord sr = null;
                try {
                    for (int i=0; i<mPendingServices.size(); i++) {
                        sr = mPendingServices.get(i);
                        // 排除非独立Service
                        if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                                || !processName.equals(sr.processName))) {
                            continue;
                        }
    
                        mPendingServices.remove(i);
                        i--;
                        proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
                                mAm.mProcessStats);
                        // 启动服务
                        realStartServiceLocked(sr, proc, sr.createdFromFg);
                    }
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception in new application when starting service "
                            + sr.shortInstanceName, e);
                    throw e;
                }
            }
    }
    

ActivityThread#handleCreateService

这里我们省略bringUpServiceLocked方法及下方的几个中间步骤,直接查看android.app.ActivityThread#handleCreateService方法:

  1. 通过ClassLoader加载并实例化了对应的Service对象;
  2. 将Service存储到ActivityThread中的一个ArrayMap中;
// android/app/ActivityThread.java
// android.app.ActivityThread#handleCreateService

final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            // 创建对应的Service实例
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
            // Service resources must be initialized with the same loaders as the application
            // context.
            context.getResources().addLoaders(
                    app.getResources().getLoaders().toArray(new ResourcesLoader[0]));

            context.setOuterContext(service);
            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();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

绑定服务

ActivityManagerService.bindIsolatedService com/android/server/am/ActivityManagerService.java ActiveServices.bindServiceLocked com/android/server/am/ActiveServices.java IApplicationThread.scheduleBindService android/app/IApplicationThread.java Binder.transact binder Binder. transact binder ApplicationThread.scheduleBindService frameworks/base/core/java/android/app/ActivityThread.java ActivityThread#handleBindService frameworks/base/core/java/android/app/ActivityThread.java IBinder = Service.onBinder() 自定义的Service实现类 IActivityManager#publishService android/app/IActivityManager.java ActivityManagerService#publishService android/app/IActivityManager.java ActiveServices#publishServiceLocked com/android/server/am/ActiveServices.java IServiceConnection#connected - ActiveServices.requestServiceBindingLocked com/android/server/am/ActiveServices.java

我们的问题是:

  1. 绑定服务时,传入的ServiceConnection对象,如何被调用来通知?
  2. 还做了些什么?

连接对象去哪里了?

查看ContextImpl.bindServiceCommon方法可以看到,传入了参数 ServiceConnection conn,然后方法中这个conn放入到了一个 ServiceDispatcher 中.

  • IServiceConnection 包含两个接口:
    • connected(): 连接到服务
    • asBinder(): 服务转Binder
  • 这里会将我们自行编写的ServiceConnection对象构造出一个ServiceDispatcher对象,然后将ServiceDispatcher提供一个IServiceconnection接口(ServiceDispatcher$InnerConnection类),用于提供服务;
  • 这个ServiceDispatcher$InnerConnection类的connect方法会调用sd的connect方法,最终会调用我们提供的ServiceConnection的回调方法:mConnection.onServiceConnected(name, service)

也就是说,使用sd.connect()就可以触发我们的连接对象的onServiceConnected回调方法;

final @NonNull LoadedApk mPackageInfo;

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
	    // 这个IServiceConnection 实际上就是持有ServiceDispatcher的弱引用对象,然后将ServiceDispatcher的少量方法暴露出去
        IServiceConnection sd;
        if (mPackageInfo != null) {
            if (executor != null) {
                // mPackageInfo 是一个 LoadedApk 对象
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
            } else {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            }
        } else {
            
        }
    	int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
	            // 调用AMS的服务式这里传入了sd
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
        //... 
    }

// com.android.server.am.ActiveServices#bindServiceLocked
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent,
                    callerApp.uid, callerApp.processName, callingPackage);
            // 提供 IBinder 
            IBinder binder = connection.asBinder();
            s.addConnection(binder, c);
            b.connections.add(c);

ServiceDispatcher类位于 android.app.LoadedApk.ServiceDispatcher

// frameworks/base/core/java/android/app/LoadedApk.java
	public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Executor executor, int flags) {
        return getServiceDispatcherCommon(c, context, null, executor, flags);
    }

    private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
            Context context, Handler handler, Executor executor, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                sd = map.get(c);
            }
            if (sd == null) {
                if (executor != null) {
                    sd = new ServiceDispatcher(c, context, executor, flags);
                } else {
                    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, executor);
            }
            return sd.getIServiceConnection();
        }
    }


static final class ServiceDispatcher {
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    @UnsupportedAppUsage
    private final ServiceConnection mConnection;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    private final Context mContext;
    private final Handler mActivityThread;
    private final Executor mActivityExecutor;
    private final ServiceConnectionLeaked mLocation;
    private final int mFlags;

    private static class InnerConnection extends IServiceConnection.Stub {
        @UnsupportedAppUsage
        final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

        InnerConnection(LoadedApk.ServiceDispatcher sd) {
            mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
        }

        public void connected(ComponentName name, IBinder service, boolean dead)
                throws RemoteException {
            LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            if (sd != null) {
                sd.connected(name, service, dead);
            }
        }
    }

    @UnsupportedAppUsage
    ServiceDispatcher(ServiceConnection conn,
                      Context context, Handler activityThread, int flags) {
        mIServiceConnection = new InnerConnection(this);
        mConnection = conn;
        mContext = context;
        mActivityThread = activityThread;
        mActivityExecutor = null;
        mLocation = new ServiceConnectionLeaked(null);
        mLocation.fillInStackTrace();
        mFlags = flags;
    }

    ServiceConnection getServiceConnection() {
        return mConnection;
    }

    // SD中提供了connected方法
    public void connected(ComponentName name, IBinder service, boolean dead) {
        if (mActivityExecutor != null) {
            mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
        } else if (mActivityThread != null) {
            mActivityThread.post(new RunConnection(name, service, 0, dead));
        } else {
            doConnected(name, service, dead);
        }
    }

    public void doConnected(ComponentName name, IBinder service, boolean dead) {
        ServiceDispatcher.ConnectionInfo old;
        ServiceDispatcher.ConnectionInfo info;

        synchronized (this) {
            if (mForgotten) {
                // We unbound before receiving the connection; ignore
                // any connection received.
                return;
            }
            old = mActiveConnections.get(name);
            if (old != null && old.binder == service) {
                // Huh, already have this one.  Oh well!
                return;
            }

            if (service != null) {
                // A new service is being connected... set it all up.
                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) {
                    // This service was dead before we got it...  just
                    // don't do anything with it.
                    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 viable service, it is now connected.
        if (service != null) {
            mConnection.onServiceConnected(name, service);
        } else {
            // The binding machinery worked, but the remote returned null from onBind().
            mConnection.onNullBinding(name);
        }
    }

}

IServiceConnection说明

服务绑定时,IServiceConnection的用途?如何实现在APP的Activity进程中调用ServiceConnection的onServiceConnected方法?

  • IServiceConnect的服务端位于APP进程中,在ContextImpl的binderServiceCommon方法中初始化,也就是LoadApk类中的ServiceDispatcher类。
  • 传递给AMS的实际上是一个Binder的远程代理对象;
// android.app.IActivityManager.Stub#TRANSACTION_bindService
// android/app/IActivityManager.java
case TRANSACTION_bindService:
{
          data.enforceInterface(descriptor);
          android.app.IApplicationThread _arg0;
          _arg0 = android.app.IApplicationThread.Stub.asInterface(data.readStrongBinder());
          android.os.IBinder _arg1;
          _arg1 = data.readStrongBinder();
          android.content.Intent _arg2;
          if ((0!=data.readInt())) {
            _arg2 = android.content.Intent.CREATOR.createFromParcel(data);
          }
          else {
            _arg2 = null;
          }
          java.lang.String _arg3;
          _arg3 = data.readString();
          android.app.IServiceConnection _arg4;
    // 这里可以看到,是在这个地方见IServiceConnection的服务端对象转换成客户端代理对象的
          _arg4 = android.app.IServiceConnection.Stub.asInterface(data.readStrongBinder());
          int _arg5;
          _arg5 = data.readInt();
          java.lang.String _arg6;
          _arg6 = data.readString();
          int _arg7;
          _arg7 = data.readInt();
          int _result = this.bindService(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7);
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
}
    

asInterface 中: new android.app.IServiceConnection.Stub.Proxy(obj) 即是将Stub转换为Proxy对象;

  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements android.app.IServiceConnection
  {
    private static final java.lang.String DESCRIPTOR = "android.app.IServiceConnection";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an android.app.IServiceConnection interface,
     * generating a proxy if needed.
     */
    public static android.app.IServiceConnection asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof android.app.IServiceConnection))) {
        return ((android.app.IServiceConnection)iin);
      }
      return new android.app.IServiceConnection.Stub.Proxy(obj);
    }
  }

也就是说,ActivityManagerService.bindService方法中的IServiceConnection参数实际上是一个Proxy对象;

// 这里的Connection是一个代理对象
public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags,
            String callingPackage, int userId) throws TransactionTooLargeException {
        return bindIsolatedService(caller, token, service, resolvedType, connection, flags,
                null, callingPackage, userId);
}

ActivityThread#handleBindService

实际上就做了两件事情

// android.app.ActivityThread#handleBindService
// frameworks/base/core/java/android/app/ActivityThread.java
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接口获取IBinder对象
                        IBinder binder = s.onBind(data.intent);
                        // 通知AMS来publicService
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
            }
        }
    }

ActivityManagerService#publishService

// com.android.server.am.ActivityManagerService#publishService
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            // com.android.server.am.ActiveServices#publishServiceLocked
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

ActiveServices#publishServiceLocked

下面我们可以看到,在publishServiceLocked方法中,取出了一个连接记录列表,然后循环的调用了其中的IServiceConnection的connected方法,也就是会调用到我们自行定义的ServiceConnnection对象的connected方法。

不过我们有个问题,就是这个ConnectionRecord对象是何时构造的?

// com.android.server.am.ConnectionRecord
// frameworks/base/services/core/java/com/android/server/am/ConnectionRecord.java
final class ConnectionRecord {
    final AppBindRecord binding;    // The application/service binding.
    final ActivityServiceConnectionsHolder<ConnectionRecord> activity;  // If non-null, the owning activity.
    final IServiceConnection conn;  // The client connection.
}

// com.android.server.am.ActiveServices#publishServiceLocked
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            // 如果服务记录为null,就什么都不做
            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;
                    // 取出连接记录ConnectionRecord
                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
                    for (int conni = connections.size() - 1; conni >= 0; conni--) {
                        ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                        for (int i = 0; i < clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            try {
                                // 调用IServiceConnection的connected方法
                                c.conn.connected(r.name, service, false);
                            } catch (Exception e) {
                               
                            }
                        }
                    }
                }
                serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
            }
        } finally {
        }
    }

构造 ConnectionRecord - bindServiceLocked

实际上这个构建ConnectRecord的过程位于bindServiceLocked方法中。

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                          String resolvedType, final IServiceConnection connection, int flags,
                          String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();

        ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
        if (token != null) {
            activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
            if (activity == null) {
                Slog.w(TAG, "Binding with unknown activity: " + token);
                return 0;
            }
        }
        ServiceLookupResult res = retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                        callingPid, callingUid, userId, true,
                        callerFg, isBindExternal, allowInstant);
        ServiceRecord s = res.record;
        try {
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            // 构造连接记录对象
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent,
                    callerApp.uid, callerApp.processName, callingPackage);

            IBinder binder = connection.asBinder();
            // 添加到ServiceRecord对象中
            s.addConnection(binder, c);
            b.connections.add(c);
            if (activity != null) {
                activity.addConnection(c);
            }
            b.client.connections.add(c);
            c.startAssociationIfNeeded();
        } finally {
        }
        return 1;
    }

部分方法的源码

ContextImpl.bindService

  • bindService : (frameworks/base/core/java/android/app/ContextImpl.java)

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

ContextImpl.bindServiceCommon

  • bindServiceCommon: (frameworks/base/core/java/android/app/ContextImpl.java)

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
                String instanceName, Handler handler, Executor executor, UserHandle user) {
            // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
            IServiceConnection sd;
            if (conn == null) {
                throw new IllegalArgumentException("connection is null");
            }
            if (handler != null && executor != null) {
                throw new IllegalArgumentException("Handler and Executor both supplied");
            }
            if (mPackageInfo != null) {
                if (executor != null) {
                    sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
                } else {
                    sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
                }
            } else {
                throw new RuntimeException("Not supported in system context");
            }
            validateServiceIntent(service);
            try {
                // WindowContext构造函数中的 WindowTokenClient
                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);
                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();
            }
        }
    

ActivityManagerService.bindIsolatedService

从这里开始,实际上位于AMS的Server端了,即我们的Activity所在的进程发送了一个启动服务的IPC请求给AMS(sysmte_server进程中)。

  • ActivityManagerService.java : (frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java)

    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) {
                // 调用Binder接口
                return mServices.bindServiceLocked(caller, token, service,
                        resolvedType, connection, flags, instanceName, callingPackage, userId);
            }
        }
    
image-20210409144356311

ActiveServices.bindServiceLocked

  • ActiveServices.bindServiceLocked: (frameworks/base/services/core/java/com/android/server/am/ActiveServices.java)

  • 这个方法有点长,我们截取重要部分

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
    // 获取调用方的权限
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        if (callerApp == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                    + " (pid=" + callingPid
                    + ") when binding service " + service);
        }

        ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
        if (token != null) {
            activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
            if (activity == null) {
                Slog.w(TAG, "Binding with unknown activity: " + token);
                return 0;
            }
        }

        int clientLabel = 0;
        PendingIntent clientIntent = null;
        final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;
       

        final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
        final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
        final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;

        ServiceLookupResult res =
            retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true,
                    callerFg, isBindExternal, allowInstant);
        if (res == null) {
            return 0;
        }
        if (res.record == null) {
            return -1;
        }
        ServiceRecord s = res.record;

        try {
            if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: "
                        + s);
            }

            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (!s.hasAutoCreateConnections()) {
                    // This is the first binding, let the tracker know.
                    ServiceState stracker = s.getTracker();
                    if (stracker != null) {
                        stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
                                s.lastActivity);
                    }
                }
            }

            if ((flags & Context.BIND_RESTRICT_ASSOCIATIONS) != 0) {
                mAm.requireAllowedAssociationsLocked(s.appInfo.packageName);
            }

            mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
                    callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
                    s.instanceName, s.processName);
            // Once the apps have become associated, if one of them is caller is ephemeral
            // the target app should now be able to see the calling app
            mAm.grantImplicitAccess(callerApp.userId, service,
                    callerApp.uid, UserHandle.getAppId(s.appInfo.uid));

            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent,
                    callerApp.uid, callerApp.processName, callingPackage);

            IBinder binder = connection.asBinder();
            s.addConnection(binder, c);
            b.connections.add(c);
            if (activity != null) {
                activity.addConnection(c);
            }
            b.client.connections.add(c);
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }

            if (s.app != null && b.intent.received) {
                // Service is already running, so we can immediately
                // publish the connection.
                try {
                    c.conn.connected(s.name, b.intent.binder, false);
                } catch (Exception e) {
                    Slog.w(TAG, "Failure sending service " + s.shortInstanceName
                            + " to connection " + c.conn.asBinder()
                            + " (in " + c.binding.client.processName + ")", e);
                }
            } else if (!b.intent.requested) {
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }
        } finally {
        }
        return 1;
    }

ActiveServices.realStartServiceLocked

 /**
     * Note the name of this method should not be confused with the started services concept.
     * The "start" here means bring up the instance in the client, and this method is called
     * from bindService() as well.
     */
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        r.setProcess(app);
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
		// 创建服务
        final boolean newService = app.startService(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);

        boolean created = false;
        try {
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            // 创建服务
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app, "Died when creating service");
            throw e;
        } finally {
            // 
        }

        // 绑定服务
        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        if (newService && created) {
            app.addBoundClientUidsOfNewService(r);
        }

        // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }
        sendServiceArgsLocked(r, execInFg, true);
    }