美文网首页
AMS分析「 Service管理 」

AMS分析「 Service管理 」

作者: 泡面先生_Jack | 来源:发表于2018-09-11 15:34 被阅读0次

    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管理 」

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