AndroidS 源码分析

696 阅读8分钟

Activity 启动流程分析(一)

Android MVC 架构详解_lerendan的博客-CSDN博客_android mvc架构

@UiContext
public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
private IBinder mToken;

Activity是一个可定制资源的上下文,并实现Window,keyEvent的callback接口。 mToken是framework传过来的一个Binder代理对象,是一个句柄。这里仅用作标识,用于在addView添加窗口时,校验其是一个ActivityRecord容器的窗口 startActivity有两种方式: 1.通过Instrumentation对象

mInstrumentation.execStartActivity

2.直接通过ATMS代理对象,这是进程全局的,可通过反射使用

ActivityTaskManager.getService().startActivity

caller是一个代理对象,标识应用侧的主线程(IApplicationThread的实现类是主线程绑定looper的对象) callingPackage是发起startActivity语义的应用包名(一个进程可以有多个应用) intent是欲启动Activity的信息,resolvedType说明欲启动Activity的data类型(注册的IntentFilter) resultTo说明启动结果返回对象。A start B,B可以返回结果给A,这里resultTo便是A bOptions 可以指定欲启动Activity的一些附加信息,如task和window类型,边界rect等。 UserHandle.getCallingUserId()。startActivity是通过Binder 进程间通信的调用的,此时的framework的Binder线程,带有发起者的信息,用于鉴权。 Android支持多用户的,应用在安装时,由PMS分配uid。主用户userId为0。

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

/*
      public static @UserIdInt int getCallingUserId() {
         return getUserId(Binder.getCallingUid());
      }
*/

startActivity的核心逻辑全在以下四句方法:

mService.mGlobalLock是wm锁,故startActivity是线程安全的,多个应用可以同时调用,在系统处理时全程加锁。 在executeRequest中可能需要持有am锁,需小心,避免两个线程相互持锁,从而死锁。 clearCallingIdentity这个的意思,将Binder线程的calluid替换为当前进程的。 restoreCallingIdentity这个的意思,将Binder线程的calluid替换为发起请求进程的。 两者结合使用,以便方法接口权限校验和在本进程使用,避免使用错误身份。

        synchronized (mService.mGlobalLock) {
                final long origId = Binder.clearCallingIdentity();
                res = executeRequest(mRequest);
                Binder.restoreCallingIdentity(origId);

检查调用者信息,aInfo时wm通过pm查找的欲启动Activity的package和class信息,如果找不到,后续会报错。 这里也会检查,欲启动Activity是哪个用户的,启动双开应用,这里会有不同打印。 插件化的思想:在package中注册一些简易的ActivityInfo,以便通过框架这里的校验。

        WindowProcessController callerApp = null;
        if (caller != null) {
            callerApp = mService.getProcessController(caller);
            if (callerApp != null) {
                callingPid = callerApp.getPid();
                callingUid = callerApp.mInfo.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
                        + ") when starting: " + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }
        final int userId = aInfo != null && aInfo.applicationInfo != null
                ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
        if (err == ActivityManager.START_SUCCESS) {
            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
                    + "} from uid " + callingUid);
        }

校验result传递:A启动B,B启动C

A启动B时,A请求B返回结果(requestCode >= 0)B的resultTo为A,则B的resultRecord为A, 若此时B再启动C,B仅是跳转,(!(requestCode >= 0)),则C的resultRecord为B的resultTo,即A 注意B不能同时带FLAG_ACTIVITY_FORWARD_RESULT和(requestCode >= 0),同时声明转发和返回结果,语义冲突!

        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = mRootWindowContainer.isInAnyTask(resultTo);
            if (DEBUG_RESULTS) {
                Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
            }
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }

        final int launchFlags = intent.getFlags();
        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            resultRecord = sourceRecord.resultTo;

startActivityUnchecked

deferWindowLayout 显式声明延迟布局,直到下一个continueWindowLayout语句,这段期间都延迟布局,除非force。这块在WindowSurfacePlacer中实现。

        try {
            mService.deferWindowLayout();
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
        } finally {
            startedActivityRootTask = handleStartResult(r, result);
            mService.continueWindowLayout();

startActivityInner

主要的处理逻辑便是根据各种条件,如何为一个ActivityRecord选择一个合适的rootTask

setInitialState
computeLaunchingTaskFlags
computeSourceRootTask // 计算mSourceRootTask
setInitialState

这里会mStartActivity = r;计算mStartActivity 的windowingMode及其Bound

        // Preferred display id is the only state we need for now and it could be updated again
        // after we located a reusable task (which might be resided in another display).
        mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
                sourceRecord, options, mRequest, PHASE_DISPLAY, mLaunchParams);
        mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea()
                ? mLaunchParams.mPreferredTaskDisplayArea
                : mRootWindowContainer.getDefaultTaskDisplayArea();
        mPreferredWindowingMode = mLaunchParams.mWindowingMode;

computeLaunchingTaskFlags

根据mSourceRecord和mInTask,LaunchMode来计算LaunchFlag

if (mSourceRecord == null && mInTask != null && mInTask.getRootTask() != null) {

mSourceRecord == null说明,该次不是由一个Activity发起,mInTask != null说明指定了一个task参考来放置Activity。

从应用侧而言,可由getAppliaction().startActivity();从system来说,没有上下文限制,但一般都是由uiContext发起

getReusableTask

Activity有四种启动模式,是在这里对应用的声明进行选择的

		if (putIntoExistingTask) {
            if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
                // There can be one and only one instance of single instance activity in the
                // history, and it is always in its own unique task, so we do a special search.
                intentActivity = mRootWindowContainer.findActivity(mIntent, mStartActivity.info,
                       mStartActivity.isActivityTypeHome());

reusedTask是否找到一个已有的task可以将待启动的Activity加入其中,若找不到,则根据计算一个新的,可能为null

是否需要newTask,这是一个final字段。

        // Compute if there is an existing task that should be used for.
        final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
        final boolean newTask = targetTask == null;
        mTargetTask = targetTask;

mStartActivity.resultTo == null,说明这个mStartActivity不需要返回结果,mInTask是否有声明一个参考task,

mAddingToTask说明,mStartActivity并没有加入一个task之中, 应用有指定了FLAG_ACTIVITY_NEW_TASK。这里有一点值得注意:同一个task才能返回结果

例如:在微信中设置头像,选择图库的照片,但如果此时图库的task与微信的task不是一个,此时,设置头像是不会返回结果的。有这段代码判断的:

    private void sendNewTaskResultRequestIfNeeded() {
        if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            // For whatever reason this activity is being launched into a new task...
            // yet the caller has requested a result back.  Well, that is pretty messed up,
            // so instead immediately send back a cancel and let the new task continue launched
            // as normal without a dependency on its originator.
            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
            mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho,
                    mStartActivity.requestCode, RESULT_CANCELED,
                    null /* data */, null /* dataGrants */);
            mStartActivity.resultTo = null;
        }
    }
    private Task computeTargetTask() {
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            // A new task should be created instead of using existing one.
            return null;
        } else if (mSourceRecord != null) {
            return mSourceRecord.getTask();
        } else if (mInTask != null) {
            return mInTask;
        } else {
            final Task rootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, null /* task */,
                    mOptions);
            final ActivityRecord top = rootTask.getTopNonFinishingActivity();
            if (top != null) {
                return top.getTask();
            } else {  // 这说明该task是一个空的task,列表中里面没有Activity
                // Remove the root task if no activity in the root task.
                rootTask.removeIfPossible("computeTargetTask");
            }
        }
        return null;
    }

computeLaunchParams

在已计算targetTask之后,说明mStartActivity是加入该targetTask的。这时再重新计算一遍mLaunchParams

如果sourceRootTask.inSplitScreenWindowingMode为true,mStartActivity的windowingMode需要和sourceRootTask保持一致。

其实也可以做实验:sourceRootTask在Primary,mStartActivity debug到Secondary,也是可以的。

如freefrom小窗,则可以在calculate进行计算

        if (newTask) { // mTargetRootTask.reuseOrCreateTask
            setNewTask(taskToAffiliate);
        } else if (mAddingToTask) {
            addOrReparentStartingActivity(targetTask, "adding to task");
        }

Task有一个mChildren的列表,里面的元素是ActivityRecord

startActivity分为两步: 将一个Activity加入到一个合适Task,作为其最后的子节点 再选择一个task作为focus,调度Task

    private void addOrReparentStartingActivity(Task parent, String reason) {
        if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
            parent.addChild(mStartActivity);
        } else {
            mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);
        }
    }

setAlwaysOnTop说明该Task总是显示在上层。同类型的task,new的在上层

dream>pip>freefrom>alwaysOnTop

            mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
            if (mOptions != null) {
                if (mOptions.getTaskAlwaysOnTop()) {
                    mTargetRootTask.setAlwaysOnTop(true);
                }
            }

S上Task分为rootTask(ActivityStack)和leafTask(Task)

startActivityLocked

mTargetRootTask.startActivityLocked

RootTask也有一个mChildren列表,子节点是Task。故这里需要将mStartActivity所在的task移到top(列表最后一个)

allowMoveToFront 准备一个切换动画。注意前面有mService.deferWindowLayout();故只是声明,并不是立马执行

showStartingWindow,同时添加一个启动窗口。启动窗口是system直接addView的,比Activity的生命周期调度要快,给用户流畅的视效

        if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) {
            positionChildAtTop(rTask);
        }
// r应该是下个用户看到的界面,如果其所在的Task,在调度之前,有另外的Activity在r之前,则需要再次将r移到top
// 
final ActivityRecord occludingActivity = getOccludingActivityAbove(r);
rTask.positionChildAtTop(r);

//再次将r移到top // 显然,如果r已是top,这次调用也无妨
task.positionChildAtTop(r);

if ((!isHomeOrRecentsRootTask() || hasActivity()) && allowMoveToFront) {

mTargetRootTask将其移到top

mRootWindowContainer.resumeFocusedTasksTopActivities 这是调度Task的入口,可以指定mTargetRootTask


                // If the target root-task was not previously focusable (previous top running
                // activity on that root-task was not visible) then any prior calls to move the
                // root-task to the will not update the focused root-task.  If starting the new
                // activity now allows the task root-task to be focusable, then ensure that we
                // now update the focused root-task accordingly.
                if (mTargetRootTask.isTopActivityFocusable()
                        && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
                    mTargetRootTask.moveToFront("startActivityInner");
                }
                mRootWindowContainer.resumeFocusedTasksTopActivities(
                        mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
            }

resumeTopActivityUncheckedLocked

将栈顶的Activity,调度到resume生命周期

mInResumeTopActivity 防止重复迭代调用

第一次isLeafTask为false,在mChildren,从上到下开始遍历,再次调用child的方法,从而走到resumeTopActivityInnerLocked

看注释,存在数组越界的异常,不知道是什么样的场景下的异常

锁屏休眠时,startActivity,并不一定保证,该Activity能立马展现给用户。如果不能点亮屏幕,则system会再次休眠。

checkReadyForSleep会将所有的Activity调度到stop状态

比如来电时,就有可能存在不亮屏的故障。

    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
        if (mInResumeTopActivity) {
            return false;
        }

        boolean someActivityResumed = false;
        try {
            mInResumeTopActivity = true;
            if (isLeafTask()) {
                if (isFocusableAndVisible()) { 
                    someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
                }
            } else {
                int idx = mChildren.size() - 1;
                while (idx >= 0) {
                    final Task child = (Task) getChildAt(idx--);
                    if (!child.isTopActivityFocusable()) {
                        continue;
                    }
                    if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) {
                        break;
                    }

                    someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
                            deferPause);

                    if (idx >= mChildren.size()) {
                        idx = mChildren.size() - 1;
                    }
                }
            }

            final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mInResumeTopActivity = false;
        }

        return someActivityResumed;
    }

resumeTopActivityInnerLocked

R上,mTopActivityOccludesKeyguard是一个缓存值,在一些情况下会判断错误。S上已没有该mTopActivityOccludesKeyguard变量,在keyguardController使用实时计算值

在Resume某个Activity之前,需要将所有的Activity,置于pause,allPausedComplete

若Activity所在的进程还没有,则会异步启动进程,返回。待进程启动后,会立马再次resume对应的Activity

​ if (next.attachedToProcess()) { 走到这,说明应用的进程已经启动

        if (pausing) {

            if (next.attachedToProcess()) {
                next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
            } else if (!next.isProcessRunning()) {
                final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
                mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
                        isTop ? "pre-top-activity" : "pre-activity");
            }
            return true;

next从这里开始可见,会将next加入open列表中

ResumeActivityItem Binder进程间通信,最终会走到ActivityThread类中

hasBeenLaunched说明启动出现错误,再次启动一次startSpecificActivity

            // This activity is now becoming visible.
            if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
                next.setVisibility(true);
            }

                transaction.setLifecycleStateRequest(
                        ResumeActivityItem.obtain(next.app.getReportedProcState(),
                                dc.isNextTransitionForward()));
                mAtmService.getLifecycleManager().scheduleTransaction(transaction);

                if (!next.hasBeenLaunched) {
                    next.hasBeenLaunched = true;
                }
                mTaskSupervisor.startSpecificActivity(next, true, false);