The process of starting Service is divided into two chapters. StartService and bindService are analyzed respectively.

This article is the source analysis of the startService process. StartService and Activity are similar in many ways. For those of you who haven’t read or don’t understand how to start an Activity before, check out my article: The Android_App startup process (including the Activity startup process). Since there are many similarities between this article and the Activity startup process, it is recommended to take a look at the Activity startup process first.

There are two ways to start a Service. StartService is used as follows:

Intent intent = new Intent(this,MyService.class);
startService(intent);
Copy the code

The above code is written in the Activity, so let’s enter it from the startService method

Go to startService and find itself inside ContextWrapper.

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

This is mainly because the Activity inherits from ContextThemeWrapper, which in turn inherits from ContextWrapper. So the ContextWrapper here is actually a Context. You can see that there is only one line of code…. in the method MBase is a context-type property inside ContextWrapper. So we have the startService method of the Context.

public abstract ComponentName startService(Intent service);
Copy the code

Context’s startService is an abstract method. So what is the entity of this mBase? The implementation of startService depends on what the entity is. To figure out what this entity is, we need to go to where mBase assigns the value.

public class ContextWrapper extends Context {
    Context mBase;

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

Hey, this is a protected method, we just need to find where it’s called. This is actually called inside the Attach method of the Activity

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback) { attachBaseContext(context); . }Copy the code

And then I’m going to assign mBase. This method uses a context as an input parameter, and we still don’t know what the context is….

So we need to know where the attach method is called, which was analyzed last time we analyzed the Activity launch process. This is actually called from the performLaunchActivity method in the ActivityThread, which is the core logic that starts the Activity.

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    / / build ContextImpl
    ContextImpl appContext = createBaseContextForActivity(r);

    // Instantiate the Activity
    Activity activity = null;
    java.lang.ClassLoader cl = appContext.getClassLoader();
    activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    
    // Call the Attach method of the Activity to instantiate something
    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);
    return activity;
}
Copy the code

The attach method is passing in a ContextImpl context.

StartService (ContextImpl); mBase (ContextImpl);

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser);
}

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
        
    / / ActivityManager. GetService () is the AMS
    ComponentName cn = ActivityManager.getService().startService(
        mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                    getContentResolver()), requireForeground,
                    getOpPackageName(), user.getIdentifier());
    return cn;
}

Copy the code

ActivityManager. GetService () is actually the AMS, here in the Activity has been analyzed in the process analysis of start here, go here. So let’s look at the AMS startService method.

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

The mServices here is an ActiveServices object, which is a property within AMS. The ActiveServices class assists AMS in managing services, including starting, binding, and stopping services. The startServiceLocked method in the ActiveServices class calls startServiceInnerLocked

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
        throws TransactionTooLargeException {... ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);return cmp;
}

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {... String error = bringUpServiceLocked(r, service.getFlags(), callerFg,false.false); .return r.name;
}
Copy the code

The bringUpServiceLocked method is called in startServiceInnerLocked

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {... realStartServiceLocked(r, app, execInFg);return null;
}
Copy the code

Finally, we see a realStartServiceLocked method in the bringUpServiceLocked method. From the name of this method, we can see that it is really time to start the actual call to the Service.

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    r.app = app;
    r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

    final boolean newService = app.services.add(r);
    boolean created = false; . app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); created =true; . }Copy the code

App. thread is an IApplicationThread, which is a remote call to ApplicationThread(the inner class of ActivityThread). Below are the scheduleCreateService methods of ApplicationThread.

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

This is the same as when the Activity starts, sending a message to the H Handler class. Then execute the start of the Service.

The CREATE_SERVICE message in this Handler’s handleMessage method calls the handleCreateService() method. This method is inside ActivityThread.

private void handleCreateService(CreateServiceData data) {
    // Build Service uses reflection to fetch build instances
    Service service = null;
    java.lang.ClassLoader cl = packageInfo.getClassLoader();
    service = packageInfo.getAppFactory()
            .instantiateService(cl, data.info.name, data.intent);
    
    // Initialize ContextImpl
    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);

    Application app = packageInfo.makeApplication(false, mInstrumentation);
    // The Service also needs this ContextImpl
    service.attach(context, this, data.info.name, data.token, app,
            ActivityManager.getService());
    // The onCreate method of the Service is immediately called
    service.onCreate();
    
    //mServices is used to store started servicesmServices.put(data.token, service); . }Copy the code

The handleCreateService method is the core of the Service startup code, which occurs in the ActivityThread. This method first builds the Service instance, then calls the Attach method of the Service, initializes something, and then calls the onCreate method of the Service. The important thing to note here is that the onCreate method of the Service, as well as other lifecycle methods, run on the main thread.

At this point, the Service startup process is analyzed.