解析Service的启动过程

Service 的启动过程   

       Service 的启动过程和根 Activity 启动过程有部分相似的知识点,另外 Service 启动过 程涉及上下文 Context 的知识点,这里只关注流程而不会详细介绍 Context   Service 的启动过程将分为两个部分来进行讲解,分别是 Contextimpl到Activity ManageService 调用 过程和 ActivityThread 启动 Service。本文基于Android8.1.0系统分析Service的启动过程。
 

1. Contextlmpl到AMS 的调用过程

       要启动 Service ,我们会调用 startService 方法 ,它在 Context Wrapper 中实现,代码如下所示:
 
frameworks/base/core/java/android/content/ContextWrapper.java
 
public class ContextWrapper extends Context {
    Context mBase;
    
    ...

    @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }

    ...

}
       在startService方法中会 调用 mBase的 startService 方法 Context 类型的  mBase 对 象具 体指的是什么呢?在“解析Activity的启动过程 中我们分析过, ActivityThread 启动 Activity 调用如下代码创建 Activity 的上下文环境:
 
frameworks/base/core/java/android/app/ActivityThread.java

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        ContextImpl appContext = createBaseContextForActivity(r); // ... 1
        Activity activity = null;

        try {
           
            if (activity != null) {
                ...
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
                ...
            }
            ... 
        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }

       在注释1处创建上下文对象appContext,并传入Activity的attach方法中,将Activity与上下文对象appContext关联起来,这个上下文对象appContext的具体类型是什么?接下来我们继续分析createBaseContextForActivity方法,代码如下所示:

frameworks/base/core/java/android/app/ActivityThread.java

    private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {

        ...

        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

        ...         

        return appContext;
    }

       上下文对象appContext的具体类型就是ContextImpl,在Activity的attach方法中将ContextImpl赋值给ContextWrapper的成员变量mBase,因此,mBast具体指向就是ContextImpl。接下来分析ContextImpl的startService方法,代码如下所示:

frameworks/base/core/java/android/app/Contextlmpl.java
 
    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }

    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier()); // ... 1
            ...

            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
       在startService 方法 中会返回 startServ iceCommon 方法,在 startServiceCommon 方法中 会在注释1处调用 AMS 的代理I Activity Manager的 startService 方法,最终调用的是 AMS 的startService 方法,这一过程在 解析Activity的启动过程 中我们也分析过,不懂的同学可以看看Activity的启动过程,这里就不再做说明了。
 

2. ActivityThread 启动 Service

       接着我们来分析 AMS 的  startService 方法 ,代码如下所示:
 
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
 
    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        ...

        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId); // ... 1
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }
       在注释1 处调用 mServices 的  startServiceLocked 方法 mServices 的类型是 ActiveServices, ActiveServices 的startServiceLocked 方法代码如下所示
 
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
 
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {

        ...

        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false); // ... 1
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        ServiceRecord r = res.record; // ... 2 

        ...

        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

       在注释1处的 retrieveServiceLocked 方法会查找否有与参数 service 对应的 ServiceRecord ,如果没有找到,就会调用 PackageManagerService 去获取参数 service 对应的 Service 信息,并封装到 ServiceRecord 中,最后将 ServiceRecord 封装为 ServiceLookupResult 返回。其中 ServiceRecord 用于描述一个 Service ,和 ActivityRecord 类似。在注释2处通过注释1处返回的 ServiceLookupResult 得到参数 service 对应的 ServiceRecord ,并传入到注释3处的 startServicelnnerLocked 方法中。代码如下所示:

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {

        ...

        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }

        ...

        return r.name;
    }
       在startServiceInnerLocked方法中又调用了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 {

        // 获取Service想要在哪个进程中运行
        final String procName = r.processName; // ... 1

        String hostingType = "service";
        ProcessRecord app;

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); // ... 2
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);

            // 如果运行Service的应用程序进程存在
            if (app != null && app.thread != null) { // ... 3
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    // 启动Service
                    realStartServiceLocked(r, app, execInFg); // ... 4
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } else {
            // If this service runs in an isolated process, then each time
            // we call startProcessLocked() we will get a new isolated
            // process, starting another process if we are currently waiting
            // for a previous process to come up.  To deal with this, we store
            // in the service any current isolated process it is running in or
            // waiting to have come up.
            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingType = "webview_service";
            }
        }

        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.

        // 如果用来运行Service的应用程序进程不存在
        if (app == null && !permissionsReviewRequired) { // ... 5
  
            // 创建应用程序进程
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) { // ... 6
                String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
                        + r.intent.getIntent() + ": process is bad";
                Slog.w(TAG, msg);
                bringDownServiceLocked(r);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }

        ...

        return null;
    }
       在注释1 处得到 ServiceRecord 的  processName 值并赋 procName, procName用来描述 Service 要在 哪个 进程 中运 行,默 是当 前进程,  我们也可以在  AndroidManif es 文件中设 android:process 属 性来新开 启一 个进程运行 Service  。在注释2 处将 procName 和 Service 的uid 传入到 AMS的 getProcessRecordLocked 方法   ,查 询是否存 在一个与  Service 对应的Process Record 类型 的对象 a pp,  ProcessRecord 主要用来 描述运行的应用 程序 进程的信息。  注释5 处判断 Service  对应的  app 为  null 则 说明用 来运行  Service 序进程不存在 ,则调 用注释6 处的 AMS 的  startProcessLock 方法来创建 对应的应用 程序 进程,关于创建应用 程序 进程 请查看" Android系统中应用程序进程的启动过程 ", 这 里只讨论 没有设置 android: proce ss 属性,即应用程序进程存在的情况 。 注释3 处判断如果用 来运行  Service 的应用 程序进程 存在,则调 用注释4 处的 realStartServiceLocked 方法 来启动 Service,realStartServiceLocked方法代码如下所示:
 

 frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

  private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        
        ...

        try {
           
            ...
    
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
             ...
        }

        ...

    }
       在realStartServiceLocked 方法中 调用了 app.thread 的  scheduleCreateService 方法 。其中  app.thread是 IApplicationThread 类型的,它的实现是 Activi tyThread 的内部类 Application Thread 。 Application Thread 的scheduleCreateService 方法如下所示:
 
frameworks/base/core/java/android/app/ActivityThread.java
        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }
        scheduleCreateService 方法将启动 Service 的参数封装成 CreateServiceData , sendMessage 方法向H 类发送类型为 CREATE_ SERVICE 的消息,并将 CreateServiceData  传递过去,这个过程和 Ac ti vi tyThread 启动 Activity 的过程是类似的。 sendMessage 方法 有多个重载方法,最终调用的 sendMessage 方法代码 如下所示:
 
frameworks/base/core/java/android/app/ActivityThread.java
 
    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }
       这里 mH 指的是 H ,它是 ActivityThread 的内部类并继承自 Handler ,是应用程序进程中主线程的消息管理类。 我们接 着查看 H 的  handleMessage 方法,代码如下所示:
 
frameworks/base/core/java/android/app/ActivityThread.java

    private class H extends Handler {
        
        ...
       
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {

                ...

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

                ...
              
            }
            
            ...
        }
    }

       handleMessage 方法根据消息类型为 CREA E_SERVICE,会调用 handleCreateService 方法,代码如下所示:

frameworks/base/core/java/android/app/ActivityThread.java


    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();

        // 获取要启动Service的应用程序的LoadedApk
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo); // ... 1
        Service service = null;
        try {
            // 获取类加载器
            java.lang.ClassLoader cl = packageInfo.getClassLoader(); // ... 2
            // 创建Service实例
            service = (Service) cl.loadClass(data.info.name).newInstance(); // ... 3
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            // 创建Service的上下文环境ContextImpl对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo); // ... 4
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);

            // 初始化Service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService()); // ... 5
            service.onCreate(); // ... 6
            mServices.put(data.token, service); // ... 7
            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);
            }
        }
    }
       
       在注释1处获取要启动 Service 的应用程序的 LoadedApk, LoadedApk是一个 APK 文件的描述类。在注释2处通过调 LoadedApk的 getClassLoader 方法 来获取类加载器。接 着在注释3处根据 CreateServiceData  对象中存储的 Service 信息,创建 Service 实例。在注释4处创建 Serv ice 的上下 文环境 Contextlmpl 对象。在注释5 处通过 Service的 attach方法 来初始化Service 。在注释6 处调用 Service 的  on Create 方法 ,这样 Service 就启动了。在注释7 处将启动的 Service 加入到 ActivityThread 的成员变量 mServices 中,其中 mServices 是  ArrayMap 类型。 
 

猜你喜欢

转载自blog.csdn.net/lixiong0713/article/details/107083155