首页 > 其他分享 >HomeActivity启动流程(launcher)

HomeActivity启动流程(launcher)

时间:2024-07-09 20:08:36浏览次数:16  
标签:task launcher 流程 HomeActivity int mStartActivity intent null app

  简介: 0. 写在前面的话上一篇讲了各种Service是在何时启动的,最后提到了关于HomeActivity的启动。HomeActivity作为Android系统启动后第一个加载的Activity,今天就来分析下其启动流程。

0. 写在前面的话

上一篇讲了各种Service是在何时启动的,最后提到了关于HomeActivity的启动。HomeActivity作为Android系统启动后第一个加载的Activity,今天就来分析下其启动流程。
其实还有个时序图的,但是太大了,截图也不全,等下次直接上传,方便自己查看。
暂时的规划先是Activity的启动流程,通过这个又会涉及到进程间通信——Binder机制,接着Activity启动后,布局是如何绘制到屏幕上,View的事件是如何分发的?通过这条线来慢慢整理这两年多我对Android的理解,加深自己的印象。

1. ActivityManagerService.systemReady(new Runnable())做了什么?

我们先来看下这个方法的代码:

public void systemReady(final Runnable goingCallback) {
    synchronized(this) {
        //mSystemReady默认为false,所以第一次调用这个方法时不会执行goingCallback.run()
        if (mSystemReady) {
            if (goingCallback != null) {
                goingCallback.run();
            }
            return;
        }
        ......
    }
    //要杀掉的进程(启动时不允许启动的进程)
    ArrayList<ProcessRecord> procsToKill = null;
    synchronized(mPidsSelfLocked) {
        for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
            ProcessRecord proc = mPidsSelfLocked.valueAt(i);
            if (!isAllowedWhileBooting(proc.info)){
                if (procsToKill == null) {
                    procsToKill = new ArrayList<ProcessRecord>();
                }
                procsToKill.add(proc);
            }
        }
    }
    //杀掉这些进程
    synchronized(this) {
        if (procsToKill != null) {
            for (int i=procsToKill.size()-1; i>=0; i--) {
                ProcessRecord proc = procsToKill.get(i);
                Slog.i(TAG, "Removing system update proc: " + proc);
                removeProcessLocked(proc, true, false, "system update done");
            }
        }

        // Now that we have cleaned up any update processes, we
        // are ready to start launching real processes and know that
        // we won't trample on them any more.
        mProcessesReady = true;
    }
    ......
    //这里会调用Runnable的run()方法
    if (goingCallback != null) goingCallback.run();
    ......
    synchronized (this) {
        //启动常驻的应用
        startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
        mBooting = true;
        if (UserManager.isSplitSystemUser()) {
            ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
            try {
                //解禁SystemUserHomeActivity
                AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
                        UserHandle.USER_SYSTEM);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }
        }
        //开始启动HomeActivity
        startHomeActivityLocked(currentUserId, "systemReady");
        ......
    }
}

这个方法内容挺多的,首次进入是设置的Runnable不会执行,后面通过查找启动时系统不允许启动的进程,并将其kill掉。接下来启动了系统常驻应用startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE),通过使用AppGlobals.getPackageManager().setComponentEnabledSetting方法解禁SystemUserHomeActivity,其flag为PackageManager.COMPONENT_ENABLED_STATE_ENABLED,最后通过startHomeActivityLocked(currentUserId, "systemReady")来启动HomeActivity


2. startHomeActivityLocked开始启动HomeActivity

这里的代码不多,也很好理解:

boolean startHomeActivityLocked(int userId, String reason) {
    //测试模式下不用管
    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
            && mTopAction == null) {
        // We are running in factory test mode, but unable to find
        // the factory test app, so just sit around displaying the
        // error message and don't try to start anything.
        return false;
    }
    //得到要启动Activity的Intent
    Intent intent = getHomeIntent();
    //将Intent解析成ActivityInfo
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
        intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
        // Don't do this if the home app is currently being
        // instrumented.
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
        ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                aInfo.applicationInfo.uid, true);
        if (app == null || app.instrumentationClass == null) {
            intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
            //启动Activity
            mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
        }
    } else {
        Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
    }

    return true;
}

Intent getHomeIntent() {
    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    intent.setComponent(mTopComponent);
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    //不是测试情况下则设置Category为Intent.CATEGORY_HOME
    if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        intent.addCategory(Intent.CATEGORY_HOME);
    }
    return intent;
}

首先是判断当前系统是否处于测试环境,接着去获取(创建)HomeIntent,并将其解析成ActivityInfo,接下来调用ActivityStarter中的startHomeActivityLocked(intent, aInfo, reason)方法去启动HomeActivity


3. startHomeActivityLockedstartActivityLocked

我们进入ActivityStarter中可以看到startHomeActivityLocked调用了startActivityLocked方法,其中传入的参数只有IntentActivityInfo不为空,其他的都为null或者0或者false,由于大部分参数都为nullstartActivityLocked中真正执行的代码并不是很多。

void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
    mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
    //调用了参数居多的方法
    startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
            null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
            null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
            0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
            0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
            false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
            null /*container*/, null /*inTask*/);
    if (mSupervisor.inResumeTopActivity) {
        // If we are in resume section already, home activity will be initialized, but not
        // resumed (to avoid recursive resume) and will stay that way until something pokes it
        // again. We need to schedule another resume.
        mSupervisor.scheduleResumeTopActivities();
    }
}
//这个参数是真TM的多啊
final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
        TaskRecord inTask) {
    //启动结果代码
    int err = ActivityManager.START_SUCCESS;
    
    ProcessRecord callerApp = null;
    //caller == null
    if (caller != null) {
        ......
    }
    
    final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;

    if (err == ActivityManager.START_SUCCESS) {
        ..Log..
    }

    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    //resultTo == null
    if (resultTo != null) {
        ......
    }

    final int launchFlags = intent.getFlags();
    //Activity启动是设置的flags
    if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
        ......
    }

    ......
    
    //检查启动Activity的权限
    boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
            requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
            resultRecord, resultStack, options);
    abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
            callingPid, resolvedType, aInfo.applicationInfo);

    if (mService.mController != null) {
        try {
            // The Intent we give to the watcher has the extra data
            // stripped off, since it can contain private information.
            Intent watchIntent = intent.cloneFilter();
            abort |= !mService.mController.activityStarting(watchIntent,
                    aInfo.applicationInfo.packageName);
        } catch (RemoteException e) {
            mService.mController = null;
        }
    }

    ......

    // If we have an ephemeral app, abort the process of launching the resolved intent.
    // Instead, launch the ephemeral installer. Once the installer is finished, it
    // starts either the intent we resolved here [on install error] or the ephemeral
    // app [on install success].
    if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
        intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
                rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
                userId);
        resolvedType = null;
        callingUid = realCallingUid;
        callingPid = realCallingPid;

        aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
    }
    //创建了ActivityRecord,用于存储保存Activity
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
            requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
            options, sourceRecord);
    ......

    try {
        mService.mWindowManager.deferSurfaceLayout();
        //启动Activity
        err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                true, options, inTask);
    } finally {
        mService.mWindowManager.continueSurfaceLayout();
    }
    postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
    return err;
}

虽然上面的方法参数很多,但是由于大部分都为null或者0,所以真正执行的部分很少。先进行对flag的检查,我们的intent只设置了Intent.FLAG_DEBUG_TRIAGED_MISSING,所以对flag判断的部分执行也不执行。权限检查!mSupervisor.checkStartAnyActivityPermission,如果没有权限,则最终不会启动。我们要启动的是HomeActivity,所有需要的权限都有,因此创建一个ActivityRecord,用于存放Activity的信息,最后调用startActivityUnchecked执行启动过程。


4. startActivityUnchecked过程

startActivityUnchecked这个方法做了很多事情,包括了对当前的ActivitylaunchMode的设置、处理,我们要启动的是HomeActivity,所以呢,我们并不care这些东西。

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
    //初始化,这里需要注意的一点是doResume这个参数我们传过来的是true,下面会用到
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
            voiceInteractor);
    //设置launchMode flag
    computeLaunchingTaskFlags();

    computeSourceStack();

    mIntent.setFlags(mLaunchFlags);

    mReusedActivity = getReusableIntentActivity();

    final int preferredLaunchStackId =
            (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;

    if (mReusedActivity != null) {
        // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
        // still needs to be a lock task mode violation since the task gets cleared out and
        // the device would otherwise leave the locked task.
        if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
                (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
            mSupervisor.showLockTaskToast();
            Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        if (mStartActivity.task == null) {
            mStartActivity.task = mReusedActivity.task;
        }
        if (mReusedActivity.task.intent == null) {
            // This task was started because of movement of the activity based on affinity...
            // Now that we are actually launching it, we can assign the base intent.
            mReusedActivity.task.setIntent(mStartActivity);
        }

        // This code path leads to delivering a new intent, we want to make sure we schedule it
        // as the first operation, in case the activity will be resumed as a result of later
        // operations.
        //这里是处理launchMode为FLAG_ACTIVITY_CLEAR_TOP的情况
        if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                || mLaunchSingleInstance || mLaunchSingleTask) {
            // In this situation we want to remove all activities from the task up to the one
            // being started. In most cases this means we are resetting the task to its initial
            // state.
            final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
                    mStartActivity, mLaunchFlags);
            if (top != null) {
                if (top.frontOfTask) {
                    // Activity aliases may mean we use different intents for the top activity,
                    // so make sure the task now has the identity of the new intent.
                    top.task.setIntent(mStartActivity);
                }
                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
                //去掉用Activity的onNewIntent方法
                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                        mStartActivity.launchedFromPackage);
            }
        }

        sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);

        mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);

        if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
            ......
        }
        setTaskFromIntentActivity(mReusedActivity);

        if (!mAddingToTask && mReuseTask == null) {
            ......
        }
    }

    if (mStartActivity.packageName == null) {
        if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
            mStartActivity.resultTo.task.stack.sendActivityResultLocked(
                    -1, mStartActivity.resultTo, mStartActivity.resultWho,
                    mStartActivity.requestCode, RESULT_CANCELED, null);
        }
        ActivityOptions.abort(mOptions);
        //启动失败
        return START_CLASS_NOT_FOUND;
    }

    // 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.
    //如果当前的Activity的launchModeFLAG_ACTIVITY_SINGLE_TOP,并且是处于任务栈的栈顶,
    //则不用启动,并调用Activity的onNewIntent方法
    final ActivityStack topStack = mSupervisor.mFocusedStack;
    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
            || mLaunchSingleTop || mLaunchSingleTask);
    if (dontStart) {
        ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
        // For paranoia, make sure we have correctly resumed the top activity.
        topStack.mLastPausedActivity = null;
        if (mDoResume) {
            mSupervisor.resumeFocusedStackTopActivityLocked();
        }
        ActivityOptions.abort(mOptions);
        if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
            // We don't need to start a new activity, and the client said not to do
            // anything if that is the case, so this is it!
            return START_RETURN_INTENT_TO_CALLER;
        }
        //调用Activity的onNewIntent方法
        top.deliverNewIntentLocked(
                mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);

        // Don't use mStartActivity.task to show the toast. We're not starting a new activity
        // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
        mSupervisor.handleNonResizableTaskIfNeeded(
                top.task, preferredLaunchStackId, topStack.mStackId);

        return START_DELIVERED_TO_TOP;
    }

    boolean newTask = false;
    final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
            ? mSourceRecord.task : null;

    // Should this be considered a new task?
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        setTaskFromReuseOrCreateNewTask(taskToAffiliate);

        if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }
        if (!mMovedOtherTask) {
            // If stack id is specified in activity options, usually it means that activity is
            // launched not from currently focused stack (e.g. from SysUI or from shell) - in
            // that case we check the target stack.
            updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
                    preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
        }
    } else if (mSourceRecord != null) {
        if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        final int result = setTaskFromSourceRecord();
        if (result != START_SUCCESS) {
            return result;
        }
    } else if (mInTask != null) {
        // The caller is asking that the new activity be started in an explicit
        // task it has provided to us.
        if (mSupervisor.isLockTaskModeViolation(mInTask)) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        final int result = setTaskFromInTask();
        if (result != START_SUCCESS) {
            return result;
        }
    } 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();
    }

    mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
            mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);

    if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
        mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
    }
    if (newTask) {
        EventLog.writeEvent(
                EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
    }
    ActivityStack.logStartActivity(
            EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
    mTargetStack.mLastPausedActivity = null;

    sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
    
    mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
    //mDoResume设置为true
    if (mDoResume) {
        ......
        final ActivityRecord topTaskActivity = mStartActivity.task.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.
            mWindowManager.executeAppTransition();
        } else {
            //执行此方法
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                    mOptions);
        }
    } else {
        mTargetStack.addRecentActivityLocked(mStartActivity);
    }
    mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

    mSupervisor.handleNonResizableTaskIfNeeded(
            mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);

    return START_SUCCESS;
}

在这个方法中,我们看到了对Activity的不同的launchMode的处理,我们要启动的HomeActivity只会是启动一个新的Task,所以大部分操作还是启动其他Activity时进行的。代码里面也讲到了,我们在初始化是mDoResume传入了true,代码会执行mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);


5. 方法的各种调用直至resumeTopActivityInnerLocked

上面讲到我们会执行ActivityStackSupervisorresumeFocusedStackTopActivityLocked方法,跟进方法后会发现其又会调用ActivityStackresumeTopActivityUncheckedLocked方法,这个方法会调用自身的resumeTopActivityInnerLocked方法,在resumeTopActivityInnerLocked中,会根据当前的Activity Task中是否有需要pause的Activity,如果有先去执行pause,没有的话则去启动Activity。
大致代码

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    // Find the first activity that is not finishing.
    //这里看了很久,后来从前面的代码慢慢理清的话,这个next就是指的就是当前要启动的Activity的Record
    //这里是自己的理解,希望不会有什么差错
    final ActivityRecord next = topRunningActivityLocked();
    ......
    final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
    boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
    if (mResumedActivity != null) {
        if (DEBUG_STATES) Slog.d(TAG_STATES,
                "resumeTopActivityLocked: Pausing " + mResumedActivity);
        //执行pause
        pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
    }
    ......
    ActivityStack lastStack = mStackSupervisor.getLastStack();
    //要启动的Activity的app是不是为空,显然是null
    if (next.app != null && next.app.thread != null) {
        ......
    } else {
        //启动
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }

    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    return true;
}

上面的代码我省略了很多,主要是先拿到最上面运行的先判断其是否为null,不为null则去判断是否需要执行pause,我们这里面是不需要执行的,在后面有个对next.app的非空判断,因为我们是第一次启动,所以并没有app,最后会执行mStackSupervisor.startSpecificActivityLocked(next, true, true)这部分代码。


6. ActivityStackSupervisor.startSpecificActivityLocked过程

这个过程就比较简单了,通过AMS去启动一个新的进程(Process)。

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);
    //很明显,这里的app为null,我们需要创建新的process
    if (app != null && app.thread != null) {
        ......
    }
    //启动新的process
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}   

7. AMS启动新的进程

AMS中startProcessLocked中调用了Process.start这个方法。Process.start中调用了startViaZygote方法,接着调用zygoteSendArgsAndGetResult方法,通过socket进行通信执行ActivityThreadmain方法。
部分代码:

AMS:
private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        ......
        //去启动进程
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        ......
}
Process.java:
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        
    }
}
private static ProcessStartResult startViaZygote(final String processClass,
                              final String niceName,
                              final int uid, final int gid,
                              final int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] extraArgs)
                              throws ZygoteStartFailedEx {
    synchronized(Process.class) {
        ......
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi)/**这里可以看到通过socket启动*/, argsForZygote);
    }
}

private static ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
    try {
        
        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");
            }
        }

        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++) {
            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.
        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可以执行ActivityThread中的main方法。


8. ActivityThreadmain方法

main方法中在上面一篇中也提到过,上次SystemServer启动过程中会调用attach(true)方法,而我们通过Zygote启动的时候,会调用attach(false)这个方法。

public static void main(String[] args) {
    ......
    //主线程
    Looper.prepareMainLooper();
    
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    ......
    //一直循环,如果退出,说明程序关闭
    Looper.loop();
    ......
}
private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        //获取AMS的本地代理类
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            //调用AMS的attachApplication方法
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
       ......
    }
    ......
    ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {......});
}

上面的主要是就是通过Binder调用AMSattachApplication方法。


9. AMS的attachApplication方法

attachApplication中主要是判断当前的Process是否存在,如果存在,则需要将其kill。接着通过thread.bindApplication来将一些需要的变量初始化,进行Application初始化,调用ApplicationonCreate()方法。最后通过mStackSupervisor.attachApplicationLocked(app)方法去真正启动Activity。下面大概看下整个流程:

//这里没啥讲的,就是调用了attachApplicationLocked方法
@Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {

    // Find the application record that is being attached...  either via
    // the pid if we are running in multiple processes, or just pull the
    // next app record if we are emulating process with anonymous threads.
    //从进程中查找是否有,如果有的话去杀掉这个进程
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }

    if (app == null) {
        Slog.w(TAG, "No pending application record for pid " + pid
                + " (IApplicationThread " + thread + "); dropping process");
        EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
        if (pid > 0 && pid != MY_PID) {
            Process.killProcessQuiet(pid);
            //TODO: killProcessGroup(app.info.uid, pid);
        } else {
            try {
                //退出
                thread.scheduleExit();
            } catch (Exception e) {
                // Ignore exceptions.
            }
        }
        return false;
    }

    // If this application record is still attached to a previous
    // process, clean it up now.
    //如果当前的Application记录仍然依附到之前的进程中,则清理掉
    if (app.thread != null) {
        handleAppDiedLocked(app, true, true);
    }

    // Tell the process all about itself.

    if (DEBUG_ALL) Slog.v(
            TAG, "Binding process pid " + pid + " to record " + app);

    final String processName = app.processName;
    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }

    EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

    app.makeActive(thread, mProcessStats);
    app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
    app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    app.forcingToForeground = null;
    updateProcessForegroundLocked(app, false, false);
    app.hasShownUi = false;
    app.debugging = false;
    app.cached = false;
    app.killedByAm = false;

    // We carefully use the same state that PackageManager uses for
    // filtering, since we use this flag to decide if we need to install
    // providers when user is unlocked later
    app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);

    mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
    //mProcessesReady这个变量在AMS的systemReady中被赋值为true,所以这里的normalMode也为true
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    ......
    try {
        int testMode = IApplicationThread.DEBUG_OFF;
        if (mDebugApp != null && mDebugApp.equals(processName)) {
            testMode = mWaitForDebugger
                ? IApplicationThread.DEBUG_WAIT
                : IApplicationThread.DEBUG_ON;
            app.debugging = true;
            if (mDebugTransient) {
                mDebugApp = mOrigDebugApp;
                mWaitForDebugger = mOrigWaitForDebugger;
            }
        }
        String profileFile = app.instrumentationProfileFile;
        ParcelFileDescriptor profileFd = null;
        int samplingInterval = 0;
        boolean profileAutoStop = false;
        if (mProfileApp != null && mProfileApp.equals(processName)) {
            mProfileProc = app;
            profileFile = mProfileFile;
            profileFd = mProfileFd;
            samplingInterval = mSamplingInterval;
            profileAutoStop = mAutoStopProfiler;
        }
        boolean enableTrackAllocation = false;
        if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
            enableTrackAllocation = true;
            mTrackAllocationApp = null;
        }

        // If the app is being launched for restore or full backup, set it up specially
        boolean isRestrictedBackupMode = false;
        if (mBackupTarget != null && mBackupAppName.equals(processName)) {
            isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
                    && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
                            || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
                            || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
        }

        if (app.instrumentationClass != null) {
            notifyPackageUse(app.instrumentationClass.getPackageName(),
                             PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
        }
        if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
                + processName + " with config " + mConfiguration);
        ApplicationInfo appInfo = app.instrumentationInfo != null
                ? app.instrumentationInfo : app.info;
        app.compat = compatibilityInfoForPackageLocked(appInfo);
        if (profileFd != null) {
            profileFd = profileFd.dup();
        }
        ProfilerInfo profilerInfo = profileFile == null ? null
                : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
        //真正执行绑定操作是通过thread的bindApplication方法。
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                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 false;
    }

    // Remove this record from the list of starting applications.
    mPersistentStartingProcesses.remove(app);
    if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
            "Attach application locked removing on hold: " + app);
    mProcessesOnHold.remove(app);

    boolean badApp = false;
    boolean didSomething = false;

    // See if the top visible activity is waiting to run in this process...
    //上面说到,这里为true,进入StackSupervisor的attachApplicationLocked方法去真正启动Activity
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    
    ......

    return true;
}


10. StackSupervisorattachApplicationLocked方法

这个方法会调用realStartActivityLocked方法,去真正启动Activity

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (!isFocusedStack(stack)) {
                continue;
            }
            ActivityRecord hr = stack.topRunningActivityLocked();
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        //真正启动Activity
                        if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                              + hr.intent.getComponent().flattenToShortString(), e);
                        throw e;
                    }
                }
            }
        }
    }
    if (!didSomething) {
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    }
    return didSomething;
}

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
    ......
    try {
        ......
        app.forceProcessStateUpTo(mService.mTopProcessState);
        //最主要的就是这里,也是通过Activity中的方法去启动Activity。
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
        ......
    } catch (RemoteException e) {
        
    }
    ......
    return true;
}

讲到这里基本上启动流程就完成了,后面就是ActivityThread进行Activity的启动过程,这个下次在继续分析。


11. 总结

这里面所有的关于Activity启动,resume,pause等等都是通过ActivityThread来进行操作,而这之中又会涉及到ActivityThread将任务交给Instrumentation去处理。这个处理过程包括了与跨进程与远端的AMS进行通信,AMS又通过ActivityStarter,ActivityStackSupervisor,ActivityStack等进行处理,最终将所启动的Activity真正启动。
其实还有个时序图的,但是太大了,截图也不全,等下次直接上传,方便自己查看。
下面计划分析ActivityThread启动Activity。


12. 写在后面的话

想写关于Activity启动流程想了好久,说实话其中有一部分只能按自己的理解来解释,可能会有一些问题。但是起码自己认为是对的。嗯,这就够了。

标签:task,launcher,流程,HomeActivity,int,mStartActivity,intent,null,app
From: https://www.cnblogs.com/zhanyaowang/p/18292679

相关文章

  • Bullet 学习笔记之 软体仿真流程(二) 软体碰撞检测与响应
    简述Bullet中软体的碰撞检测与响应算法,仅针对Soft类型,Deformable类型不包含在这篇文章中。1.软体碰撞检测在BulletPhysics中,软体的碰撞检测采用的是“点-面”的方法,即分别用两个软体的m_ndbvt和m_fdbvt做碰撞检测,两个bvh树之间的遍历方法不在此展开,当Node......
  • 转-OAuth2.0 原理流程及其单点登录和权限控制
    原文链接单点登录是多域名企业站点流行的登录方式。本文以现实生活场景辅助理解,力争彻底理清OAuth2.0实现单点登录的原理流程。同时总结了权限控制的实现方案,及其在微服务架构中的应用。1什么是单点登录1.1多点登录传统的多点登录系统中,每个站点都实现了本站专用的帐号数......
  • 转-OAuth2.0 原理流程及其单点登录和权限控制
    原文链接单点登录是多域名企业站点流行的登录方式。本文以现实生活场景辅助理解,力争彻底理清OAuth2.0实现单点登录的原理流程。同时总结了权限控制的实现方案,及其在微服务架构中的应用。1什么是单点登录1.1多点登录传统的多点登录系统中,每个站点都实现了本站专用的帐号数......
  • 转-OAuth2.0 原理流程及其单点登录和权限控制
    原文链接单点登录是多域名企业站点流行的登录方式。本文以现实生活场景辅助理解,力争彻底理清OAuth2.0实现单点登录的原理流程。同时总结了权限控制的实现方案,及其在微服务架构中的应用。1什么是单点登录1.1多点登录传统的多点登录系统中,每个站点都实现了本站专用的帐号数......
  • 性能测试:性能测试流程与方法
    简介性能测试流程是指在进行性能测试时所遵循的一系列步骤和阶段,以确保对系统的全面测试和评估。性能测试流程的具体步骤可能会因组织、项目和测试需求而有所不同。性能****测试流程分析现状:首先需要对应用程序或系统进行详细的分析,了解其当前的性能状况、发现性能瓶颈,并确定......
  • 1 python介绍、基本语法、流程控制
     一、Python介绍python的创始人为吉多·范罗苏姆(GuidovanRossum)。1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承。  最新的TIOBE排行榜,Python赶超PHP占据第五, Python崇尚优美、清晰、简单,是......
  • 记录 中**信 ruoyi项目 部署全流程
    零本地环境改为线上环境包括1后端的数据库连接地址2后端的文件存储本地地址3后端的文件存储ip地址4前端baseUrl一后端项目打包双击package二mstsc进入服务器三备份四后端jar包替换五前端文件替换六检查数据库需不需要备份七启动java-jarruoyi-ad......
  • 2024.07.09【读书笔记】|医疗科技创新流程(第二章 创新创造 概念探索与测试案例分析1)
    案例一:Oculeve-神经刺激治疗干眼症背景与挑战干眼症(DryEyeDisease,DED)是一种常见的眼部疾病,影响着数百万美国人的生活质量。该病症由泪液不足或蒸发过快引起,导致眼表炎症、疼痛、灼热感、异物感和视力受损。Oculeve团队认识到,尽管市场上有人工泪液等治疗方法,但这些方......
  • camunda快速入门(四):如何设计一个带条件分支的流程
    在本节中,您将学习如何使用BPMN2.0排他网关(ExclusiveGateways)使流程更加动态。1、添加两个网关我们想修改我们的流程,使其更具动态性。为此,请在CamundaModeler中打开该过程。接下来,从Modeler的左侧菜单中,选择网关形状(菱形)并将其拖动到“开始事件”和“服务任务”之间的......
  • Android 10.0 SystemUI启动流程
    1、手机开机后,Android系统首先会创建一个Zygote(核心进程)。2、由Zygote启动SystemServer。3、SystemServer会启动系统运行所需的众多核心服务和普通服务、以及一些应用及数据。例如:SystemUI启动就是从SystemServer里启动的。4、进入锁屏界面,开机完成。SystemServer中......