AMS分析「 Service管理 」

ActivityManagerService服务负责管理Service服务,下面通过Service服务的启动流程来分析下AMS是如何管理Service服务的

Service的启动方式有两种:
1:startService
2:bindService

startService分析

我们要启动一个Service服务一般都是在Activity类中直接调用startService(Intent)来启动,而Activity类中并没有相关的方法,我们知道Activity继承自ContextWrapper,ContextWrapper类中的startService方法直接调用了ContextImpl的startService方法。

Service的可以在当前的进程中启动,也可以在新的进程中启动。在新的进程中启动的逻辑和前面分析的Activity的启动流程类似,所以此处我们仅仅分析在当前进程中启动Service的情况。

我们分析Service的启动流程首先从ContextImpl的startService方法开始分析。

1. ContextImpl.StartService

public ComponentName startService(Intent service) {
        return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess();
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), getOpPackageName(), user.getIdentifier());
            return cn;
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }

StartService调用了startServiceCommon方法来启动Service,在startServiceCommon方法中通过进程间通信请求,调用了AMS服务的startService方法。以上代码在应用进程中。通过进程间调用,下面代码逻辑进入系统服务进程中。

2. AMS.startService

public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, String callingPackage, int userId)
            throws TransactionTooLargeException {
    ……
        synchronized(this) {
        //获取调用进程的UID和PID
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
        //调用startServiceLocked来继续处理service启动的逻辑
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, callingPackage, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

这个方法处理也是比较简单,获取调用者的Uid和Pid,调用ActiveService的startServiceLocked方法来继续处理Service启动的逻辑。

3. ActiveService.startServiceLocked

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, String callingPackage, int userId)
            throws TransactionTooLargeException {
        //获取调用程序的进程信息
        if (caller != null) {
            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
            ……
        }
 
        //调用要启动的service的Intent信息,在PMS服务中查找对应的service,并将它封装在一个ServiceLookupResult对象中
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg);
        //得到要启动service的ServiceRecord信息
        ServiceRecord r = res.record;
 
        final ServiceMap smap = getServiceMap(r.userId);
    ……
        //调用startServiceInnerLocked方法继续启动service服务
        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    }

在AMS服务中,每个Service都使用一个ServiceRecord对象来描述,就像Activity一样,每个Activity都用一个ActivityRecord对象描述。然后调用retrieveServiceLocked方法来查找一个和目标Service对应的ServiceRecord,最后将这个ServiceRecord对象封装在ServiceLookupResult对象中。

最后条用startServiceInnerLocked方法来继续启动目标Service

下面在了解下retrieveServiceLocked方法的处理逻辑。

private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg) {
        ServiceRecord r = null;
        //获取当前的用户ID
        userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
                false, ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
        找到该用户下的保存Service的集合ServiceMap
        ServiceMap smap = getServiceMap(userId);
        final ComponentName comp = service.getComponent();
        //根据component信息从ServiceMap中查找
        if (comp != null) {
            r = smap.mServicesByName.get(comp);
        }
        //根据IntentFilter信息从ServiceMap中查找
        if (r == null) {
            Intent.FilterComparison filter = new Intent.FilterComparison(service);
            r = smap.mServicesByIntent.get(filter);
        }
//如果ServiceMap中没有找到目标Service的ServiceRecord信息,则从PMS中查找并创建一个ServiceRecord对象,然后保存到ServiceMap中
        if (r == null) {
            try {
                ResolveInfo rInfo =
                    AppGlobals.getPackageManager().resolveService(
                                service, resolvedType,
                                ActivityManagerService.STOCK_PM_FLAGS, userId);
                ServiceInfo sInfo =
                    rInfo != null ? rInfo.serviceInfo : null;
                    ……
                    r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                    res.setService(r);
                    smap.mServicesByName.put(name, r);
                    smap.mServicesByIntent.put(filter, r);
                }
            } catch (RemoteException ex) {
                // pm is in same process, this will never happen.
            }
        }
       ……
        return null;
    }

retrieveServiceLocked方法用来查找目标Service的ServiceRecord对象,首先从AMS服务中的ServiceMap中查找,ServiceMap中保存了AMS服务中所有激活的Service信息,如果在ServiceMap中没有找到,说明该Service还没有启动。那么就需要从PMS服务中查找目标Service的信息并创建一个ServiceRecord对象。最后把他保存在对应的ServiceMap集合中。

接着看startServiceInnerLocked方法,该方法中处理逻辑直接较简单,直接调用了bringUpServiceLocked方法来处理。

4. ActiveService. bringUpServiceLocked

private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting) throws TransactionTooLargeException {
 
           final String procName = r.processName;
        ProcessRecord app;
 
      //判断目标Service所在的进程是否已经存在,如果已经存在则直接调用目标进程启动Service
       app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } 
            ……
            }
        //如果目标进程不存在,则需要先创建目标进程,然后再创建Service
        if (app == null) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)) == null) {
               ……
}

这个方法首先根据目标Serivce的进程信息,来查询对应的进程是否存在,如果对应的目标进程已经存在,则通过通知目标进程来启动Service,如果目标进程还没有创建,则电泳AMS服务的startProcessLocked方法启动一个目标进程,然后在启动service。启动目标进程的方法和Activity中启动目标进程的方法类似,此处不再分析。

我们分析在同一个进程中启动Service的逻辑,目标进程肯定已经存在了,不需要新创建进程,所以直接调用realStartServiceLocked方法来启动service服务。

5. ActiveService.realStartServiceLocked

 private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        ……
        //将即将要启动ServiceRecord和一个进程关联起来
        r.app = app;
 
       boolean created = false;
        try {
            ……
           //通过进程间通信请求,调用目标进程的scheduleCreateService方法创建一个Service服务
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } 
    ……
}

将即将要启动的ServiceRecord r的成员变量设置为ProcessRecord对象app,表示这个ServiceRecord对象锁描述的Service组件是在app所描述的进程中启动运行的。

在Activity的启动过程中描述过:ProcessRecord的成员变量thread是一个ApplicationThreadProxy的binder代理对象,它指向了应用程序进程中一个Applicationthread的binder服务端对象。因此可以通过thread进行进程间通信请求,调用binder服务端ApplicationThread的scheduleCreateService来创建Service。

同样,ApplicationThread接收到请求后,最终发送消息CREATE_SERVICE由Hander来处理,Handler的handleMessage又调用了ActivityThread的handleCreateService方法来处理。

6. ActivityThread.handleCreateService

private void handleCreateService(CreateServiceData data) {
        //获取当前应用程序的LoadedApk对象
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
        //使用当前应用程序的类加载器加载目标service,并创建它的一个对象
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
           ……
        }
 
        try {
            //创建并初始化Context对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
        //创建一个Application对象,用来描述service所在的应用程序信息
            Application app = packageInfo.makeApplication(false, mInstrumentation);
        //使用上面的信息初始化刚创建的service对象
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            //调用service的onCreate方法
            service.onCreate();
        //最后将servcie保存在ActivityThread的mServices变量中。
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                // nothing to do.
            }
        } ……
    }

第一步:在该方法中首先获得一个LoadedAPK对象,在之前我们曾经分析过,LoadedApk主要用来描述进程中所加载的一个应用程序,里面保存了应用程序的资源路径等信息。
第二步:使用LoadedApk对象中保存的ClassLoader来加载目标Service类到内存中,并创建一个目标Service的对象。
第三步,创建ContextImpl对象,并初始化,用来当做Service对象的上下文信息,Service对象就可以通过它来访问程序的资源和方法。
第四步,创建一个Application对象,用来描述Service所在应用程序的信息。
第五步,用上面创建的信息,context,Application等信息来初始化刚创建的service对象。
第六步,service对象初始化完成后就调用了它的onCreate方法。这样Service服务就基本上启动起来了

你可能感兴趣的:(AMS分析「 Service管理 」)