【Android 入门】冷热启动流程

403 阅读6分钟

一些理解,关于冷、热、温启动

首先针对App通俗的理解冷、热、温启动分别:是 从 0 到 1, 从 0.8 到 1, 从 0.5 到 1 的 过程;

从应用层开发的角度来说,系统并没有界定一个明确的启动方式,只是不同操作流程中,回调方法的过程有所不同。在工作或者学习过程中,作为开发人员,我们需要对这些不同流程做到了如指掌,才能开发出一个有着优秀体验感的Android app给到用户。

一些前置的小动作

1.官网关于启动时间说明

2.以下介绍大部分是源码线索,更多源码细节需要自己阅读源码。

启动APP

从源码角度看问题,或许可以更加开阔一个开发者的视野。这里从Android 6.0 源码角度来看下,系统是如何启动我们的App。

首先,用户通过点击App图标进入我们开发的App程序,这里需要查看到入口承载的系统应用Launcher3 。(贴一下关键的源码流程,在熟悉之后也可以总结一个调用时序图)

从Launcher点击开始出发

launcher3\src\com\android\launcher3\Launcher.java

onClick() 用户点击我们的App应用图标进入。这里,LauncherApp启动后,通过PMS获取到各个应用的信息,当用户点击具体图标时,会查询到相关Appinfo的信息。

  public void onClick(View v) {
        //....
        Object tag = v.getTag();
        if (tag instanceof AppInfo) {
            startAppShortcutOrInfoActivity(v);
        }  
        //...
    }

startAppShortcutOrInfoActivity()

@Thunk 
void startAppShortcutOrInfoActivity(View v) {
    //...
    //启动我们的应用
    boolean success = startActivitySafely(v, intent, tag);
    //...
}

startActivitySafely()

public boolean startActivitySafely(View v, Intent intent, Object tag) {
    //...
    try {
        //这里调用Launcher自己的方法
        success = startActivity(v, intent, tag);
    } catch (ActivityNotFoundException e) { 
    }
    //...
    return success;
}

startActivity()

private boolean startActivity(View v, Intent intent, Object tag) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    try {
        //...
        if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
            // Could be launching some bookkeeping activity
            startActivity(intent, optsBundle);
        } 
        return true;
    } catch (SecurityException e) { 
    }
    return false;
}

到Activity休息一下

最终还是走到ActivtiystartActivity()方法

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

startActivityForResult()

    @Override
    public void startActivityForResult(
            String who, Intent intent, int requestCode, @Nullable Bundle options) {
      //...
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, who,
                intent, requestCode, options); 
        //...
    }

Instrumentation.execStartActivity()

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, String target,
        Intent intent, int requestCode, Bundle options) {
    int result = ActivityManagerNative.getDefault()
        .startActivity(whoThread, who.getBasePackageName(), intent,
               intent.resolveTypeIfNeeded(who.getContentResolver()),
                token, target, requestCode, 0, null, options);
    return null;
}

通过一些列的方法调用,到ActivityManagerNative.getDefault().startActivity()方法,后通过Binder通讯调用到AMSstartActivity()

AMS重新出发

AMS.startActivity()

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

startActivityAsUser()

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

ActivityStackSupervisor.startActivityMayWait()


    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 config,
            Bundle options, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {
            //...
            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);

            //...
            return res;
        }
    }

startActivityLocked()

    final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage,
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
            ActivityContainer container, TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;
        //...
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);
       //...
        return err;
    }

startActivityUncheckedLocked()

    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
            boolean doResume, Bundle options, TaskRecord inTask) {
        final Intent intent = r.intent;
        final int callingUid = r.launchedFromUid;
        //...
        targetStack.mLastPausedActivity = null;
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
        //...
        return ActivityManager.START_SUCCESS;
    }

ActivityStack.startActivityLocked()

    final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
        //...
        if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
        }
    }

ActivityStackSupervisor.resumeTopActivitiesLocked()


    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        //...
        // Do targetStack first.
        boolean result = false;
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }
        //...
        return result;
    }

ActivityStack.resumeTopActivityLocked()

    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        //...
        boolean result = false;
        try {
            //...
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        return result;
    }

resumeTopActivityInnerLocked()


    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
         //...
        // We need to start pausing the current activity so the top one
        // can be resumed...
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
       //...
        return true;
    }

ActivityStackSupervisor.pauseBackStacks()

    boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
        boolean someActivityPaused = false; 
        someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
                            dontWait); 
        return someActivityPaused;
    }

ActivityStack.startPausingLocked()

    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
        //...
        if (prev.app != null && prev.app.thread != null) { 
            try { 
            //...
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            } catch (Exception e) { 
            }
        } else { 
        }
      //...
    }

通过跨进程通讯调用ActivityThreadschedulePauseActivity()

回到ActivityThread

ActivityThread中回发送H.PAUSE_ACTIVITY的消息

public final void schedulePauseActivity(IBinder token, boolean finished,
     boolean userLeaving, int configChanges, boolean dontReport) {
         sendMessage(
            finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
               token,(userLeaving ? 1 : 0) | (dontReport ? 2 : 0),configChanges);
  }

接受处理消息

case PAUSE_ACTIVITY:
    handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,(msg.arg1&2) != 0);
break;

handlePauseActivity()

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
    //...
    if (!dontReport) {
        try {
            ActivityManagerNative.getDefault().activityPaused(token);
        } catch (RemoteException ex) {
        }
    }
   //...
}

又回到AMS

AMS.activityPaused()

@Override
public final void activityPaused(IBinder token) {
    final long origId = Binder.clearCallingIdentity();
    synchronized(this) {
        ActivityStack stack = ActivityRecord.getStackLocked(token);
        if (stack != null) {
            stack.activityPausedLocked(token, false);
        }
    }
//...
}

ActivityStack.activityPausedLocked()

final void activityPausedLocked(IBinder token, boolean timeout) {
    //...
    final ActivityRecord r = isInStackLocked(token);
    if (r != null) {
        if (mPausingActivity == r) {
            completePauseLocked(true);
        }  
    }
    //...
}

ActivityStack.completePauseLocked()

private void completePauseLocked(boolean resumeNext) {
    //...
    if (resumeNext) {
        final ActivityStack topStack = mStackSupervisor.getFocusedStack();
        if (!mService.isSleepingOrShuttingDown()) {
            mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
        } 
        //...
    }
    //...
}

resumeTopActivitiesLocked()

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
     Bundle targetOptions) {
    boolean result = false;
    //...
    if (isFrontStack(targetStack)) {
        result = targetStack.resumeTopActivityLocked(target, targetOptions);
    }
    //...
    return result;
}

resumeTopActivityLocked

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    //...
    boolean result = false;
    try {
        //...
        result = resumeTopActivityInnerLocked(prev, options);
    } finally { 
    }
    return result;
}

resumeTopActivityInnerLocked()

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
    //...
    ActivityStack lastStack = mStackSupervisor.getLastStack();
    if (next.app != null && next.app.thread != null) {
        //...
    } else {
    //...
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
    return true;
}

startSpecificActivityLocked()

    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);

        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) { 
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

这里可以看到,点击桌面,AMS会判断进程是否已经被创建,一般第一次没有被创建的时候;AMS通过Socket发送创建进程的消息给ZygoteZygote再收到AMS的消息,会fork出一个当前需要创建的进程;再进程创建完成后,通过启动Binder驱动,调用ActivityThread.main()方法。(以上流程,通过跟踪startSpecificActivityLocked()中调用的getProcessRecordLocked()查看到)

ZygotemMethod.invoke()反射调用android.app.ActivityThreadmain()中:

    public static void main(String[] args) {
        //...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
 
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();
        //...
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

ActivityThread.attach(false);

private void attach(boolean system) {
    //...
    final IActivityManager mgr = ActivityManagerNative.getDefault();
    try {
        mgr.attachApplication(mAppThread);
    }catch (RemoteException ex) {
    }
     //...
}

这里又通过跨进程,调用AMSattachApplication()

    @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }

AMS.attachApplicationLocked()

    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
         //...
        try {
            //...
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
            updateLruProcessLocked(app, false, null);
            app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
        } catch (Exception e) {
            //...
        } 
         //...
        return true;
    }

这里通过跨进程调用ActivityThread.bindApplication()

public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
                Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
                Bundle coreSettings) {
       //...
    sendMessage(H.BIND_APPLICATION, data);
 }

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;

handleBindApplication()

private void handleBindApplication(AppBindData data) {
     //...
    try { 
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
        //...
        try {
            mInstrumentation.onCreate(data.instrumentationArgs);
        }
        catch (Exception e) { 
        }
        //...
        try {
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) { 
        //...
        }
    } finally {
        StrictMode.setThreadPolicy(savedPolicy);
    }
}

这里主要关注data.info.makeApplicationmInstrumentation.callApplicationOnCreate

LoadedApk.makeApplication


    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }
         //...
        return app;
    }

这边可以看到当mApplication不为空时,不重复创建。

Application创建过程

Instrumentation.newApplication

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }

Instrumentation.newApplication

    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

通过源码可以看到,Application在这边被创建,并且调用了attach()方法。

Instrumentation.callApplicationOnCreate

    public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }

接着调用Application.onCreate()

最后

从源码出发了解了整个流程,对于开发过程中的一些细节问题也就迎刃而解。