美文网首页
App 启动流程分析(基于 Android 10)

App 启动流程分析(基于 Android 10)

作者: tandeneck | 来源:发表于2020-06-07 00:19 被阅读0次

    背景

    在 Android 手机上,当我们要启动一个应用,一般是通过在桌面点击应用图标,之后就进入 App 里面了。这显然是再正常不过的事情了,但是这些都是系统在后台默默付出的效果,系统究竟在背后做了些啥事情?今天就让我们一起探秘吧。

    桌面上的那些形形色色的 App 图标其实是由系统自带的一个叫 Launcher 应用程序管理的,一般情况下,当安装一个新的应用后,就会在手机桌面界面上出现一个相应的图标。既然 Luancher 应用和要启动的应用是不同的两个应用,那就要涉及到进程间通信了,但是本文我们不探讨进程间通信,把握 App 启动的整体流程即可。

    主体流程

    我们在开发 App 时候,会在 Manifest 文件中定义默认启动的 Activity,如下:

            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    

    点击图标就会启动这个 Activity。例如点击桌面图标启动微信(假设启动的 Activity 为 MainActivity),则启动流程大概如下:

    Launcher

    Launcher的源代码工程在 packages/apps/Launcher3 目录下,负责启动其它应用程序的源代码实现在 src/com/android/launcher3/Launcher.java 文件中:

    // packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
    public class Launcher extends BaseDraggingActivity implements LauncherExterns,
            LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate,
            InvariantDeviceProfile.OnIDPChangeListener {
        ....
        public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
                @Nullable String sourceContainer) {
            if (TestProtocol.sDebugTracing) {
                android.util.Log.d(TestProtocol.NO_START_TAG,
                        "startActivitySafely outer");
            }
    
            if (!hasBeenResumed()) {
                // Workaround an issue where the WM launch animation is clobbered when finishing the
                // recents animation into launcher. Defer launching the activity until Launcher is
                // next resumed.
                addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
                UiFactory.clearSwipeSharedState(true /* finishAnimation */);
                return true;
            }
    
            boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
            if (success && v instanceof BubbleTextView) {
                // This is set to the view that launched the activity that navigated the user away
                // from launcher. Since there is no callback for when the activity has finished
                // launching, enable the press state and keep this reference to reset the press
                // state when we return to launcher.
                BubbleTextView btv = (BubbleTextView) v;
                btv.setStayPressed(true);
                addOnResumeCallback(btv);
            }
            return success;
        }
        ....    
    

    可以看到 Launcher 继承了 BaseDraggingActivity,其本身也是一个 Activity,其调用了 BaseDraggingActivity 的 startActivitySafely(),如下:

    // packages/apps/Launcher3/src/com/android/launcher3/BaseDraggingActivity.java
        public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
                @Nullable String sourceContainer) {
            if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
                Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
                return false;
            }
            Bundle optsBundle = (v != null) ? getActivityLaunchOptionsAsBundle(v) : null;
            UserHandle user = item == null ? null : item.user;
            // Prepare intent
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (v != null) {
                intent.setSourceBounds(getViewBounds(v));
            }
            try {
                boolean isShortcut = (item instanceof WorkspaceItemInfo)
                        && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                        || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                        && !((WorkspaceItemInfo) item).isPromise();
                if (isShortcut) {
                    // Shortcuts need some special checks due to legacy reasons.
                    startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
                } else if (user == null || user.equals(Process.myUserHandle())) {
                    // Could be launching some bookkeeping activity
                    startActivity(intent, optsBundle);
                    AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
                            Process.myUserHandle(), sourceContainer);
                } else {
                    LauncherAppsCompat.getInstance(this).startActivityForProfile(
                            intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
                    AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(), user,
                            sourceContainer);
                }
                getUserEventDispatcher().logAppLaunch(v, intent);
                getStatsLogManager().logAppLaunch(v, intent);
                return true;
            } catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
                Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
            }
            return false;
        }
       
    

    在这里我们可以看到熟悉的 startActivity(intent, optsBundle),这里的 intent 包含的信息即前面 Manfiest 文件所指定的信息。同时指定 Flag 为 FLAG_ACTIVITY_NEW_TASK,表示在一个新的 task 中启动 Activity。

    startActivity 最后又会调用 startActivityForResult,源码如下:

    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 {
                ...
            }
        }
    

    这里的 mInstrumentation 是 Activity 的成员变量,它的类型是 Intrumentation,用来监控应用程序和系统的交互。mMainThread 也是 Activity 的成员变量,它的类型是 ActivityThread,也就是我们平常所说的主线程啦。通过 mMainThread.getApplicationThread() 获得 ApplicationThread,它是 ActivityThread 的一个内部类,是一个 Binder 对象。AMS 会通过 Application 来和 ActivityThread 进行进程间通信。

    Instrumentation 的 execStartActivity 方法如下:

    public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
            IApplicationThread whoThread = (IApplicationThread) contextThread;
            Uri referrer = target != null ? target.onProvideReferrer() : null;
            if (referrer != null) {
                intent.putExtra(Intent.EXTRA_REFERRER, referrer);
            }
            if (mActivityMonitors != null) {
                ...
            }
            try {
                intent.migrateExtraStreamToClipData();
                intent.prepareToLeaveProcess(who);
                int result = ActivityTaskManager.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;
        }
    

    可以看到,启动 Activity 真正的实现是由 ActivityManager.getService() 的 startActivity() 方法来完成的,这和 Android8.0 之前是有区别的:

    • 在 Android8.0 之前,ActivityManagerNative.getDefault().startActivity() 来完成,通过 getDefault 来获取到 AMS 的代理对象,用 AMS 的代理对象 ActivityManagerProxy 来与 AMS 跨进程通信。

    • 8.0 之后,这个逻辑封装到了 ActivityManager 中,通过 AIDL 跨进程通信,使用 IActivityManager,它是 AMS 的本地代理。

    至此,点击桌面的流程如下:

    ActivityManagerService 接受并处理启动请求

    Instrumentation.execStartActivity() 通过 ActivityManager.getService() 把启动流程转换到 AMS,以下是 AMS 的 startActivity() 方法:

        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());
        }
        
            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) {
            return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                    resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
                    true /*validateIncomingUser*/);
        }
    
        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,
                boolean validateIncomingUser) {
            enforceNotIsolatedCaller("startActivity");
    
            userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
                    Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    
            // TODO: Switch to user app stacks here.
            return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                    .setCaller(caller)
                    .setCallingPackage(callingPackage)
                    .setResolvedType(resolvedType)
                    .setResultTo(resultTo)
                    .setResultWho(resultWho)
                    .setRequestCode(requestCode)
                    .setStartFlags(startFlags)
                    .setProfilerInfo(profilerInfo)
                    .setActivityOptions(bOptions)
                    .setMayWait(userId)
                    .execute();
    
        }
    
    

    可以发现,startActivity() 方法调用了 startActivityAsUser() 方法,最后调用了 ActivityStartController.obtainStarter() 方法:

    /**
     * Controller for delegating activity launches.
     *
     * This class' main objective is to take external activity start requests and prepare them into
     * a series of discrete activity launches that can be handled by an {@link ActivityStarter}. It is
     * also responsible for handling logic that happens around an activity launch, but doesn't
     * necessarily influence the activity start. Examples include power hint management, processing
     * through the pending activity list, and recording home activity launches.
     */
    public class ActivityStartController {   
        ....
        ActivityStarter obtainStarter(Intent intent, String reason) {
            return mFactory.obtain().setIntent(intent).setReason(reason);
        }
        ...
    }
    
    

    根据注释得知 ActivityController 是以委托的方式把启动请求交给了一个包含所有启动信息的 ActivityStarter 对象并调用 execute 方法执行,ActivityStarter 的 execute() 方法如下:

    
     /**
         * Starts an activity based on the request parameters provided earlier.
         * @return The starter result.
         */
        int execute() {
            try {
                // TODO(b/64750076): Look into passing request directly to these methods to allow
                // for transactional diffs and preprocessing.
                if (mRequest.mayWait) {
                    return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                            mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
                            mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                            mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                            mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                            mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                            mRequest.inTask, mRequest.reason,
                            mRequest.allowPendingRemoteAnimationRegistryLookup);
                } else {
                    return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                            mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
                            mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                            mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                            mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                            mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                            mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                            mRequest.outActivity, mRequest.inTask, mRequest.reason,
                            mRequest.allowPendingRemoteAnimationRegistryLookup);
                }
            } finally {
                onExecutionComplete();
            }
        }
    
    

    因为前面在 ActivityManagerService.startActivityAsUser() 方法中调用了ActivityStarter.setMayWait() 方法,所以这里 mRequest.mayWait 值为 true,即调用 startActivityMayWait() 方法,关键代码如下:

    private 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, SafeActivityOptions options, boolean ignoreTargetSecurity,
                int userId, TaskRecord inTask, String reason,
                boolean allowPendingRemoteAnimationRegistryLookup) {
            
    
                ...
                
                //启动Activity
                int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                        voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                        callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                        ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                        allowPendingRemoteAnimationRegistryLookup);
    
                ...
        }
    
    

    之后又会调用多个 startActivity() 方法来到 startActivityUnchecked() 方法,这个方法会根据启动标志位和 Activity 启动模式来决定如何启动一个 Activity 以及是否要调用 deliverNewIntent 方法通知 Activity 有一个 Intent 试图重新启动它,在里面其又会启动 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked() 方法,如下:

        boolean resumeFocusedStackTopActivityLocked(
                ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    
            if (!readyToResume()) {
                return false;
            }
    
            if (targetStack != null && isFocusedStack(targetStack)) {
                return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
            }
    
            final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
            if (r == null || !r.isState(RESUMED)) {
                mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
            } else if (r.isState(RESUMED)) {
                // Kick off any lingering app transitions form the MoveTaskToFront operation.
                mFocusedStack.executeAppTransition(targetOptions);
            }
    
            return false;
        }
    
    
    

    ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked() 方法调用了 ActivityStack 的 resumeTopActivityUncheckedLocked() 方法,接着又调用了 resumeTopActivityInnerLocked() 方法,resumeTopActivityInnerLocked() 方法中会先判断是否由 Activity 处于 Resumed 状态,如果有的话先让这个 Activity 执行 pause 过程,然后执行 ActivityStackSupervisor.startSpecificActivityLocked() 方法,这个方法会根据进程和线程是否为空判断 App 是否已经启动,如果没有启动则会创建新的进程处理,反之已经启动的情况则会调用 realStartActivityLocked() 继续处理,方法如下:

        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);
    
            getLaunchTimeTracker().setLaunchTime(r);
    
            if (app != null && app.thread != null) {
                try {
                    if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                            || !"android".equals(r.info.packageName)) {
                        // Don't add this if it is a platform component that is marked
                        // to run in multiple processes, because this is actually
                        // part of the framework so doesn't make sense to track as a
                        // separate apk in the process.
                        app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
                                mService.mProcessStats);
                    }
                    realStartActivityLocked(r, app, andResume, checkConfig);
                    return;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting activity "
                            + r.intent.getComponent().flattenToShortString(), e);
                }
    
                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
    
            mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false, false, true);
        }
    

    我们现在分析的是首次启动 App,即进程还未创建,所以会调用 ActivityManagerService.startProcessLocked() 方法,然后经过多次调用通过 Process.start()创建进程:

        private ProcessStartResult startProcess(String hostingType, String entryPoint,
                ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
                String seInfo, String requiredAbi, String instructionSet, String invokeWith,
                long startTime) {
            ...
            startResult = Process.start(entryPoint,
                            app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                            app.info.dataDir, invokeWith,
                            new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            ...
        }
    
    // frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
        private ProcessStartResult startProcess(String hostingType, String entryPoint,
                ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
                String seInfo, String requiredAbi, String instructionSet, String invokeWith,
                long startTime) {
            ...
            startResult = Process.start(entryPoint,
                            app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                            app.info.dataDir, invokeWith,
                            new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            ...
        }
    
       //  frameworks/base/core/java/android/os/Process.java
        public static final ProcessStartResult start(final String processClass,
                                      final String niceName,
                                      int uid, int gid, int[] gids,
                                      int runtimeFlags, int mountExternal,
                                      int targetSdkVersion,
                                      String seInfo,
                                      String abi,
                                      String instructionSet,
                                      String appDataDir,
                                      String invokeWith,
                                      String[] zygoteArgs) {
            return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                        runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                        abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
        }
    
        // frameworks/base/core/java/android/os/ZygoteProcess.java
        public final Process.ProcessStartResult start(final String processClass,
                                                      final String niceName,
                                                      int uid, int gid, int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      String[] zygoteArgs) {
            try {
                return startViaZygote(processClass, niceName, uid, gid, gids,
                        runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                        abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                        zygoteArgs);
            } catch (ZygoteStartFailedEx ex) {
                Log.e(LOG_TAG,
                        "Starting VM process through Zygote failed");
                throw new RuntimeException(
                        "Starting VM process through Zygote failed", ex);
            }
        }
    
        private Process.ProcessStartResult startViaZygote(final String processClass,
                                                          final String niceName,
                                                          final int uid, final int gid,
                                                          final int[] gids,
                                                          int runtimeFlags, int mountExternal,
                                                          int targetSdkVersion,
                                                          String seInfo,
                                                          String abi,
                                                          String instructionSet,
                                                          String appDataDir,
                                                          String invokeWith,
                                                          boolean startChildZygote,
                                                          String[] extraArgs)
                                                          throws ZygoteStartFailedEx {
            ...
            synchronized(mLock) {
                return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
            }
        }
    
        private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
            Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
    
            if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
                try {
                    primaryZygoteState = ZygoteState.connect(mSocket);
                } catch (IOException ioe) {
                    throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
                }
                maybeSetApiBlacklistExemptions(primaryZygoteState, false);
                maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
            }
            if (primaryZygoteState.matches(abi)) {
                return primaryZygoteState;
            }
    
            // The primary zygote didn't match. Try the secondary.
            if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
                try {
                    secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
                } catch (IOException ioe) {
                    throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
                }
                maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
                maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
            }
    
            if (secondaryZygoteState.matches(abi)) {
                return secondaryZygoteState;
            }
    
            throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
        }
    

    最终是调用 Zygote 进程并通过 socket 通信的方式让 Zygote 进程 fork 出一个新的进程,并通过反射创建 ActivityThread 主线程并对其进行初始化。现在,要启动的 Activity 的进程和主线程皆已创建完毕。在 ActivityThread.attach 方法中,首先会通过 AMS 为新应用绑定一个 Application。

    之后,在 ActivityManagerService.attachApplication() 方法中经过多次跳转会执行到 ActivityStackSupervisor.realStartActivityLocked(),哎?这不是之前说的如果进程存在调用的方法嘛?至此,我们根据以上分析可以得到下流程图:

    启动 Activity

    通过上面可知,不过应用进程创建与否,最后都会走到 ActivityStackSupervisor.realStartActivityLocked() 方法,关键代码如下:

        final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
                boolean andResume, boolean checkConfig) throws RemoteException {
    
            if (!allPausedActivitiesComplete()) {
                // While there are activities pausing we skipping starting any new activities until
                // pauses are complete. NOTE: that we also do this for activities that are starting in
                // the paused state because they will first be resumed then paused on the client side.
                if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
                        "realStartActivityLocked: Skipping start of r=" + r
                        + " some activities pausing...");
                return false;
            }
    
            ...
    
    
                    // Create activity launch transaction.
                    final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                            r.appToken);
                    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                            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, mService.isNextTransitionForward(),
                            profilerInfo));
    
                    // Set desired final state.
                    final ActivityLifecycleItem lifecycleItem;
                    if (andResume) {
                        lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
                    } else {
                        lifecycleItem = PauseActivityItem.obtain();
                    }
                    clientTransaction.setLifecycleStateRequest(lifecycleItem);
    
                    // Schedule transaction.
                    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    
                    ...
        }
    
    

    可以发现,ClientTransaction 管理了 Activity 的启动流程,里面调用了 ClientLifecycleManager 的 scheduleTransaction() 方法,如下:

        frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java 
        void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            final IApplicationThread client = transaction.getClient();
            transaction.schedule();
            ...
        }
    
        frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
        public void schedule() throws RemoteException {
            mClient.scheduleTransaction(this);
        }
    
    

    ClientTransaction.schedule() 方法的 mClient 是一个 IApplicationThread 类型,它的实现是 ActivityThread 的内部类 它继承了IApplicationThread.Stub,ApplicationThread 的 scheduleTransaction 调用了 ActivityThread 父类 ClientTransactionHandler 的 scheduleTransaction() 方法。

        frameworks/base/core/java/android/app/ActivityThread.java
        private class ApplicationThread extends IApplicationThread.Stub {
            ...
            @Override
            public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
                ActivityThread.this.scheduleTransaction(transaction);
            }
        }
    
        frameworks/base/core/java/android/app/ClientTransactionHandler.java
        void scheduleTransaction(ClientTransaction transaction) {
            transaction.preExecute(this);
            sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
        }
    
    

    通过 sendMessage 给 ActivityThead 的 H 发送一个 EXECUTE_TRANSACTION 消息,H 是 ActivityThread 的内部类,继承了 Handler:

    class H extends Handler {
        ...
        public void handleMessage(Message msg) {
    
        ...
             case EXECUTE_TRANSACTION:
                        final ClientTransaction transaction = (ClientTransaction) msg.obj;
                        mTransactionExecutor.execute(transaction);
                        if (isSystem()) {
                            // Client transactions inside system process are recycled on the client side
                            // instead of ClientLifecycleManager to avoid being cleared before this
                            // message is handled.
                            transaction.recycle();
                        }
                        // TODO(lifecycler): Recycle locally scheduled transactions.
                        break;
        ...
        }  
        ...
    }
    
    

    mTransactionExecutor.execute() 方法通过一系列的调用会执行 LaunchActivityItem 的 execute 方法,而里面的 client 是 ActivityThread 类型,所以 H 发送的消息最后会由 ActivityThread 处理,如下:

        frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
        public void execute(ClientTransactionHandler client, IBinder token,
                PendingTransactionActions pendingActions) {
            ...
            client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        }
    
        frameworks/base/core/java/android/app/ActivityThread.java
        public Activity handleLaunchActivity(ActivityClientRecord r,
                PendingTransactionActions pendingActions, Intent customIntent) {
            ...
            final Activity a = performLaunchActivity(r, customIntent);
            ...
            return a;
        }
    

    终于柳暗花明,performLaunchActivity 最终处理了 Activity 对象的创建和启动过程,这里从方法的注释中也可以看出:

     /**  Core implementation of activity launch. */
        private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ActivityInfo aInfo = r.activityInfo;
            if (r.packageInfo == null) {
                r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                        Context.CONTEXT_INCLUDE_CODE);
            }
    
            ComponentName component = r.intent.getComponent();
            if (component == null) {
                component = r.intent.resolveActivity(
                    mInitialApplication.getPackageManager());
                r.intent.setComponent(component);
            }
    
            if (r.activityInfo.targetActivity != null) {
                component = new ComponentName(r.activityInfo.packageName,
                        r.activityInfo.targetActivity);
            }
    
            ContextImpl appContext = createBaseContextForActivity(r);
            Activity activity = null;
            try {
                java.lang.ClassLoader cl = appContext.getClassLoader();
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
                StrictMode.incrementExpectedActivityCount(activity.getClass());
                r.intent.setExtrasClassLoader(cl);
                r.intent.prepareToEnterProcess();
                if (r.state != null) {
                    r.state.setClassLoader(cl);
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            try {
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
                if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
                if (localLOGV) Slog.v(
                        TAG, r + ": app=" + app
                        + ", appName=" + app.getPackageName()
                        + ", pkg=" + r.packageInfo.getPackageName()
                        + ", comp=" + r.intent.getComponent().toShortString()
                        + ", dir=" + r.packageInfo.getAppDir());
    
                if (activity != null) {
                    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                    Configuration config = new Configuration(mCompatConfiguration);
                    if (r.overrideConfig != null) {
                        config.updateFrom(r.overrideConfig);
                    }
                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                            + r.activityInfo.name + " with config " + config);
                    Window window = null;
                    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                        window = r.mPendingRemoveWindow;
                        r.mPendingRemoveWindow = null;
                        r.mPendingRemoveWindowManager = null;
                    }
                    appContext.setOuterContext(activity);
                    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);
    
                    if (customIntent != null) {
                        activity.mIntent = customIntent;
                    }
                    r.lastNonConfigurationInstances = null;
                    checkAndBlockForNetworkAccess();
                    activity.mStartedActivity = false;
                    int theme = r.activityInfo.getThemeResource();
                    if (theme != 0) {
                        activity.setTheme(theme);
                    }
    
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onCreate()");
                    }
                    r.activity = activity;
                }
                r.setState(ON_CREATE);
    
                mActivities.put(r.token, r);
    
            } catch (SuperNotCalledException e) {
                throw e;
    
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to start activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            return activity;
        }
    

    performLaunchActivity() 这个方法主要完成了以下几件事情:

    • 从 ActivityClientRecord 中获取待启动的 Activity 的组件信息,比如 Activity 的 theme、LaunchMode。
    • 通过 Instrumentation 的 newActivity 方法使用类加载器创建 Activity 对象。
    • 获取 apk 文件的描述类 LoadApk,调用 makeApplication 方法来尝试创建 Application,如果 Application 已经创建过了,则返回之前创建好的 Application。Application 对象的创建也是通过 Instrumentation 来完成的,一样是通过类加载器来实现。前面也提到过,创建主线程的时候也会绑定 Application,大概流程是会发送 BIND_APPLICATION 的消息,接着回调 ActiviityThread 的 handleBindApplication(),而在这个方法中也是通过 LoaderApk 的 makeApplication 来创建 Application,这也说明一个应用只有一个 Application 对象(单进程)。
    • 创建 ContextImpl 对象并通过 Activity 的 attach 方法来完成一些重要数据的初始化,在 attach 方法中会创建 Window 对象并与 Activity 关联,这样当 window 接收到外部输入事件后就可以把事件传递给 Activity。
    • 调用Instrumentation的callActivityOnCreate方法,启动Activity。

    总结

    App 启动流程比较复杂,作为应用开发者我们把握住流程即可。Launcher 进程向 AMS 请求创建根 Activity,如果待启动的 Activity 的应用程序未启动,则会通过 Zygote 进程 fork 自身创建应用程序进程,当应用程序进程启动后,AMS 会通过进程间通信启动 Activity。

    参考

    相关文章

      网友评论

          本文标题:App 启动流程分析(基于 Android 10)

          本文链接:https://www.haomeiwen.com/subject/pusftktx.html