美文网首页Android进阶之路Android开发Android开发经验谈
Android点击Launcher应用图标的应用程序启动过程(栈

Android点击Launcher应用图标的应用程序启动过程(栈

作者: 快乐猿Days | 来源:发表于2019-01-17 19:27 被阅读7次

    Android的Launcher启动过程分析(1)
    Android的Launcher启动过程分析(2)
    前面分析了Launcher的启动过程,下面来看一下当点击桌面上应用图标时应用程序是如何启动的。
    我们知道Launcher启动后会通过PackageManagerService获取所有已安装信息并展示在Home上,那么我们就从点击事件开始代码如下:
    /Volumes/android/WORKING_DIRECTORY/packages/apps/Launcher3/src/com/android/launcher3/ItemClickHandler

    private static void onClick(View v) {
            // Make sure that rogue clicks don't get through while allapps is launching, or after the
            // view has detached (it's possible for this to happen if the view is removed mid touch).
            if (v.getWindowToken() == null) {
                return;
            }
    
            Launcher launcher = Launcher.getLauncher(v.getContext());
            if (!launcher.getWorkspace().isFinishedSwitchingState()) {
                return;
            }
    
            Object tag = v.getTag();
            if (tag instanceof ShortcutInfo) {
                onClickAppShortcut(v, (ShortcutInfo) tag, launcher);
            } else if (tag instanceof FolderInfo) {
                if (v instanceof FolderIcon) {
                    onClickFolderIcon(v);
                }
            } else if (tag instanceof AppInfo) {
                startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
            } else if (tag instanceof LauncherAppWidgetInfo) {
                if (v instanceof PendingAppWidgetHostView) {
                    onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
                }
            }
        }
    
    

    这里Launcher中条目点击回调接口是ItemClickHandler,在onClick中我们看到会调用startAppShortcutOrInfoActivity函数一路追下去最终会调用父类BaseDraggingActivity的startActivitySafely:

    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
            if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
                Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
                return false;
            }
    
            // Only launch using the new animation if the shortcut has not opted out (this is a
            // private contract between launcher and may be ignored in the future).
            boolean useLaunchAnimation = (v != null) &&
                    !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
            Bundle optsBundle = useLaunchAnimation
                    ? 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 = Utilities.ATLEAST_MARSHMALLOW
                        && (item instanceof ShortcutInfo)
                        && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                        || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                        && !((ShortcutInfo) item).isPromise();
                if (isShortcut) {
                    // Shortcuts need some special checks due to legacy reasons.
                    startShortcutIntentSafely(intent, optsBundle, item);
                } else if (user == null || user.equals(Process.myUserHandle())) {
                    // Could be launching some bookkeeping activity
                    startActivity(intent, optsBundle);
                } else {
                    LauncherAppsCompat.getInstance(this).startActivityForProfile(
                            intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
                }
                getUserEventDispatcher().logAppLaunch(v, intent);
                return true;
            } catch (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;
        }
    

    这里会通过Intent指定栈和配置一些信息从而调用startActivity,相信这个函数大家都比较熟悉了,一路下去调用
    startActivityForResult(@RequiresPermission Intent intent, int requestCode,
    @Nullable Bundle options)函数,在其中最终会调用Instrumentation的execStartActivity:
    /Users/herrickxu/Library/Android/sdk/platforms/android-25/android.jar!/android/app/Instrumentation.class

     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 = ActivityManagerNative.getDefault()
                    .startActivity(whoThread, who.getBasePackageName(), intent,
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, target != null ? target.mEmbeddedID : null,
                            requestCode, 0, null, options);
                checkStartActivityResult(result, intent);
            } 
    ...
            return null;
        }
    

    这里的 ActivityManagerNative.getDefault 返回ActivityManagerService的远程接口,即 ActivityManagerProxy 接口,有人可能会问了为什么会是ActivityManagerProxy,这就涉及到Binder通信了,这里不再展开。通过Binder驱动程序, ActivityManagerProxy 与AMS服务通信,则实现了跨进程到System进程。

    AMS响应Launcher进程请求

    从上面的流程我们知道,此时AMS应该处理Launcher进程发来的请求,我们来看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 bOptions) {
            return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                    resultWho, requestCode, startFlags, profilerInfo, bOptions,
                    UserHandle.getCallingUserId());
        }
    

    这里的caller就是指ApplicationThread类型的Binder实体, callingPackage就是Laucher的包名,最终会调用startActivityAsUser():

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

    这里会将参数交给实现类ActivityStarter.java,我们在execute中能看到如何mayWait为true就调用startActivityMayWait函数代码如下
    /Volumes/android/WORKING_DIRECTORY/frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

    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,
                PendingIntentRecord originatingPendingIntent) {
            // Refuse possible leaked file descriptors
            if (intent != null && intent.hasFileDescriptors()) {
                throw new IllegalArgumentException("File descriptors passed in Intent");
            }
            mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
            //判定是否指定了组名ComponentInfo{com.android.settings/com.android.settings.Settings}
            boolean componentSpecified = intent.getComponent() != null;
    ...
    
            //解析intent获取ResolveInfo,ResolveInfo是获取的AndroidManifest.xml信息
            ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
                    0 /* matchFlags */,
                            computeResolveFilterUid(
                                    callingUid, realCallingUid, mRequest.filterCallingUid));
            if (rInfo == null) {
                UserInfo userInfo = mSupervisor.getUserInfo(userId);
                if (userInfo != null && userInfo.isManagedProfile()) {
                    // Special case for managed profiles, if attempting to launch non-cryto aware
                    // app in a locked managed profile from an unlocked parent allow it to resolve
                    // as user will be sent via confirm credentials to unlock the profile.
                    UserManager userManager = UserManager.get(mService.mContext);
                    boolean profileLockedAndParentUnlockingOrUnlocked = false;
                    long token = Binder.clearCallingIdentity();
                    try {
                        UserInfo parent = userManager.getProfileParent(userId);
                        profileLockedAndParentUnlockingOrUnlocked = (parent != null)
                                && userManager.isUserUnlockingOrUnlocked(parent.id)
                                && !userManager.isUserUnlockingOrUnlocked(userId);
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                    if (profileLockedAndParentUnlockingOrUnlocked) {
                        rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
                                PackageManager.MATCH_DIRECT_BOOT_AWARE
                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                                computeResolveFilterUid(
                                        callingUid, realCallingUid, mRequest.filterCallingUid));
                    }
                }
            }
            // Collect information about the target of the Intent.
     //从Intent中获取ActivityInfo 
            ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
    
            synchronized (mService) {
                final ActivityStack stack = mSupervisor.mFocusedStack;
                stack.mConfigWillChange = globalConfig != null
                        && mService.getGlobalConfiguration().diff(globalConfig) != 0;
                if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                        "Starting activity when config will change = " + stack.mConfigWillChange);
    
                final long origId = Binder.clearCallingIdentity();
    //判断是不是heavy-weight process,如果是的话,需要做一些特殊处理
                if (aInfo != null &&
                        (aInfo.applicationInfo.privateFlags
                                & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 &&
                        mService.mHasHeavyWeightFeature) {
                    // This may be a heavy-weight process!  Check to see if we already
                    // have another, different heavy-weight process running.
                    if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
     ...
                                }
                            }
    
                         ...
    //创建ActivityRecord
                final ActivityRecord[] outRecord = new ActivityRecord[1];
                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, originatingPendingIntent);
              ...
                }
    
                mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
                return res;
            }
        }
    

    目测这个方法里面有数百行,省略了非关键部分,下面接着走startActivity:

    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
                    IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                    int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                    ActivityRecord[] outActivity) {
            int result = START_CANCELED;
            try {
                mService.mWindowManager.deferSurfaceLayout();
                result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                        startFlags, doResume, options, inTask, outActivity);
            } finally {
                // If we are not able to proceed, disassociate the activity from the task. Leaving an
                // activity in an incomplete state can lead to issues, such as performing operations
                // without a window container.
                final ActivityStack stack = mStartActivity.getStack();
                if (!ActivityManager.isStartResultSuccessful(result) && stack != null) {
                    stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
                            null /* intentResultData */, "startActivity", true /* oomAdj */);
                }
                mService.mWindowManager.continueSurfaceLayout();
            }
    
            postStartActivityProcessing(r, result, mTargetStack);
    
            return result;
        }
    

    我们看到这里走到了startActivityUnchecked这个函数里面去了:

    // Note: This method should only be called from {@link startActivity}.
        private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                ActivityRecord[] outActivity) {
    ////此方法主要根据参数重新设置类的成员变量,将存储当前Activity对应的启动模式等信息
    ///mSourceRecord是com.android.launcher3.Launcher,启动app会创建一个新的task,所以mInTask是null
            setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                    voiceInteractor);
    //该方法主要计算并处理acitivity启动的栈信息
            computeLaunchingTaskFlags();
    
            computeSourceStack();
    //设置FLAGS
            mIntent.setFlags(mLaunchFlags);
    ///得到可重复使用的activity,这里mReusedActivity为nul
            ActivityRecord reusedActivity = getReusableIntentActivity();
    ...
          
            // If the activity being launched is the same as the one currently at the top, then
            // we need to check if it should only be launched once.
            final ActivityStack topStack = mSupervisor.mFocusedStack;
            final ActivityRecord topFocused = topStack.getTopActivity();
    //获取栈顶的ActivityRecord
            final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
            final boolean dontStart = top != null && mStartActivity.resultTo == null
                    && top.realActivity.equals(mStartActivity.realActivity)
                    && top.userId == mStartActivity.userId
                    && top.app != null && top.app.thread != null
                    && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                    || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
         
    ...
                return START_DELIVERED_TO_TOP;
            }
    
            boolean newTask = false;
            final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                    ? mSourceRecord.getTask() : null;
    
            // Should this be considered a new task?
            int result = START_SUCCESS;
            if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                    && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                newTask = true;
    //创建新栈
                result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
            } else if (mSourceRecord != null) {
                result = setTaskFromSourceRecord();
            } else if (mInTask != null) {
                result = setTaskFromInTask();
            } else {
                // This not being started from an existing activity, and not part of a new task...
                // just put it in the top task, though these days this case should 
    never happen.
                setTaskToCurrentTopOrCreateNewTask();
            }
            if (result != START_SUCCESS) {
                return result;
            }
    
            mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
                    mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
            mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
                    mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
            if (newTask) {
                EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
                        mStartActivity.getTask().taskId);
            }
            ActivityStack.logStartActivity(
                    EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
            mTargetStack.mLastPausedActivity = null;
    
            mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
    
            mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                    mOptions);
            if (mDoResume) {
                final ActivityRecord topTaskActivity =
                        mStartActivity.getTask().topRunningActivityLocked();
                if (!mTargetStack.isFocusable()
                        || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                        && mStartActivity != topTaskActivity)) {
                    // If the activity is not focusable, we can't resume it, but still would like to
                    // make sure it becomes visible as it starts (this will also trigger entry
                    // animation). An example of this are PIP activities.
                    // Also, we don't want to resume activities in a task that currently has an overlay
                    // as the starting activity just needs to be in the visible paused state until the
                    // over is removed.
                    mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                    // Go ahead and tell window manager to execute app transition for this activity
                    // since the app transition will not be triggered through the resume channel.
                    mService.mWindowManager.executeAppTransition();
                } else {
                    // If the target stack was not previously focusable (previous top running activity
                    // on that stack was not visible) then any prior calls to move the stack to the
                    // will not update the focused stack.  If starting the new activity now allows the
                    // task stack to be focusable, then ensure that we now update the focused stack
                    // accordingly.
                    if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                        mTargetStack.moveToFront("startActivityUnchecked");
                    }
                    //开始创建进程mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                            mOptions);
                }
            } else if (mStartActivity != null) {
                mSupervisor.mRecentTasks.add(mStartActivity.getTask());
            }
            mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
    
            mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
                    preferredLaunchDisplayId, mTargetStack);
    
            return START_SUCCESS;
        }
    

    在startActivityUnchecked()方法中主要做的事情就是调用setTaskFromReuseOrCreateNewTask() 为新启动的应用创建Task,调用startActivityLocked()将这个新的Task设置到栈顶,最后调用resumeFocusedStackTopActivityLocked()来创建新的进程,下面开始逐个分析这三个主要方法:

    1. setTaskFromReuseOrCreateNewTask
    private int setTaskFromReuseOrCreateNewTask(
                TaskRecord taskToAffiliate, ActivityStack topStack) {
            mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
    
            // Do no move the target stack to front yet, as we might bail if
            // isLockTaskModeViolation fails below.
    
            if (mReuseTask == null) {
    ////调用createTaskRecord创建Task
                final TaskRecord task = mTargetStack.createTaskRecord(
                        mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
                        mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                        mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                        mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
                        mOptions);
                addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
                updateBounds(mStartActivity.getTask(), mLaunchParams.mBounds);
    
                ...
            return START_SUCCESS;
        }
    

    为基建启动的activity创建TaskRecord,下面接着看ActivityStack createTaskRecord函数:

    TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                boolean toTop, ActivityRecord activity, ActivityRecord source,
                ActivityOptions options) {
            final TaskRecord task = TaskRecord.create(
                    mService, taskId, info, intent, voiceSession, voiceInteractor);
            // add the task to stack first, mTaskPositioner might need the stack association
            addTask(task, toTop, "createTaskRecord");
            final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
            final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
                    .isKeyguardOrAodShowing(displayId);
            if (!mStackSupervisor.getLaunchParamsController()
                    .layoutTask(task, info.windowLayout, activity, source, options)
                    && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
                task.updateOverrideConfiguration(getOverrideBounds());
            }
            task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
            return task;
        }
    

    创建task后,将这个task加入到mTaskHistory中,接着我看看addTask方法

    void addTask(final TaskRecord task, final boolean toTop, String reason) {
            addTask(task, toTop ? MAX_VALUE : 0, true /* schedulePictureInPictureModeChange */, reason);
            if (toTop) {
                // TODO: figure-out a way to remove this call.
                mWindowContainerController.positionChildAtTop(task.getWindowContainerController(),
                        true /* includingParents */);
            }
        }
    
    void addTask(final TaskRecord task, int position, boolean schedulePictureInPictureModeChange,
                String reason) {
            // TODO: Is this remove really needed? Need to look into the call path for the other addTask
    //先从记录里面移除
            mTaskHistory.remove(task);
    //获取栈在堆内的索引
            position = getAdjustedPositionForTask(task, position, null /* starting */);
            final boolean toTop = position >= mTaskHistory.size();
            final ActivityStack prevStack = preAddTask(task, reason, toTop);
    //添加到记录中
            mTaskHistory.add(position, task);
    //关联父stack
            task.setStack(this);
    
            updateTaskMovement(task, toTop);
    
            postAddTask(task, prevStack, schedulePictureInPictureModeChange);
        }
    

    继续回到ActivittyStarter的startActivityUnchecked中我们看到调用ActivityStack调用其startActivityLocked方法:

    1. startActivityLocked:
    void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
                boolean newTask, boolean keepCurTransition, ActivityOptions options) {
            TaskRecord rTask = r.getTask();
            final int taskId = rTask.taskId;
            // mLaunchTaskBehind tasks get placed at the back of the task stack.
            if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
                // Last activity in task had been removed or ActivityManagerService is reusing task.
                // Insert or replace.
                // Might not even be in.
                insertTaskAtTop(rTask, r);
            }
            TaskRecord task = null;
            ...
            final TaskRecord activityTask = r.getTask();
            if (task == activityTask && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
                mStackSupervisor.mUserLeaving = false;
                if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                        "startActivity() behind front, mUserLeaving=false");
            }
    
            task = activityTask;
    
            // Slot the activity into the history stack and proceed
            if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
                    new RuntimeException("here").fillInStackTrace());
            // TODO: Need to investigate if it is okay for the controller to already be created by the
            // time we get to this point. I think it is, but need to double check.
            // Use test in b/34179495 to trace the call path.
            if (r.getWindowContainerController() == null) {
    //内部调用TaskRecord的addActivityToTop方法
                r.createWindowContainer();
            }
    //调用TaskRecord的setFrontOfTask()方法
            task.setFrontOfTask();
    
           ...
        }
    

    接下来我们继续看startActivityLocked中的insertTaskAtTop(rTask, r)方法:

    
        private void insertTaskAtTop(TaskRecord task, ActivityRecord starting) {
            // TODO: Better place to put all the code below...may be addTask...
            mTaskHistory.remove(task);
            // Now put task at top.
            final int position = getAdjustedPositionForTask(task, mTaskHistory.size(), starting);
            mTaskHistory.add(position, task);
            updateTaskMovement(task, true);
            mWindowContainerController.positionChildAtTop(task.getWindowContainerController(),
                    true /* includingParents */);
        }
    

    该方法中会通过WindowContainerController.positionChildAtTop调整task于栈顶,下面继续看setFrontOfTask:

     final void setFrontOfTask() {
            boolean foundFront = false;
            final int numActivities = mActivities.size();
            for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
                final ActivityRecord r = mActivities.get(activityNdx);
                if (foundFront || r.finishing) {
                    r.frontOfTask = false;
                } else {
                    r.frontOfTask = true;
                    // Set frontOfTask false for every following activity.
                    foundFront = true;
                }
            }
            if (!foundFront && numActivities > 0) {
                // All activities of this task are finishing. As we ought to have a frontOfTask
                // activity, make the bottom activity front.
                mActivities.get(0).frontOfTask = true;
            }
        }
    

    调用TaskRecord.java -->setFrontOfTask()将要启动的app的main activity设置到Task的的栈顶。到这里即将启动的app的task已经创建好,并设置了栈顶,下面开始为其创建进程。

    创建进程的过程

    我们回到ActivityStarter的startActivityUnchecked函数中,继续看到这个函数mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,它里面有没多少东西,就不贴代码了,接着走ctivityStack.java 的resumeTopActivityUncheckedLocked(),然后接着走resumeTopActivityInnerLocked()

    @GuardedBy("mService")
        private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    ...
    //将当前activity置为pause状态
            boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
            ...
    //创建进程
                if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
                mStackSupervisor.startSpecificActivityLocked(next, true, true);
            }
    
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        }
    

    com.android.server.am.ActivityStackSupervisor的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);
    ////设置启动时间
            getLaunchTimeTracker().setLaunchTime(r);
    //如果对应进程已经存在,并向AMS注册过
            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.
            }
    //如果进程不存在,利用AMS的startProcessLocked函数,创建一个新的进程
            mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false, false, true);
        }
    

    该函数中判断进程是否存在,如果存在就向AMS注册,如果不存在就创建一个新的进程,接着看startProcessLocked:

     @GuardedBy("this")
        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) {
            long startTime = SystemClock.elapsedRealtime();
            ProcessRecord app;
    ...
    
            if (app == null) {
                checkTime(startTime, "startProcess: creating new process record");
    //调用newProcessRecordLocked创建ProcessRecord对象
                app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
                if (app == null) {
                    Slog.w(TAG, "Failed making new process record for "
                            + processName + "/" + info.uid + " isolated=" + isolated);
                    return null;
                }
                app.crashHandler = crashHandler;
                app.isolatedEntryPoint = entryPoint;
                app.isolatedEntryPointArgs = entryPointArgs;
                checkTime(startTime, "startProcess: done creating new process record");
            } 
    ...
     checkTime(startTime, "startProcess: stepping in to startProcess");
    /start进程
            final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
            checkTime(startTime, "startProcess: done starting proc!");
            return success ? app : null;
    }
    

    这个方法主要是调用newProcessRecordLocked创建ProcessRecord对象,然后继看AMS的startProcessLocked函数如何开始创建进程的:

    @GuardedBy("this")
        final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
                boolean isolated, int isolatedUid) {
           ...
            final ProcessRecord r = new ProcessRecord(this, stats, info, proc, uid);
           ...
            addProcessNameLocked(r);
            return r;
        }
    

    回过头来继续看startProcessLocked中调用的的启动进程函数startProcessLocked (参数不同的startProcessLocked)

     @GuardedBy("this")
        private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
                ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
                String seInfo, String requiredAbi, String instructionSet, String invokeWith,
                long startTime) {
    ...
            if (mConstants.FLAG_PROCESS_START_ASYNC) {
                if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
                        "Posting procStart msg for " + app.toShortString());
                mProcStartHandler.post(() -> {
                    try {
                        synchronized (ActivityManagerService.this) {
                            final String reason = isProcStartValidLocked(app, startSeq);
                         ...
    //启动进程
                        final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                                app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                                requiredAbi, instructionSet, invokeWith, app.startTime);
                        synchronized (ActivityManagerService.this) {
                            handleProcessStartedLocked(app, startResult, startSeq);
                        }
                    } 
    ...
                return true;
            } else {
                try {
    //启动进程
                    final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                            uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                            invokeWith, startTime);
                    handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                            startSeq, false);
                } 
    ...
                return app.pid > 0;
            }
        }
    

    这里主要就是调用startProcess启动进程并返回结果:

     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) {
            try {
                ...
                if (hostingType.equals("webview_service")) {
                    startResult = startWebView(entryPoint,
                            app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                            app.info.dataDir, null,
                            new String[] {PROC_START_SEQ_IDENT + app.startSeq});
                } else {
    //启动进程
                    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});
                }
                checkTime(startTime, "startProcess: returned from zygote!");
                return startResult;
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }
    

    这里进行判断hostingType是webview_service启动webview_service进程,否者启动Process.start()启动进程,start方法中会调用startViaZygote方法,最终会调用zygoteSendArgsAndGetResult方法来个Zygote通讯:

     private static ProcessStartResult zygoteSendArgsAndGetResult(
                ZygoteState zygoteState, ArrayList<String> args)
                throws ZygoteStartFailedEx {
            try {
                // Throw early if any of the arguments are malformed. This means we can
                // avoid writing a partial response to the zygote.
                int sz = args.size();
                for (int i = 0; i < sz; i++) {
                    if (args.get(i).indexOf('\n') >= 0) {
                        throw new ZygoteStartFailedEx("embedded newlines not allowed");
                    }
                }
    
                /**
                 * See com.android.internal.os.ZygoteInit.readArgumentList()
                 * Presently the wire format to the zygote process is:
                 * a) a count of arguments (argc, in essence)
                 * b) a number of newline-separated argument strings equal to count
                 *
                 * After the zygote process reads these it will write the pid of
                 * the child or -1 on failure, followed by boolean to
                 * indicate whether a wrapper process was used.
                 */
                final BufferedWriter writer = zygoteState.writer;
                final DataInputStream inputStream = zygoteState.inputStream;
    
                writer.write(Integer.toString(args.size()));
                writer.newLine();
    
                for (int i = 0; i < sz; i++) {//发送请求参数到Zygote
                    String arg = args.get(i);
                    writer.write(arg);
                    writer.newLine();
                }
    
                writer.flush();
    
                // Should there be a timeout on this?
                ProcessStartResult result = new ProcessStartResult();
    
                // Always read the entire result from the input stream to avoid leaving
                // bytes in the stream for future process starts to accidentally stumble
                // upon.
    //Zygote处理完成会返回子进程的pid(即要创建的进程)
                result.pid = inputStream.readInt();
                result.usingWrapper = inputStream.readBoolean();
    
                if (result.pid < 0) {
                    throw new ZygoteStartFailedEx("fork() failed");
                }
                return result;
            } catch (IOException ex) {
                zygoteState.close();
                throw new ZygoteStartFailedEx(ex);
            }
        }
    

    到这里位置,客户端请求Zygote创建进程的请求就发送出去了,Zygote会返回进行的pid给客户端(ActivityMangerService)。由于ActivityMangerService在SystemServer进程中,所以这里即SystemServer进程通过socket向Zygote发送了信息。那么我们继续追踪一下Zygote是如何处理客户端请求的。

    Zygote处理客户端请求

    由于本片文章太长我进行了分割,请继续看下一篇Android点击Launcher应用图标的应用程序启动过程(栈和进程的创建)之Zygote是如何处理客户端请求的

    相关文章

      网友评论

        本文标题:Android点击Launcher应用图标的应用程序启动过程(栈

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