Activity的启动过程(2)

时间:2022-04-15 15:38:56

Activity启动流程(1)中,Activity的启动经过binder通信就会进入ActivityManagerService所在的进程中继续执行startActivity方法,由于后续的方法涉及的逻辑比较多,在后面的分析中我可能会把某一个函数单独拿出来分析,最后我会做一个启动流程的总结。
ok,接下来看下startActivity的实现:

ActivityManangerService类startActivity

public final int startActivity(IApplicationThread caller,
        Intent intent, String resolvedType, Uri[] grantedUriPermissions,
        int grantedMode, IBinder resultTo,
        String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
        String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
    return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
            grantedUriPermissions, grantedMode, resultTo, resultWho,
            requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler,
            null, null);
}  

可以发现,这一步其实什么操作都没有做,只是将调用转发给了mMainStack,然后执行了startActivityMayWait方法。如果对参数的值记得不是很清晰的,可以看下Activity的启动流程(1)

接下来就要真的开始真正进入分析正题了。ActivityStack.java位于的源码路径为frameworks/base/services/java/com/android/server/am/ActivityStack.java,看下mStack.startActivityMayWait:

ActivityStack类startActivityMayWait

final int startActivityMayWait(IApplicationThread caller, int callingUid,
        Intent intent, String resolvedType, Uri[] grantedUriPermissions,
        int grantedMode, IBinder resultTo,
        String resultWho, int requestCode, boolean onlyIfNeeded,
        boolean debug, String profileFile, ParcelFileDescriptor profileFd,
        boolean autoStopProfiler, WaitResult outResult, Configuration config) {
    // Refuse possible leaked file descriptors
    if (intent != null && intent.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }
    /**intent.getComponent != null componentSpecified = true*/
    boolean componentSpecified = intent.getComponent() != null;

    // Don't modify the client's object!
    intent = new Intent(intent);

    // Collect information about the target of the Intent.
    /**获得即将启动的activity的信息*/
    ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
            profileFile, profileFd, autoStopProfiler);

    /**启动activity时对ActivityManagerService作同步*/
    synchronized (mService) {
        int callingPid;
        if (callingUid >= 0) {
            callingPid = -1;
        } else if (caller == null) {
            callingPid = Binder.getCallingPid();
            callingUid = Binder.getCallingUid();
        } else {
            callingPid = callingUid = -1;
        }
        //callingPid = callingUid = -1
        mConfigWillChange = config != null
                && mService.mConfiguration.diff(config) != 0;
        if (DEBUG_CONFIGURATION) Slog.v(TAG,
                "Starting activity when config will change = " + mConfigWillChange);
        //mConfigWillChange = false
        //清除调用者的pid和uid,准备调用本进程内的函数 
        final long origId = Binder.clearCallingIdentity();
        /**mMainStack在ActivityManangerService创建ActivityStack实例时被赋值为true*/
        if (mMainStack && aInfo != null &&
                (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
            ......
        }

        int res = startActivityLocked(caller, intent, resolvedType,
                grantedUriPermissions, grantedMode, aInfo,
                resultTo, resultWho, requestCode, callingPid, callingUid,
                onlyIfNeeded, componentSpecified, null);

        ......
}

这部分还是比较好理解的,我把和流程无关紧要的代码注释掉了。intent.getComponent() != null,故componentSpecified = true;接下来就是调用resolveActivity方法获取即将启动的Activity信息aInfo,aInfo的信息主要是从AndroidManifest.xml中获取,resolveActivity的具体实现,可以参考resolveActivity解析;接下来会设置callingUid和callingPid,从上一步可知,callingUid为-1且caller != null,故最后得到callingPid = callingUid = -1;config = null,故mConfigWillChange = false。接下来就会进入startActivityLocked函数。

ActivityStack类startActivityLocked

final int startActivityLocked(IApplicationThread caller,
        Intent intent, String resolvedType,
        Uri[] grantedUriPermissions,
        int grantedMode, ActivityInfo aInfo, IBinder resultTo,
        String resultWho, int requestCode,
        int callingPid, int callingUid, boolean onlyIfNeeded,
        boolean componentSpecified, ActivityRecord[] outActivity) {

    int err = START_SUCCESS;
    ProcessRecord callerApp = null;
    /**根据传入的IApplicationThread构建应用的ProcessRecord*/
    if (caller != null) {
        callerApp = mService.getRecordForAppLocked(caller);
        if (callerApp != null) {
            callingPid = callerApp.pid;
            callingUid = callerApp.info.uid;
        } else {
            Slog.w(TAG, "Unable to find app for caller " + caller
                  + " (pid=" + callingPid + ") when starting: "
                  + intent.toString());
            err = START_PERMISSION_DENIED;
        }
    }

    if (err == START_SUCCESS) {
        Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid "
                + (callerApp != null ? callerApp.pid : callingPid));
    }

    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    if (resultTo != null) {
        int index = indexOfTokenLocked(resultTo);
        if (DEBUG_RESULTS) Slog.v(
            TAG, "Will send result to " + resultTo + " (index " + index + ")");
        if (index >= 0) {
            /**requestCode >= 0表示需要启动的Actvity给父Activity返回结果,故sourceRecord和resultRecode相同*/
            sourceRecord = mHistory.get(index);
            if (requestCode >= 0 && !sourceRecord.finishing) {
                resultRecord = sourceRecord;
            }
        }
    }
    /**resultRecord = null*/
    int launchFlags = intent.getFlags();

    if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
            && sourceRecord != null) {
       ......
    }
    //代码块1
    /**未找到要启动的Activity组建信息*/
    if (err == START_SUCCESS && intent.getComponent() == null) {
        // We couldn't find a class that can handle the given Intent.
        // That's the end of that!
        err = START_INTENT_NOT_RESOLVED;
    }

    //代码块2
    /**根据提供的条件,未解析成功Activty信息*/
    if (err == START_SUCCESS && aInfo == null) {
        // We couldn't find the specific class specified in the Intent.
        // Also the end of the line.
        err = START_CLASS_NOT_FOUND;
    }
    //代码块3
    if (err != START_SUCCESS) {
        if (resultRecord != null) {
            sendActivityResultLocked(-1,
                resultRecord, resultWho, requestCode,
                Activity.RESULT_CANCELED, null);
        }
        mDismissKeyguardOnNextActivity = false;
        return err;
    }

    //代码块4
    /**检查启动Activity进行的权限信息*/
    final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
            callingUid, aInfo.applicationInfo.uid, aInfo.exported);
    if (perm != PackageManager.PERMISSION_GRANTED) {
       ......
    }

    ......

    ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
            intent, resolvedType, aInfo, mService.mConfiguration,
            resultRecord, resultWho, requestCode, componentSpecified);
   ......

    err = startActivityUncheckedLocked(r, sourceRecord,
            grantedUriPermissions, grantedMode, onlyIfNeeded, true);
    ......
    return err;
}  

这部分代码理解起来不复杂,我在代码中也进行了注视。startActivityLocked函数的主要作用就是构建ActivityRecord信息,准备为下一步Activity Task的创建和复用做准备。函数一开始根据启动目标Activity的进程(由于我们是在手机桌面启动了应用)构建ProcessRecord,这里的ProcessRecord指向就是Launcher所在的进程;接着使用构建的ProcessRecord callerApp获取callingUid和callingPid,如果记得清楚的话,在此步骤之前,callingUid和callingPid一直为-1,到了这一步才被真正赋值;尝试获取sourceRecord和resultRecord,mHistory保存所有之前启动过的Activity,由于Launcher已经启动,故sourceRecord表示Launcher,由于requestCode = -1故resultRecord=null;代码块1会判断能否根据intent找到要启动的Activity的组建信息,如果未找到,则err = START_INTENT_NOT_RESOLVED;代码块2会判断能否解析要启动的Activity信息,如果不能解析,则err = START_CLASS_NOT_FOUND;代码块3判断经过前面的判断之后,如果err != START_SUCCESS,则返回错误码。

进过上面的处理后,系统会去判断启动此Activity的进程的权限,如果未能通过验证,则会返回权限异常,权限部分会在后续文章中进行分析。过程中还有其他无关流程的处理我就省略掉了,接下来就会根据之前的信息构造即将要启动的Activity的ActivityRecord,然后去调用startActivityUncheckedLocked

ActivityStack类startActivityUncheckedLocked

final int startActivityUncheckedLocked(ActivityRecord r,
        ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
        int grantedMode, boolean onlyIfNeeded, boolean doResume) {
    final Intent intent = r.intent;
    final int callingUid = r.launchedFromUid;

    int launchFlags = intent.getFlags();

    // We'll invoke onUserLeaving before onPause only if the launching
    // activity did not explicitly state that this is an automated launch.
    //代码块1
    mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;

由于要启动的Activity未置位Intent.FLAG_ACTIVITY_NO_USER_ACTION,故mUserLeaving = true。

    if (!doResume) {
       ......
    }
    //r.delayResume = true
    ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
            != 0 ? r : null;
    //notTop = null
    // If the onlyIfNeeded flag is set, then we can do this if the activity
    // being launched is the same as the one making the call...  or, as
    // a special case, if we do not know the caller then we count the
    // current top activity as the caller.
    if (onlyIfNeeded) {
       ......
    }

    if (sourceRecord == null) {
       ......
    } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        // The original activity who is starting us is running as a single
        // instance...  this new activity it is starting must go on its
        // own task.
        //代码块1
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
  }   else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
        // The activity being started is a single instance...  it always
        // gets launched into its own task.
        //代码块2
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }

    if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
              ......
              //代码块3
    }
    boolean addingToTask = false;
    TaskRecord reuseTask = null;
    if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
         //代码块4
       if (r.resultTo == null) {
            // See if there is a task to bring to the front.  If this is
            // a SINGLE_INSTANCE activity, there can be one and only one
            // instance of it in the history, and it is always in its own
            // unique task, so we do a special search.
            ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
                    ? findTaskLocked(intent, r.info)
                    : findActivityLocked(intent, r.info);
            if (taskTop != null) {
               ......
               //代码块5
             }
    }

从前面的分析可知,doResue = true,notTop = null;onlyIfNeeded = false;sourceRecord != null;代码块1会对sourecRecord的launchMode进行判断,由于sourceRecord代表的是Launcher,Launcher的launchMode为SINGLE_INSTANCE,故在代码块1会对launchFlags添加Intent.FLAG_ACTIVITY_NEW_TASK的标志。代码块2会对即将启动的Activity的launchMode进行判断,由于我们在新建Activity时并没有执行launchMode,launchMode为STAND,故不会进入代码块2执行;由之前的分析可知r.resultTo = null,故代码块3也不会执行;由于在代码块1中LAUNCH_SINGLE_TASK被置位,个程序会进入代码块4中执行;根据之前的分析r.resultTo = null,由于r.launchMode != LAUNCH_SINGLE_INSTANCE,故程序会执行findTaskLocked函数,并将结果赋值给taskTop,由于即将要启动的Activity的launchMode被设置为LAUNCH_SINGLE_TASK,故在系统中中无法找到可以启动目标Activity的ActivityRecord,故taskTop = null,故代码块5不会被执行

    boolean newTask = false;
    boolean keepCurTransition = false;

    // Should this be considered a new task?
    if (r.resultTo == null && !addingToTask
            && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        if (reuseTask == null) {
            //代码块1
            // todo: should do better management of integers.
            mService.mCurTask++;
            if (mService.mCurTask <= 0) {
                mService.mCurTask = 1;
            }
            r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in new task " + r.task);
        } else {
            r.setTask(reuseTask, reuseTask, true);
        }
        newTask = true;
       .....

    } else if (sourceRecord != null) {
        //代码块2
       ......
    } else if (!addingToTask &&
                (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
      //代码块3
       ......

    } else {
     //代码块4
       ......
    }

   ......
   startActivityLocked(r, newTask, doResume, keepCurTransition);  

根据前面的分析可知,r.resultTo = null ,addingToTask = false且launchFlags的FLAG_ACTIVITY_NEW_TASK被置为,故代码块1会被执行,代码块2,3,4均不会被执行,接下来就好好分析下代码块1。

经过之前的分析可知,需要心的Activity Task来启动目标Activity,mService为ActivityManagerService实例,mCurTask表示当前task的数量,在新建task之前先修改mCurTask的值,使其加1,然后为目标Activity的ActivityRecord设置新的的TaskRecord,并设置newTask = true,接下来就会去执行startActivityLocked函数了,这个startActivityLocked函数是之前startActivity函数的重载形式。

ActivityStack类startActivityLocked

private final void startActivityLocked(ActivityRecord r, boolean newTask,
        boolean doResume, boolean keepCurTransition) {
    final int NH = mHistory.size();
    int addPos = -1;
    if (!newTask) {
        //代码块1
        .......
    }
    if (addPos < 0) {
        addPos = NH;
    }
    if (addPos < NH) {
       ......
    }
    mHistory.add(addPos, r);
    r.putInHistory();
    r.frontOfTask = newTask;
    if (NH > 0) {
        // We want to show the starting preview window if we are
        // switching to a new task, or the next activity's process is
        // not currently running.
        boolean showStartingIcon = newTask;
        ProcessRecord proc = r.app;
        if (proc == null) {
            proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
        }
        if (proc == null || proc.thread == null) {
            showStartingIcon = true;
        }
        if (DEBUG_TRANSITION) Slog.v(TAG,
                "Prepare open transition: starting " + r);
        if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
            mService.mWindowManager.prepareAppTransition(
                    WindowManagerPolicy.TRANSIT_NONE, keepCurTransition);
            mNoAnimActivities.add(r);
        } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
            mService.mWindowManager.prepareAppTransition(
                    WindowManagerPolicy.TRANSIT_TASK_OPEN, keepCurTransition);
            mNoAnimActivities.remove(r);
        } else {
            mService.mWindowManager.prepareAppTransition(newTask
                    ? WindowManagerPolicy.TRANSIT_TASK_OPEN
                    : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
            mNoAnimActivities.remove(r);
        }
        mService.mWindowManager.addAppToken(
                addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
        boolean doShow = true;
        if (newTask) {
            // Even though this activity is starting fresh, we still need
            // to reset it to make sure we apply affinities to move any
            // existing activities from other tasks in to it.
            // If the caller has requested that the target task be
            // reset, then do so.
            if ((r.intent.getFlags()
                    &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                resetTaskIfNeededLocked(r, r);
                doShow = topRunningNonDelayedActivityLocked(null) == r;
            }
        }
        if (SHOW_APP_STARTING_PREVIEW && doShow) {
            // Figure out if we are transitioning from another activity that is
            // "has the same starting icon" as the next one.  This allows the
            // window manager to keep the previous window it had previously
            // created, if it still had one.
            ActivityRecord prev = mResumedActivity;
            if (prev != null) {
                // We don't want to reuse the previous starting preview if:
                // (1) The current activity is in a different task.
                if (prev.task != r.task) prev = null;
                // (2) The current activity is already displayed.
                else if (prev.nowVisible) prev = null;
            }
            mService.mWindowManager.setAppStartingWindow(
                    r, r.packageName, r.theme,
                    mService.compatibilityInfoForPackageLocked(
                            r.info.applicationInfo), r.nonLocalizedLabel,
                    r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
        }
    } else {
        ......
    }
    if (VALIDATE_TOKENS) {
        ......
    }

    if (doResume) {
        resumeTopActivityLocked(null);
    }
}