First, write in front

Here’s what you need to know before you start:

  • There is a compiled good Android source code, now the basic AS can meet, start to follow the steps, a deeper understanding
  • Have some understanding of Binder mechanism
  • This article is based on API 26, which version of the source code is not important, the general process is not fundamentally different
  • From the user’s finger to the desktop icon to the Activity launch

Key Class Introduction

  • ActivityManagerService: AMS is one of the core services in Android. It is mainly responsible for the starting, switching, scheduling of four components in the system and the management and scheduling of application processes. Its responsibilities are similar to the process management and scheduling modules in the operating system, and it is also a Binder implementation class. Application processes can invoke system services through the Binder mechanism.
  • ActivityThread: the entry class of the application. The system starts the message loop queue by calling the main function. The thread in which the ActivityThread resides is called the main thread of the application (UI thread).
  • Instrumentation: Tool class that monitors the interaction between the application and the system. It wraps calls to ActivityManagerService. Some plug-in solutions are implemented by hook class.
  • ActivityStarter: An Activity starter utility class that handles the various flags for starting an Activity.
  • ActivityStackSupervisor: Manages the stack of activities for all applications, where mFocusedStack is the current application’s Activity stack.

Application Process

  • In most cases, each Android application runs in its own Linux process. When some code for an application needs to be run, the system creates this process for the application and keeps it running until it is no longer needed and the system needs to reclaim its memory for use by another application.
  • The lifecycle of an application process is not directly controlled by the application itself, but is determined by a combination of factors, such as what part of the application the system knows is running, how important it is to the user, and the total amount of memory available in the system. This is one of the basic features of Android that is very unique.
  • When an application component starts and the application is not running any other components, the Android system uses a single thread of execution to start a new Linux process for the application. By default, all components of the same application run in the same process and thread (called the “main” thread). If an application component starts and a process already exists for the application (because other components of the application exist), the component starts within that process and uses the same thread of execution. However, you can arrange for other components in your application to run in separate processes and create additional threads for any process.
  • Each application process is equivalent to a Sandbox. Android assigns a UID to each application. Note that the UID is different from the User ID in Linux.
  • Android provides an inter-process communication (IPC) mechanism with remote Procedure call (RPC), in which the system remotely executes a method called by an Activity or other application component (in another process) and returns any results to the caller. Therefore, you decompose the method call and its data to the extent that the operating system can recognize it, transfer it from the local process and address space to the remote process and address space, and then reassemble and execute the call in the remote process. The return value is then transmitted back in the opposite direction. Android provides all the code needed to perform these IPC transactions, so you only need to focus on defining and implementing the RPC programming interface.

Here’s a picture to add to the idea of a process:

Ii. Process analysis

Let’s start with a diagram of the process:

Here is a detailed process diagram that shows you the complete startup process and the classes involved:

To help you understand this, add Gityuan’s system startup architecture diagram, just look at the top half of this diagram:

Third, an overview of the

In simple terms, the following four steps can be summarized from the user’s finger touch and click on the desktop icon to the Activity launch:

  1. When you click an App on the desktop, the Launcher process is the process where the Launcher is located. The Binder starts remote processes and sends messages to the system_server process.
  1. In system_server, the operation to start the process is called firstActivityManagerService#startProcessLocked()Method, which is called internallyProcess.start(android.app.ActivityThread); Then through socket communication Zygote process fork child process, namely app process. When the process is created, it loads the ActivityThread and executesActivityThread#main()Methods;
  1. In the app process,main()Method instantiates the ActivityThread and creates ApplicationThread, Looper, and Hander objectsActivityThread#attach(false)Method to communicate with the BinderActivityManagerService#attachApplication(mAppThread)Method to notify ActivityManagerService of thread information, and Looper starts the loop.
  1. Back in system_server,ActivityManagerService#attachApplication(mAppThread)Method is called internallythread#bindApplication()mStackSupervisor#attachApplicationLocked()Let’s go through each method in turn; 4.1thread#bindApplication()Method is calledActivityThread#sendMessage(H.BIND_APPLICATION, data)The method, finallyActivityThread#handleBindApplication()To create the Application object and then callApplication#attach(context)To bind the Context, and that’s called after the Application object is createdmInstrumentation#callApplicationOnCreate()performApplication#onCreate()Life cycle; 4.2mStackSupervisor#attachApplicationLocked()Method callapp#thread#scheduleLaunchActivity()ActivityThread#ApplicationThread#scheduleLaunchActivity()Method, and then throughActivityThread#sendMessage(H.LAUNCH_ACTIVITY, r)The method, finallyActivityThread#handleLaunchActivity()To create an Activity object, and then callactivity.attach()Method, and then callmInstrumentation#callActivityOnCreate()performActivity#onCreate()Life cycle;

Four, the source call inquiry

For each of the steps in the first flowchart of this article, here’s a step-by-step look at how the source code is invoked:

STEP 1

Users click on the app icon;

STEP 2

To catch the click on the Launcher, call Activity#startActivity();

STEP 3

Activitystartactivity ();

Activity.java

    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if(options ! = null) { startActivityForResult(intent, -1, options); }else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if(mParent == null) { options = transferSpringboardActivityOptions(options); Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); ...}else{...}}Copy the code

STEP 4

Instrumentation sends messages to the system_server process through Binder communication, calling ActivityManager#getService()#startActivity(), The implementation of ActivityManager#getService() is ActivityManagerService;

Instrumentation.java

    public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {... try {intent. MigrateExtraStreamToClipData (); intent.prepareToLeaveProcess(who); int result = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! = null ? target.mEmbeddedID : null, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
Copy the code

ActivityManager.java

    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    returnam; }};Copy the code

STEP 5

ActivityManagerService calls ActivityStarter;

ActivityManagerService.java

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }

Copy the code

STEP 6

ActivityStarter calls ActivityStackSupervisor;

    final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {··· int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);

        ···
    }

    int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask, String reason) {··· mLastStartActivityResult = startActivity(Task, String reason)caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                container, inTask); ...return mLastStartActivityResult;
    }

    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {...return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
    }

    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord outActivity []) {... try {mService. MWindowManager. DeferSurfaceLayout (); result = startActivityUnchecked(r,sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity); } finally {···} ···} private int startActivityUnchecked(final ActivityRecord r, ActivityRecord RsourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) {··if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if(! mTargetStack.isFocusable() || (topTaskActivity ! = null && topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) {···}else{... mSupervisor. ResumeFocusedStackTopActivityLocked (mTargetStack mStartActivity, mOptions); }}else{···} ···}Copy the code

STEP 7

ActivityStackSupervisor calls ActivityStack;

    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if(targetStack ! = null && isFocusedStack(targetStack)) {returntargetStack.resumeTopActivityUncheckedLocked(target, targetOptions); }...return false;
    }

Copy the code

STEP 8

ActivityStack calls back to the ActivityStackSupervisor;

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {... try {... result = resumeTopActivityInnerLocked (prev, options); } finally {···} ··returnresult; } private Boolean resumeTopActivityInnerLocked (ActivityRecord prev, ActivityOptions options) {...if (next.app != null && next.app.thread != null) {
           ···
        } else{... mStackSupervisor. StartSpecificActivityLocked (next,true.true); }...}Copy the code

STEP 9

ActivityStackSupervisor calls back to ActivityManagerService, which determines whether the process to start the App exists. If so, it tells the process to start the Activity. Otherwise, it creates the process first.

Void startSpecificActivityLocked (ActivityRecord r, Boolean andResume, Boolean checkConfig) {...if(app ! = null && app.thread ! = null) {try {··· // If the process already exists, notify the process to start component realStartActivityLocked(r, app, andResume, checkConfig);return; } the catch (RemoteException e) {...}} / / or process is created first mService. StartProcessLocked (r.p rocessName, r.i show nfo. ApplicationInfo,true, 0,
                "activity", r.intent.getComponent(), false.false.true);
    }

Copy the code

STEP 10

Moving on to the case where the process has not yet been created, we see that the final call here is Process#start() to start the process;

ActivityManagerService.java

    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        returnstartProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType, hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); } final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler {··· startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs); ···} private final void startProcessLocked(ProcessRecord App, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            ProcessStartResult startResult;
            if (hostingType.equals("webview_service"{...}))else{ startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, entryPointArgs); }...}Copy the code

STEP 11

ActivityManagerService notifies Zygote process fork child process through socket communication, that is, app process;

STEP 12

When the process is created, it loads the ActivityThread, executes the ActivityThread#main() method, instantiates the ActivityThread, and creates ApplicationThread, Looper, and Hander objects. Call the ActivityThread#attach(false) method to communicate with the Binder, then Looper starts the loop;

ActivityThread.java

Public static void main(String[] args) {··· looper.prepareMainLooper (); ActivityThread thread = new ActivityThread(); thread.attach(false);

        if(sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }... stars. The loop (); Private void attach(Boolean system) {···if (!system) {
            ···
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            ···
        } else{···} ···}Copy the code

Back in system_server, The ActivityManagerService#attachApplication(mAppThread) method internally calls thread#bindApplication() and thread plication MStackSupervisor# attachApplicationLocked()

STEP 13

Where the thread#bindApplication() method calls the ActivityThread#sendMessage(h.bind_application, data) method, Finally we get to ActivityThread#handleBindApplication(), which creates the Application object, and then calls Application#attach(context) to bind the context, After creating the Application object, call mInstrumentation#callApplicationOnCreate() to execute the Application#onCreate() lifecycle;

ActivityManagerService.java

    @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            ···
            attachApplicationLocked(thread, callingPid);
            ···
        }
    }

    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        ···
        try {
            ···
            if(app.instr ! = null) { thread.bindApplication(processName, appInfo, providers, app.instr.mClass, profilerInfo, app.instr.mArguments, app.instr.mWatcher, app.instr.mUiAutomationConnection,testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.persistent, new Configuration(getGlobalConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial); }else {
                thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.persistent, new Configuration(getGlobalConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial); Catch (Exception e) {···} ··· ·if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true; }} catch (Exception e) {···}} ···}Copy the code

ActivityThread#ApplicationThread.java

        public final void bindApplication(String processName, ApplicationInfo appInfo, ·· sendMessage(h.bind_application, data); }Copy the code

ActivityThread.java

    private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        ···
        mH.sendMessage(msg);
    }

Copy the code

Let’s look at the handleMessage() method of this mH;

ActivityThread#H.java

Public void handleMessage(Message MSG) {··· switch (MSG. What) {··case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break; ......}}Copy the code

Create the Minstrumobject, and call data#info#makeApplication to create the Application object;

ActivityThread.java

Private void handleBindApplication(AppBindData Data) {··· Try {// Create an Application instance Application app = data.info.makeApplication(data.restrictedBackupMode, null); mInitialApplication = app; ... try {mInstrumentation. CallApplicationOnCreate (app); } the catch (Exception e) {...}} finally...} {...}Copy the code

LoadedApk.java

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if(mApplication ! = null) {returnmApplication; } ··· Application app = null; ... try {... app = mActivityThread. MInstrumentation. NewApplication (cl, appClass, appContext); Catch (Exception E) {···} ···if(instrumentation ! = null) {try {// Execute Application#onCreate() life cycleinstrumentation.callApplicationOnCreate(app); } catch (Exception e) {···}} ··return app;
    }

Copy the code

STEP 14

The mStackSupervisor#attachApplicationLocked() method is called app#thread#scheduleLaunchActivity() The ActivityThread#ApplicationThread#scheduleLaunchActivity() method, and then the ActivityThread#sendMessage(h.aunch_activity, r) method, Finally we get to ActivityThread#handleLaunchActivity(), create the Activity object, and call the activity.attach() method, Then call mInstrumentation#callActivityOnCreate() to execute the Activity#onCreate() lifecycle;

ActivityStackSupervisor.java

    boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
      
        for(int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; - displayNdx) {...for(int stackNdx = stacks.size() - 1; stackNdx >= 0; - stackNdx) {...if(hr ! = null) {if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                            if (realStartActivityLocked(hr, app, true.true)) {
                                didSomething = true; }} catch (RemoteException e) {··}}}}} ··} final Boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, Boolean checkConfig) throws RemoteException {... try {... app. Thread. ScheduleLaunchActivity (new Intent (r.i ntent), r.appToken, System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global and // override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, ! andResume, mService.isNextTransitionForward(), profilerInfo); ··} catch (RemoteException e) {··} ··}Copy the code

ActivityThread#ApplicationThread.java

@Override public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo ProfilerInfo) {·· sendMessage(h.aunch_activity, r); }Copy the code

ActivityThread.java

    private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        ···
        mH.sendMessage(msg);
    }

Copy the code

Let’s also look at the handleMessage() method of the mH;

ActivityThread#H.java

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                caseLAUNCH_ACTIVITY: {··· handleLaunchActivity(r, null,"LAUNCH_ACTIVITY"); ...}break; ......}}Copy the code

ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String Reason) {··· Activity a = performLaunchActivity(r, customIntent); ···} Private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {··· Activity Activity = null; Try {/ / Java objects created Activity. Lang. This cl = appContext. GetClassLoader (); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); Catch (Exception e) {···} try {···if(activity ! = null) {··· activity. Attach (appContext, this, getInstrumentation(), R.token, R.indent, app, R.intent, R.aptivityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback); ·· // Execute the Activity#onCreate() life cycle
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else{ mInstrumentation.callActivityOnCreate(activity, r.state); } catch (SuperNotCalledException e) {···} catch (Exception E) {Copy the code

At this point, the entire app startup process and source code calls have been analyzed.