Android Service startup process

The content of this article is mostly from the book "Android Advanced Decryption". Therefore, I may not provide much help to you. The purpose of writing this article is just to have an impression and provide a convenience for myself when I study again.

The service startup process is divided into two parts, namely the invocation process from ContextImpl to ActivityManagerService and the process in which ActivityThread starts the Service.

1. The calling process of ContextImpl to ActivityManagerService

When we start the Service in the Activity, we first call the startService method, which is implemented in the ContextWrapper class, and there is only one line of code in the method body:

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

 Now let's take a look at what the mBase object of Context type refers to. In the process of ActivityThread starting Activity, the createBaseContextForActivity method is called in the performLaunchActivity method of ActivityThread to create a context object of type ContextImpl. Then pass the created context object AppContext to the app.attach method. Take a look at what is done in the createBaseContextForActivity method. code show as below:

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        
        // 代码省略。。。

        // 调用createActivityContext创建上下文对象

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

       
        // 代码省略。。。

        return appContext;
    }

It can be seen that the appContext object passed into the activity.attach method is of type ContextImpl. In the attach method of the Activity class, the attachBaseContext method of the ContextWrapper class is called. The method code is as follows:

protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }

    // 将传递进来的ContextImpl(继承自Context)类型的base对象赋值给了mBase变量

    mBase = base;
}

Therefore, mBase specifically refers to ContextImpl. Therefore, our process of starting the Service starts with the ContextImpl class. code show as below:

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    // 调用了startServiceCommon方法
    return startServiceCommon(service, false, mUser);
}

It can be seen from the code that the startServiceCommon method is returned in the ContextImpl.startService method. Now let's take a look at what is done in this method.

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

            // 代码省略。。。

            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

The familiar ActivityManager.getService().startService(....); code appears in this method. Those familiar with the Activity startup process should know that this code will actually call the startService method in ActivityManagerService. At this point, the calling process from ContextImpl to AMS is over. The sequence diagram is as follows:

Second, the process of ActivityThread starting Service

After the previous process, the code logic is executed to the startService method of AMS. This method calls the startServiceLocked method of ActiveServices. The code is as follows:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        
        // 代码省略。。。

        // 注释1:查找是否有与参数service对应的ServiceRecord
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        // 注释2:得到参数service对应的ServiceRecord
        ServiceRecord r = res.record;

       
        // 代码省略。。。。

        // 注释3
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

Note 1, the retrieveServiceLocked method is called, its role is to find out whether there is a ServiceRecord corresponding to the parameter service. The code implementation is as follows:

private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
        
        if (r == null) {
            try {
                
                // 注释1:

                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId, callingUid);
                
                // 注释2

                r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                   
        }
        if (r != null) {
            
            // 代码省略。。。
            
            // 注释3
            return new ServiceLookupResult(r, null);
        }
        return null;
    }

Note 1, it will eventually call PackageManagerService to obtain the Service information corresponding to the parameter service. At Note 2, encapsulate the Service information corresponding to the parameter service obtained in the first step into ServiceRecord. Note 3, return ServiceRecord to the startServiceLocked method of ActiveServices in the form of a ServiceLookupResult object. In the comment 2 of the startServiceLocked method, the ServiceRecord corresponding to the parameter service is obtained through the ServiceLookupResult returned in the comment 1, and passed to the startServiceInnerLocked method in the comment 3. The code of this method mainly calls the bringUpServiceLocked method, which will not be shown here. Look directly at the code of the bringUpServiceLocked method:

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        
        // 代码省略。。。

        // 注释1
       
        final String procName = r.processName;
        String hostingType = "service";
        ProcessRecord app;

        if (!isolated) {

            // 注释2

            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
           
            // 注释3

            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);

                    // 注释4

                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }
                
            }
        } else {          
            // 。。。。
        }

        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
        // 注释5
        if (app == null && !permissionsReviewRequired) {
            // 注释6
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, 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) {
                r.isolatedProc = app;
            }
        }

        // 。。。。

        return null;
    }

Note 1, get the processName value of ServiceRecord and assign it to procName, where processName is used to describe which process the Service wants to run in, and the default is the current process. Note 2: Pass the procName and the uid of the Service into the getProcessRecordLocked method of AMS to query whether there is an object app of the ProcessRecord type corresponding to the Service. ProcessRecord is mainly used to describe the information of the running application process. The judgment at Note 3 indicates that the application process used to run the Service exists, and the realStartServiceLocked method at Note 4 will be called at this time. The judgment at Note 5 indicates that the application process corresponding to Service has not been created yet, and the code at Note 6 will be called at this time. Note 6 calls the startProcessLocked method of AMS to create the application process corresponding to the Service. Now let's look at the realStartServiceLocked method in note 4, the code is as follows:

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

        // 注释1

        if (app.thread == null) {
            throw new RemoteException();
        }
        
        try {
            
            // 注释2

            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 {
            // 代码省略。。。
        }

       // 代码省略。。。
    }

This method has a lot of code, but there are only two things we need to look at. Note 1, you need to pay attention, at this time, if the application process corresponding to the Service has not been created, an exception will be thrown. Note 2, call the scheduleCreateService method of app.thread. And app.thread is of type IApplicationThread, and its implementation is the internal class ApplicationThread of ActivityThread. The method code is as follows:

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

This method encapsulates the information needed to start the Service into CreateServiceData, and sends a CREATE_SERVICE message to class H through the sendMessage method. We directly look at the processing of CREATE_SERVICE in the handleMessage method of class H:

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方法

                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;                
            }
            
    }

The processing of CREATE_SERVICE is to call the handleCreateService method. The method code is as follows:

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();
        
        // 注释1

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            // 注释2
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            //.....
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            // 注释3
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 注释4
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            // 注释5
            service.onCreate();
            // 注释6
            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) {
           // 。。。
        }
    }

This method does some of the above. Note 1: Get the LoadedApk of the application of the Service to be started. Note 2, get the class loader, and create a Service instance based on the class loader. Note 3, create the ContextImpl object of the Service context. Note 4, call the attach method of the service to initialize the Service, and pass in the ContextImpl object context created in the previous step. In this method of Service, the attachBaseContext method of ContextWrapper is called, and the parameter context is assigned to mBase. Note 5 calls the service's onCreate life cycle method, so that the Service starts. Note 6, add the started Service to the member variable mServices of ActivityThread, where mServices is an ArrayMap collection with IBinder as the key and Service as the value.

At this point, the service startup process is over, and finally the sequence diagram of this process is attached to end this article.

At this point, the article is over. I would like to thank the author of the book "Android Advanced Decryption".

Guess you like

Origin blog.csdn.net/zhourui_1021/article/details/105617527