This is the sixth day of my participation in the August Text Challenge.More challenges in August

Service startup process

StartService (service) Calls the startService method in the Activity, actually calling the startService method of the ContextWrapper parent class. MBase. StartService (service), ContextWrapper, ContextWrapper, ContextWrapper, ContextWrapper, ContextWrapper We looked at the creation of the Activity Context and learned that the mBase object is actually ContextImpl, So mBase. StartService actually calls ContextImpl’s startService method:

class ContextImpl extends Context {

    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            / / 1
            ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());
            if(cn ! =null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!!!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ":" + cn.getClassName());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ":"+ cn.getClassName()); }}return cn;
        } catch (RemoteException e) {
            throwe.rethrowFromSystemServer(); }}}Copy the code

In the note 1 through ActivityManager. GetService () to obtain the ActivityManagerService SystemServer process, The startService method of ActivityManagerService is then called.

public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage,
        String callingFeatureId, int userId)
        throws TransactionTooLargeException {... res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, requireForeground, callingPackage, callingFeatureId, userId); .return res;
}
Copy the code

The startService method of ActivityManagerService calls the startServiceLocked method of ActiveServices. The startServiceLocked method is called internally. The startServiceLocked method has a lot of content, so we’ll focus on the key code here:

ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
Copy the code

The startServiceInnerLocked key method is called in the startServiceLocked method, and the realStartServiceLocked method is called in the startServiceInnerLocked method:

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {... app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), app.getReportedProcState()); . }Copy the code

App. thread is an IApplicationThread. Those familiar with ActivityThreads should know that IApplicationThread is an inner class of activityThreads. The scheduleCreateService method of IApplicationThread is called here:

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);
}
Copy the code

Service Context creation process

The IApplicationThread’s scheduleCreateService method calls the ActivityThread’s sendMessage method, and the first parameter is h.create_service. The sendMessage method of the ActivityThread ends up sending a Message to the main mH object of type H of the ActivityThread. Class H is an inner class of the ActivityThread that inherits Handler. Msg. what == h.create_service calls handleCreateService((CreateServiceData)msg.obj);

@UnsupportedAppUsage
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);
        / / 1
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        / / 2
        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]));
        / / 3
        context.setOuterContext(service);
        / / 4
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        / / 5
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0.0);
        } catch (RemoteException e) {
            throwe.rethrowFromSystemServer(); }}catch (Exception e) {
        if(! mInstrumentation.onException(service, e)) {throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ":"+ e.toString(), e); }}}Copy the code

In comment 1, the ContextImpl object Conext is created using the ContextImpl createAppContext method and passed the ContextIml to the Attach method of the Service in comment 4. The Service object is created by reflecting on the instantiateService method at comment 2, the setOuterContext method is called at comment 3, Assigning the previously created Service instance to mOuterContext, a ContextImpl member variable, allows ContextImpl to access Service variables and methods as well. The onCreate method of the service is called in comment 5 to indicate that the service has started successfully. Attach the service:

@UnsupportedAppUsage
public final void attach( Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager) {
    / / 1
    attachBaseContext(context);
    mThread = thread;           // NOTE:  unused - remove?
    mClassName = className;
    mToken = token;
    mApplication = application;
    mActivityManager = (IActivityManager)activityManager;
    mStartCompatibility = getApplicationInfo().targetSdkVersion
            < Build.VERSION_CODES.ECLAIR;

    setContentCaptureOptions(application.getContentCaptureOptions());
}
Copy the code

The attachBaseContext method is finally called at comment 1, and finally the attachBaseContext method of ContextWrapper is called,

public class ContextWrapper extends Context {
    Context mBase;
    protected void attachBaseContext(Context base) {
        if(mBase ! =null) {
            throw new IllegalStateException("Base context already set");
        }
        / / 1mBase = base; }}Copy the code

The base at comment 1 is ContextImpl passed all the way, Copy ContextImpl to mBase, a member of ContextWrapper’s Context type, so that Context methods can be used in ContextWrapper, The Service inherits from ContextWrapper and can also use the Context’s methods.