Android 进阶解密:根 Activity 启动过程

2023-10-26

一、根 Activity 启动过程

可以分为三个部分:
① Launcher 请求 AMS 过程
② AMS 到 ApplicationThread 的调用过程
③ ActivityThread 启动 Activity

二、Launcher 启动 AMS 过程

在桌面点击应用图标,会调用 Launcher#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 ? getActivityLaunchOptions(v) : null;

    UserHandle user = item == null ? null : item.user;

    // Prepare intent
    // 准备 Intent,启动模式 Flag 设置成 NEW_TASK
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (v != null) {
        intent.setSourceBounds(getViewBounds(v));
    }
    try {
        if (Utilities.ATLEAST_MARSHMALLOW && (item instanceof ShortcutInfo) && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) && !((ShortcutInfo) item).isPromise()) {
            // 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
            // 调用此方法(在 Activity 中实现)
            startActivity(intent, optsBundle);
        } else {
            LauncherAppsCompat.getInstance(this).startActivityForProfile(
                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
        }
        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;
}

@Activity#startActivity(Intent intent, Bundle options):

public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        // 调用此方法
        startActivityForResult(intent, -1, options);
    } else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}

@Activity#startActivityForResult(…):

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        // 调用 Instrumentation#execStartActivity(...) 方法
        Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
        }
        if (requestCode >= 0) {
            // If this start is requesting a result, we can avoid making
            // the activity visible until the result is received.  Setting
            // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
            // activity hidden during this time, to avoid flickering.
            // This can only be done when a result is requested because
            // that guarantees we will get information back when the
            // activity is finished, no matter what happens to it.
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
        // TODO Consider clearing/flushing other event sources and events for child windows.
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            // Note we want to go through this method for compatibility with
            // existing applications that may have overridden it.
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}

@Instrumentation#execStartActivity(…):

  • Instrumentation 主要用来监控应用程序和系统的交互
  • 在 ActivityThread#performLaunchActivity() 方法中被赋值,此时 Activity 还没有回调 onCreate() 方法
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                ActivityResult result = null;
                if (am.ignoreMatchingSpecificIntents()) {
                    result = am.onStartActivity(intent);
                }
                if (result != null) {
                    am.mHits++;
                    return result;
                } else if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        // 1. ActivityManager.getService():获取 AMS 代理对象
        // 2. AMS#startActivity():调用 AMS 代理对象的 startActivity() 方法
        int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

@ActivityManager#getService():

public static IActivityManager getService() {
    // IActivityManagerSingleton 是 Singleton 类实例
    // 调用 Singleton#get()
    return IActivityManagerSingleton.get(); // get() 方法会调用 Singleton#create() 方法
}

// IActivityManagerSingleton 是 Singleton 类实例,泛型传入 IActivityManager
private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() {
    @Override
    protected IActivityManager create() {
        // 获取 AMS 的引用
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
        // 获取 AMS 在本地的代理
        final IActivityManager am = IActivityManager.Stub.asInterface(b);
        return am;
    }
};

@Singleton#get():

public abstract class Singleton<T> {
    private T mInstance;

    // Singleton 实现类要实现 create() 方法
    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                // get() 方法会调用 create() 方法
                mInstance = create();
            }
            return mInstance;
        }
    }
}

@ActivityManagerService#startActivity(…):

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

三、AMS 到 ApplicationThread 的调用过程

@ActivityManagerService#startActivity(…):

public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    // 调用 ActivityManagerService#startActivityAsUser()
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId());
}

@ActivityManagerService#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) {
    // 判断调用者是否被进程隔离
    // 如果被隔离,则抛 SecurityException 异常,提示 "Isolated process not allowed to call startActivity"
    enforceNotIsolatedCaller("startActivity");
    // 判断调用者权限,如果没权限,也会抛出 SecurityException 异常
    userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    // 调用 ActivityStarter#startActivityMayWait()
    return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, null, null, bOptions, false, userId, null, null, "startActivityAsUser");
}

@ActivityStarter#startActivityMayWait(…):

final 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, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {
    ...
    // 调用此方法
    int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
            aInfo, rInfo, voiceSession, voiceInteractor,
            resultTo, resultWho, requestCode, callingPid,
            callingUid, callingPackage, realCallingPid, realCallingUid,
            startFlags, options, ignoreTargetSecurity, componentSpecified,
            // 倒数第二个参数 inTask,代表要启动的 Activity 所在的栈,类型为 TaskRecord
            // 倒数第一个参数 reason,代表启动理由,上面传入的是 "startActivityAsUser"
            outRecord, container, inTask, reason);
    ...
    return res;
    }
}

@ActivityStarter#startActivityLocked(…):

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, String reason) {
    // 判断启动的理由是否为空
    if (TextUtils.isEmpty(reason)) {
        // 启动理由为空,抛 IllegalArgumentException 异常
        throw new IllegalArgumentException("Need to specify a reason.");
    }
    mLastStartReason = reason;
    mLastStartActivityTimeMs = System.currentTimeMillis();
    mLastStartActivityRecord[0] = null;
    // 调用此方法
    mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
            aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
            callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
            options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
            container, inTask);

    if (outActivity != null) {
        // mLastStartActivityRecord[0] is set in the call to startActivity above.
        outActivity[0] = mLastStartActivityRecord[0];
    }
    return mLastStartActivityResult;
}

@ActivityStarter#startActivity(…):

private int startActivity(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;
    // Pull the optional Ephemeral Installer-only bundle out of the options early.
    final Bundle verificationBundle = options != null ? options.popAppVerificationBundle() : null;

    ProcessRecord callerApp = null;
    // 判断 IApplicationThread 类型的 caller(对应 Launcher 所在的应用程序进程的 ApplicationThread 对象)是否为空
    if (caller != null) {
        // mService 类型是 ActivityManagerService
        // 调用 AMS#getRecordForAppLocked() 得到 callerApp 对象,类型是 ProcessRecord
        // ProcessRecord 用于描述一个应用程序进程
        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 = ActivityManager.START_PERMISSION_DENIED;
        }
    }
    ...
    // 创建 ActivityRecord,记录将要启动的 Activity 的信息
    // ActivityRecord 用于描述一个 Activity,记录一个 Activity 的所有信息
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
            callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
            resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
            mSupervisor, container, options, sourceRecord);
    if (outActivity != null) {
        // 把 r(ActivityRecord 类型)赋值给 outActivity(ActivityRecord[] 类型)
        outActivity[0] = r;
    }
    
    doPendingActivityLaunchesLocked(false);

    // 调用此方法
    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
            options, inTask, outActivity);
}

@ActivityStarter#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);
    }
    ...
    return result;
}

@ActivityStarter#startActivityUnchecked(…):

  • 处理与栈相关的逻辑
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
    ...
    ActivityRecord reusedActivity = getReusableIntentActivity();
    ...
    if (reusedActivity != 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(reusedActivity.getTask(),
                    (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.getTask() == null) {
            mStartActivity.setTask(reusedActivity.getTask());
        }
        if (reusedActivity.getTask().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.
            reusedActivity.getTask().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.
        if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || isDocumentLaunchesIntoExisting(mLaunchFlags)
                    || mLaunchSingleInstance || mLaunchSingleTask) {
            final TaskRecord task = reusedActivity.getTask();

            // 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 = task.performClearTaskForReuseLocked(mStartActivity, mLaunchFlags);

            // The above code can remove {@code reusedActivity} from the task, leading to the
            // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
            // task reference is needed in the call below to
            // {@link setTargetStackAndMoveToFrontIfNeeded}.
            if (reusedActivity.getTask() == null) {
                reusedActivity.setTask(task);
            }

            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.getTask().setIntent(mStartActivity);
                }
                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
            }
        }

    // 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.topActivity();
    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.getTask());
        // 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;
        }
        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.getTask(), preferredLaunchStackId,
                    preferredLaunchDisplayId, topStack.mStackId);

        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
                // 根 Activity 的 Intent 的 Flag 为 FLAG_ACTIVITY_NEW_TASK
                // 此判断条件满足
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        // 创建新的 TaskRecord,用来描述一个 Activity 任务栈
        result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, preferredLaunchStackId, 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;
    }
    ...
    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
            ...
        } else {
            if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                mTargetStack.moveToFront("startActivityUnchecked");
            }
            // 调用此方法
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions);
        }
    } else {
        mTargetStack.addRecentActivityLocked(mStartActivity);
    }
    ...
    return START_SUCCESS;
}

@ActivityStackSupervisor#resumeFocusedStackTopActivityLocked(…):

/** The stack currently receiving input or launching the next activity.*/
// 接收输入事件或启动下一个 Activity 的栈
ActivityStack mFocusedStack;

boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    // 获取要启动的 Activity 所在栈中位于栈顶,且不是停止状态的 ActivityRecord
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    // 获取的 ActivityRecord 为 null,或 Activity 的状态不是 RESUMED 状态
    // 对应即将要启动的 Activity,此处判断条件满足
    if (r == null || r.state != RESUMED) {
        // 调用此方法
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    } else if (r.state == RESUMED) {
        mFocusedStack.executeAppTransition(targetOptions);
    }
    return false;
}

@ActivityStack#resumeTopActivityUncheckedLocked(…):

 /** Run all ActivityStacks through this */
 // 通过 mStackSupervisor 对象运行所有 ActivityStack
 protected final ActivityStackSupervisor mStackSupervisor;

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    if (mStackSupervisor.inResumeTopActivity) {
        // Don't even start recursing.
        return false;
    }

    boolean result = false;
    try {
        // Protect against recursion.
        mStackSupervisor.inResumeTopActivity = true;
        // 调用此方法
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }
    mStackSupervisor.checkReadyForSleepLocked();

    return result;
}

@ActivityStack#resumeTopActivityInnerLocked(…):

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    ...
    boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
    final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0
                && !lastResumedCanPip;
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
        if (mResumedActivity != null) {
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }
    ...
    if (next.app != null && next.app.thread != null) {
        ...
        try {
           ...
            next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                        mService.isNextTransitionForward(), resumeAnimOptions);
        } catch (Exception e) {
            ...
            mStackSupervisor.startSpecificActivityLocked(next, true, false);
            ...
        }
        ...
    } else {
        ...
        // 调用此方法
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }

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

@ActivityStackSupervisor#startSpecificActivityLocked(…):

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    // 获取即将启动的 Activity 所在的应用程序进程
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

    r.getStack().setLaunchTime(r);

    // 若要启动的 Activity 所在的应用程序进程不为 null,且进程对应的 thread(IApplicationThread 类型)不为 null
    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.versionCode,
                            mService.mProcessStats);
            }
            // 情况一:调用此方法,启动 Activity
            // 第二个参数传入要启动的 Activity 所在的应用程序进程
            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.
    }
    // 情况二:此时代表要启动的 Activity 所在的应用程序进程不存在
    // 调用 ActivityManagerService#startProcessLocked() 方法
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
}

情况一:要启动的 Activity 所在的应用程序进程存在
@ActivityStackSupervisor#realStartActivityLocked(…):

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
    // app:要启动的 Activity 所在的应用程序进程(ProcessRecord 类型)
    // app.thread:IApplicationThread(对应实现是 ActivityThread 内部类 ApplicationThread)
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info,
                mergedConfiguration.getGlobalConfiguration(),
                mergedConfiguration.getOverrideConfiguration(), r.compat,
                r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                r.persistentState, results, newIntents, !andResume,
                mService.isNextTransitionForward(), profilerInfo);
    ...
    return true;
}

至此,app.thread.scheduleLaunchActivity(...) 代码逻辑运行在 ActivityManagerService 所在的进程(SystemServer),app 对应应用程序进程,app.thread 对应 ActivityThread 内部类 ApplicationThread,ApplicationThread 是 ActivityManagerService 所在进程(SystemServer)和应用程序进程通信的桥梁

情况二:要启动的 Activity 所在的应用程序进程不存在
@ActivityManagerService#startProcessLocked(…):

final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
}

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) {
    ...            
    startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
    ...
}

@ActivityManagerService#startProcessLocked(…):

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    ...
    // 启动 Activity 所属的应用进程流程:调用 Zygote,通过 socket 通信的方式让 Zygote 进程 fork 出一个新进程,并根据字符串 "android.app.ActivityThread" 反射出 ActivityThread 实例,接着调用其 main() 方法。至此,应用进程已经启动,只不过还没执行相应的初始化操作
    startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
            app.info.dataDir, invokeWith, entryPointArgs);
    ...
}

@ActivityThread:
ActivityThread#main() ->
thread.attach(false) ->
mgr.attachApplication(mAppThread); ->
@ActivityManagerService:
attachApplication(mAppThread); ->
attachApplicationLocked(thread, callingPid); ->
mStackSupervisor.attachApplicationLocked(app)

最终调用了
@ActivityStackSupervisor#attachApplicationLocked(…):

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

以上为 AMS 到 ApplicationThread 的调用过程

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 进阶解密:根 Activity 启动过程 的相关文章

  • 在包“android”中找不到属性“backgroundTint”的资源标识符

    我发现了一些视图 xml 属性 例如backgroundTint backgroundTintMode 但是当我使用它作为视图属性定义时 Eclipse 显示错误 No resource identifier found for attri
  • StrictMode 策略违规:我的应用程序中存在 android.os.strictmode.LeakedClosableViolation?

    Android 开发新手 第一次在我的应用程序上尝试 StrictMode 我注意到以下内容 并想知道这是否是我的应用程序或库中的问题 我不太清楚 谢谢你 D StrictMode StrictMode policy violation a
  • 如何重试已消耗的 Observable?

    我正在尝试重新执行失败的已定义可观察对象 一起使用 Retrofit2 和 RxJava2 我想在单击按钮时重试特定请求及其订阅和行为 那可能吗 service excecuteLoginService url tokenModel Ret
  • CardView 圆角获得意想不到的白色

    When using rounded corner in CardView shows a white border in rounded area which is mostly visible in dark environment F
  • 是否可以将数组或对象添加到 Android 上的 SharedPreferences

    我有一个ArrayList具有名称和图标指针的对象 我想将其保存在SharedPreferences 我能怎么做 注意 我不想使用数据库 无论 API 级别如何 请检查SharedPreferences 中的字符串数组和对象数组 http
  • java.lang.NoClassDefFoundError:org.apache.batik.dom.svg.SVGDOMImplementation

    我在链接到我的 Android LibGDX 项目的 Apache Batik 库时遇到了奇怪的问题 但让我们从头开始 在 IntelliJ Idea 中我有一个项目 其中包含三个模块 Main Android 和 Desktop 我强调的
  • Adobe 是否为其 PDF 阅读器提供 Android SDK 或 API? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望能够在我们的应用程序内的视图中显示本地 PDF 文件 在 Android 4 03 下的平板电脑上运行 目前 我们将 Adob eR
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • Android 模拟器插件无法初始化后端 EGL 显示

    我在 Cloudbees 上设置了 Jenkins 作业 并且可以在那里成功签出并编译我的 Android 项目 现在我想在 android 模拟器中运行一些 JUnit 测试并添加 Android 模拟器插件 我将 显示模拟器窗口 选项设
  • 是否有 ADB 命令来检查媒体是否正在播放

    我想使用 ADB 命令检查根植于终端的外部设备中是否正在播放音频 视频 我无法找到任何 ADB 命令 如果有 我尝试过 adb shell dumpsys media player 我想要一个命令来指定视频是否正在运行 您可以使用以下命令查
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 在 SQLite 中搜索时排除 HTML 标签和一些 UNICODE 字符

    更新 4 我已经成功运行了firstchar例如 但现在的问题是使用regex 即使包含头文件 它也无法识别regex操作员 有什么线索可以解决这个问题吗 更新 2 我已经编译了sqlite3我的项目中的库 我现在正在寻找任何人帮助我为我的
  • 如何默认在 ActionOpenDocument 意图中显示“内部存储”选项

    我需要用户选择一个自定义文件类型的文件 并将其从 Windows 文件资源管理器拖到 Android 设备上 但默认情况下内部存储选项不可用 当我使用以下命令启动意图时 var libraryIntent new Intent Intent
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • 增加活动的屏幕亮度

    显然 Android 操作系统中至少有三种不同的技术可以改变屏幕亮度 其中两个在纸杯蛋糕之后不再起作用 而第三个被接受的技术显然有一个错误 我想在单视图活动开始时增加屏幕亮度 然后在活动结束时将亮度恢复为用户设置 没有按钮 没有第二个视图或
  • 在activity_main.xml中注释

    我是安卓新手 据我所知 XML 中的注释与 HTML 中的注释相同 使用 形式 我想在 Android 项目的 Activity main xml 配置文件中写一些注释 但它给了我错误 值得注意的是 我使用的是 Eclipse 但目前 我直
  • Crashlytics 出现 Android Studio 构建错误

    我正在尝试将 CrashLytics 与 Android Studio 和 gradle 一起使用 但出现一个令人困惑的错误 java lang NoSuchMethodError 我的 build gradle 是 buildscript
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐

  • MES系统质量追溯功能,到底在追什么?

    今天我们就来分析一下生产企业的产品质量追溯问题 以及MES系统中产品追溯的应用 我们知道 生产质量管理是MES系统中十分重要的一部分 因为长期以来 车间质量管理部门希望车间的加工水平持续保持在最佳状态 对加工过程产生的质量问题能得到及时的发
  • 河北某日报移动端python数据采集 eds加密新闻内容

    写在最前面 此移动端采用EDS 的js加密 核心的js加密代码 贴在 个人爱好尝试破解 仅提供技术交流用 目标地址 抓取的详情页地址 var e 4Qjir8b019EIXH0FBzIJIuElne7uRYd6AB7qOIQg TdtJrw
  • Java日期计算溢出问题

    先看下面的代码 SimpleDateFormat fmt new SimpleDateFormat yyyy MM dd final Date beginDate fmt parse 2013 8 1 for int i 0 i lt 30
  • 【Docker】ERROR: Could not find a version that satisfies the requirement pytest==5.0.1

    1 背景 背景参考 Docker elasticsearch 监控工具 elasticsearch HQ lcc lcc soft es elasticsearch HQ 3 5 12 pip install r requirements
  • Java解决Oracle中ORA-12542:TNS无监听程序ORA-12542:TNS:监听程序无法识别连接符中请求的服务

    环境 WINDOWS2003 ORACLE 10G 第一次安装完ORACLE后使用SQLPLUS链接都是没问题的 但重启服务器就报了异常 ORA 12541 TNS 无监听程序 这里肯定是监听器出了问题 但没有做任何变动 只是重启了服务器
  • 音频特征(2):时域图、频谱图、语谱图(时频谱图)

    文章目录 时域和频域 1 概述 2 时域 波形和频域 用几张对比图来区分 2 1 时域和频域 2 2 区分 时频谱图 语谱图 傅里叶变换的典型用途是将信号分解成频率谱 显示与频率对应的幅值大小 时域和频域 1 概述 1 什么是信号的时域和频
  • Zabbix实践(四) zabbix的通知推送解决方案

    zabbix 监控建立起来后 可以使用zabbix自带的推送接口 进行消息的推送 本节 说明一下采用OneAlert产品作为 zabbix的下游 进行消息推送 OneAlert 是一款集成了各种推送和接收消息的软件 个人版本免费 其他版本
  • TypeScript-初识

    引言 TypeScript 静态类检查器 提供了 JavaScript 的所有功能 并且在这些功能之上添加了一层 TypeScript 的类型系统 TypeScript 会在执行前检查程序是否有错误 并根据值的种类进行检查 一 定义属性 c
  • 分析压缩感知

    1 引言 信号采样是模拟的物理世界通向数字的信息世界之必备手段 多年来 指导信号采样的理论基础一直是着名的Nyquist 采样定理 定理指出 只有当采样速率达到信号带宽的两倍以上时 才能由采样信号精确重建原始信号 可见 带宽是Nyquist
  • 跳坑:由于找不到vcruntime140_1.dll,无法继续执行代码。重新安装程序可能会解决此问题。

    一 问题背景 在安装MySQL服务运行初始化命令时 出现弹窗报错 由于找不到vcruntime140 1 dll 无法继续执行代码 重新安装程序可能会解决此问题 二 原因分析 综合网上问答数据分析 此处报错原因时因为缺少了动态链接库 vcr
  • 使用Picgo自动上传本地图片教程(typora+gitee图床)

    使用Picgo自动上传本地图片教程 typora 注意 2022 3 25日起gitee不能用于图床了 gitee加了防盗链 所有图片的都访问不了了 大家请选择其他的图床存放图片 本文章配置gitee图床教程已不可用 获取Picgo 官网
  • 企业网三层架构

    文章目录 三层架构 WLAN 无线网络天生的缺陷 链路聚合技术 原理 ensp配置 VRRP 工作过程 配置 三层架构 园区 工厂 政府机关 写字楼 校园 公园等 这些公共场所内为实现数据的互通所搭建的网络都可以称为园区网 不同的园区网搭建
  • AI人体抠像之灰度图如何还原成原图——以Face++人体抠像为例

    Face 人体抠像API V1版本图片返回结果为灰度图 但是并不是可以直接用的结果 我们需要的是保留人体部分的像素数据 背景根据需要可以自由替换的 让我们来看看如何才能还原 原理 一 V1版本返回值可还原成灰度图 颜色只有黑白灰三种颜色 颜
  • 鸿蒙系统开源

    华为的鸿蒙系统可能一直是听说过没见过的系统 在今天也终于正式宣布开源了 鸿蒙系统托管在了国内的 Gitee 上 也就是码云上面 其地址如下 https openharmony gitee com 在它的托管主页上有一个项目介绍 我这里复制过
  • 华为笔试题:坐标移动

    include
  • Spring集成Hadoop实践

    在Spring中集成Hadoop流程梳理 1 maven添加spring data hadoop依赖
  • 关于mysql一直显示Processing configuration..

    安装3遍一直显示Processing configuration 最后重启解决的 有相同问题的可以试试
  • matter.js的入门小结

    Matter js 是一个用于创建物理引擎的 JavaScript 库 它提供了一个简单而强大的 API 使得开发者可以创建出真实世界中的物理效果 例如碰撞 重力和摩擦等 以下是 Matter js 入门学习笔记 1 安装和导入 Matte
  • html视频倍速播放,如何让网页视频倍速播放

    Video Speed Controller 是一款倍速播放视频的浏览器插件 现在网站上播放的视频 基本上都可以实现倍速播放 但偶尔也有些网站上的视频 没有倍速播放功能 有时候看一些没有倍速播放功能的视频 确实比较难受或有点不耐烦 有没有一
  • Android 进阶解密:根 Activity 启动过程

    一 根 Activity 启动过程 可以分为三个部分 Launcher 请求 AMS 过程 AMS 到 ApplicationThread 的调用过程 ActivityThread 启动 Activity 二 Launcher 启动 AMS