Android14 - AMS之Activity启动过程(1)

news2024/11/15 14:10:35
Android14 - AMS之Activity启动过程(2)-CSDN博客
​​​​​​​ Android14 - AMS之Activity启动过程(3)-CSDN博客

我们以Context的startActivity场景(option == null, FLAG_ACTIVITY_NEW_TASK)来梳理

整体时序图如下:

服务端

客户端

入口

ContextImpl的入口:

platform/frameworks/base/core/java/android/app/ContextImpl.java

@Override
public void startActivity(Intent intent) {
    warnIfCallingFromSystemProcess();
    startActivity(intent, null);
}

@Override
public void startActivity(Intent intent, Bundle options) {
    if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                && (targetSdkVersion < Build.VERSION_CODES.N
                        || targetSdkVersion >= Build.VERSION_CODES.P)
                && (options == null
                        || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity"
                            + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                            + " Is this really what you want?");
        }
    mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,  (Activity) null, intent, -1, options);
}

通过Context来启动时,如果不是FLAG_ACTIVITY_NEW_TASK,并且option为null,会抛出异常。

下一步调用execStartActivity,关注这里传入的几个参数:

Context who:getOuterContext(),这里只ContextImp自己;如果是从Activity内启动,则是Activity对象自身(见Activity->startActivityForResult(...))。

IBinder contextThread:mMainThread.getApplicationThread(),也就是服务端向客户端通信时,客户端的binder stub

Activity target:null。也就是回退时的result Activity。

Intent intent:intent。

requestCode: -1。

options:null。

platform/frameworks/base/core/java/android/app/Instrumentation.java

public ActivityResult execStartActivity(
		Context who, IBinder contextThread, IBinder token, Activity target,
		Intent intent, int requestCode, Bundle options) {
    try {
		intent.migrateExtraStreamToClipData(who);
		intent.prepareToLeaveProcess(who);
		int result = ActivityTaskManager.getService().startActivity(whoThread,
				who.getOpPackageName(), who.getAttributionTag(), intent,
				intent.resolveTypeIfNeeded(who.getContentResolver()), token,
				target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
		notifyStartActivityResult(result, options);
		checkStartActivityResult(result, intent);
	} catch (RemoteException e) {
		throw new RuntimeException("Failure from system", e);
	}
	return null;
}

创建ActivityStarter

我们忽略过ActivityTaskManager从binder客户端到服务端的过程,直接看服务端代码:

platform/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

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

@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
		String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
		String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
		Bundle bOptions, int userId) {
	return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
			resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
			true /*validateIncomingUser*/);
}

private int startActivityAsUser(IApplicationThread caller, String callingPackage,
		@Nullable String callingFeatureId, Intent intent, String resolvedType,
		IBinder resultTo, String resultWho, int requestCode, int startFlags,
		ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {

	final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);

	assertPackageMatchesCallingUid(callingPackage);
	enforceNotIsolatedCaller("startActivityAsUser");

	if (intent != null && intent.isSandboxActivity(mContext)) {
		SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
				SdkSandboxManagerLocal.class);
		sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
				intent, Binder.getCallingUid(), callingPackage
		);
	}

	if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
		SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
				SdkSandboxManagerLocal.class);
		if (sdkSandboxManagerLocal == null) {
			throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"
					+ " an activity from an SDK sandbox uid.");
		}
		sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);
	}

	userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
			Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

	// TODO: Switch to user app stacks here.
	return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
			.setCaller(caller)
			.setCallingPackage(callingPackage)
			.setCallingFeatureId(callingFeatureId)
			.setResolvedType(resolvedType)
			.setResultTo(resultTo)
			.setResultWho(resultWho)
			.setRequestCode(requestCode)
			.setStartFlags(startFlags)
			.setProfilerInfo(profilerInfo)
			.setActivityOptions(opts)
			.setUserId(userId)
			.execute();

}

obtainStarter()方法实际是调用了mFactory.obtain(), 而mFactory为ActivityStarter的内部类DefaultFactory,看下DefaultFactory的obtain()。

platform/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

static class DefaultFactory implements Factory {
    private final int MAX_STARTER_COUNT = 3;
    private SynchronizedPool<ActivityStarter> mStarterPool =
                new SynchronizedPool<>(MAX_STARTER_COUNT);
                
    public ActivityStarter obtain() {
        ActivityStarter starter = mStarterPool.acquire();
    
        if (starter == null) {
            if (mService.mRootWindowContainer == null) {
                throw new IllegalStateException("Too early to start activity.");
            }
            starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
        }
    
        return starter;
    }
}

obtain本质上是获取了一个ActivityStarter对象,用来启动activity。每个Intent对应一个ActivityStarter这里使用了SynchronizedPool--简单的对象池来管理对象的生产,对象池里有3个对象,如果申请时池子里没有可用对象,则直接new一个。

Activity参数整理、合法性检查与ActivityRecord的创建

现在,通过obtain()获得了一个ActivityStarter,通过执行其execute方法来启动一个Activity:

platform/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

int execute() {
    ...
    if (mRequest.activityInfo == null) {
          mRequest.resolveActivity(mSupervisor);
    }
    res = executeRequest(mRequest);
    ...
}

/**
 * Executing activity start request and starts the journey of starting an activity. Here
 * begins with performing several preliminary checks. The normally activity launch flow will
 * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
 */
private int executeRequest(Request request) {
	if (TextUtils.isEmpty(request.reason)) {
		throw new IllegalArgumentException("Need to specify a reason.");
	}
	mLastStartReason = request.reason;
	mLastStartActivityTimeMs = System.currentTimeMillis();
	// Reset the ActivityRecord#mCurrentLaunchCanTurnScreenOn state of last start activity in
	// case the state is not yet consumed during rapid activity launch.
	if (mLastStartActivityRecord != null) {
		mLastStartActivityRecord.setCurrentLaunchCanTurnScreenOn(false);
	}
	mLastStartActivityRecord = null;

    // *** 1. 整理参数,为后续构建ActivityRecorder等对象做准备
	final IApplicationThread caller = request.caller;
	Intent intent = request.intent;
	NeededUriGrants intentGrants = request.intentGrants;
	String resolvedType = request.resolvedType;
	ActivityInfo aInfo = request.activityInfo;
	ResolveInfo rInfo = request.resolveInfo;
	final IVoiceInteractionSession voiceSession = request.voiceSession;
	final IBinder resultTo = request.resultTo;
	String resultWho = request.resultWho;
	int requestCode = request.requestCode;
	int callingPid = request.callingPid;
	int callingUid = request.callingUid;
	String callingPackage = request.callingPackage;
	String callingFeatureId = request.callingFeatureId;
	final int realCallingPid = request.realCallingPid;
	final int realCallingUid = request.realCallingUid;
	final int startFlags = request.startFlags;
	final SafeActivityOptions options = request.activityOptions;
	Task inTask = request.inTask;
	TaskFragment inTaskFragment = request.inTaskFragment;

	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;

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

	final int userId = aInfo != null && aInfo.applicationInfo != null
			? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
	final int launchMode = aInfo != null ? aInfo.launchMode : 0;
	if (err == ActivityManager.START_SUCCESS) {
		request.logMessage.append("START u").append(userId).append(" {")
				.append(intent.toShortString(true, true, true, false))
				.append("} with ").append(launchModeToString(launchMode))
				.append(" from uid ").append(callingUid);
		if (callingUid != realCallingUid
				&& realCallingUid != Request.DEFAULT_REAL_CALLING_UID) {
			request.logMessage.append(" (realCallingUid=").append(realCallingUid).append(")");
		}
	}

	ActivityRecord sourceRecord = null;
	ActivityRecord resultRecord = null;
	if (resultTo != null) {
		sourceRecord = ActivityRecord.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) {
		// Transfer the result target from the source activity to the new one being started,
		// including any failures.
		if (requestCode >= 0) {
			SafeActivityOptions.abort(options);
			return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
		}
		resultRecord = sourceRecord.resultTo;
		if (resultRecord != null && !resultRecord.isInRootTaskLocked()) {
			resultRecord = null;
		}
		resultWho = sourceRecord.resultWho;
		requestCode = sourceRecord.requestCode;
		sourceRecord.resultTo = null;
		if (resultRecord != null) {
			resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
		}
		if (sourceRecord.launchedFromUid == callingUid) {
			// The new activity is being launched from the same uid as the previous activity
			// in the flow, and asking to forward its result back to the previous.  In this
			// case the activity is serving as a trampoline between the two, so we also want
			// to update its launchedFromPackage to be the same as the previous activity.
			// Note that this is safe, since we know these two packages come from the same
			// uid; the caller could just as well have supplied that same package name itself
			// . This specifially deals with the case of an intent picker/chooser being
			// launched in the app flow to redirect to an activity picked by the user, where
			// we want the final activity to consider it to have been launched by the
			// previous app activity.
			callingPackage = sourceRecord.launchedFromPackage;
			callingFeatureId = sourceRecord.launchedFromFeatureId;
		}
	}

	if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
		// We couldn't find a class that can handle the given Intent.
		// That's the end of that!
		err = ActivityManager.START_INTENT_NOT_RESOLVED;
	}

	if (err == ActivityManager.START_SUCCESS && aInfo == null) {
		// We couldn't find the specific class specified in the Intent.
		// Also the end of the line.
		err = ActivityManager.START_CLASS_NOT_FOUND;
	}

	if (err == ActivityManager.START_SUCCESS && sourceRecord != null
			&& sourceRecord.getTask().voiceSession != null) {
		// If this activity is being launched as part of a voice session, we need to ensure
		// that it is safe to do so.  If the upcoming activity will also be part of the voice
		// session, we can only launch it if it has explicitly said it supports the VOICE
		// category, or it is a part of the calling app.
		if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
				&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
			try {
				intent.addCategory(Intent.CATEGORY_VOICE);
				if (!mService.getPackageManager().activitySupportsIntentAsUser(
						intent.getComponent(), intent, resolvedType, userId)) {
					Slog.w(TAG, "Activity being started in current voice task does not support "
							+ "voice: " + intent);
					err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
				}
			} catch (RemoteException e) {
				Slog.w(TAG, "Failure checking voice capabilities", e);
				err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
			}
		}
	}

	if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
		// If the caller is starting a new voice session, just make sure the target
		// is actually allowing it to run this way.
		try {
			if (!mService.getPackageManager().activitySupportsIntentAsUser(
					intent.getComponent(), intent, resolvedType, userId)) {
				Slog.w(TAG,
						"Activity being started in new voice task does not support: " + intent);
				err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
			}
		} catch (RemoteException e) {
			Slog.w(TAG, "Failure checking voice capabilities", e);
			err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
		}
	}

	final Task resultRootTask = resultRecord == null
			? null : resultRecord.getRootTask();

	if (err != START_SUCCESS) {
		if (resultRecord != null) {
			resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
					null /* data */, null /* dataGrants */);
		}
		SafeActivityOptions.abort(options);
		return err;
	}

   // *** 2. 合法性检查
	boolean abort;
	try {
       // 2.1权限检查
		abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
				requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
				request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,
				resultRootTask);
	} catch (SecurityException e) {
		// Return activity not found for the explicit intent if the caller can't see the target
		// to prevent the disclosure of package existence.
		final Intent originalIntent = request.ephemeralIntent;
		if (originalIntent != null && (originalIntent.getComponent() != null
				|| originalIntent.getPackage() != null)) {
			final String targetPackageName = originalIntent.getComponent() != null
					? originalIntent.getComponent().getPackageName()
					: originalIntent.getPackage();
			if (mService.getPackageManagerInternalLocked()
					.filterAppAccess(targetPackageName, callingUid, userId)) {
				if (resultRecord != null) {
					resultRecord.sendResult(INVALID_UID, resultWho, requestCode,
							RESULT_CANCELED, null /* data */, null /* dataGrants */);
				}
				SafeActivityOptions.abort(options);
				return ActivityManager.START_CLASS_NOT_FOUND;
			}
		}
		throw e;
	}
	abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
			callingPid, resolvedType, aInfo.applicationInfo);
	abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
			callingPackage);

	// Merge the two options bundles, while realCallerOptions takes precedence.
	ActivityOptions checkedOptions = options != null
			? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;

	@BalCode int balCode = BAL_ALLOW_DEFAULT;
	if (!abort) {
		try {
          // 2.2 是否允许后台启动
			Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
					"shouldAbortBackgroundActivityStart");
			BackgroundActivityStartController balController =
					mController.getBackgroundActivityLaunchController();
			balCode =
					balController.checkBackgroundActivityStart(
							callingUid,
							callingPid,
							callingPackage,
							realCallingUid,
							realCallingPid,
							callerApp,
							request.originatingPendingIntent,
							request.backgroundStartPrivileges,
							intent,
							checkedOptions);
			if (balCode != BAL_ALLOW_DEFAULT) {
				request.logMessage.append(" (").append(
								BackgroundActivityStartController.balCodeToString(balCode))
						.append(")");
			}
		} finally {
			Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
		}
	}

	if (request.allowPendingRemoteAnimationRegistryLookup) {
		checkedOptions = mService.getActivityStartController()
				.getPendingRemoteAnimationRegistry()
				.overrideOptionsIfNeeded(callingPackage, checkedOptions);
	}
	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;
		}
	}

    // 2.3 拦截器拦截
	mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
			callingFeatureId);
	if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment,
			callingPid, callingUid, checkedOptions)) {
		// activity start was intercepted, e.g. because the target user is currently in quiet
		// mode (turn off work) or the target application is suspended
		intent = mInterceptor.mIntent;
		rInfo = mInterceptor.mRInfo;
		aInfo = mInterceptor.mAInfo;
		resolvedType = mInterceptor.mResolvedType;
		inTask = mInterceptor.mInTask;
		callingPid = mInterceptor.mCallingPid;
		callingUid = mInterceptor.mCallingUid;
		checkedOptions = mInterceptor.mActivityOptions;

		// The interception target shouldn't get any permission grants
		// intended for the original destination
		intentGrants = null;
	}

	if (abort) {
		if (resultRecord != null) {
			resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
					null /* data */, null /* dataGrants */);
		}
		// We pretend to the caller that it was really started, but they will just get a
		// cancel result.
		ActivityOptions.abort(checkedOptions);
		return START_ABORTED;
	}

   // *** 3 是否要跳转到Review页面
	// If permissions need a review before any of the app components can run, we
	// launch the review activity and pass a pending intent to start the activity
	// we are to launching now after the review is completed.
	if (aInfo != null) {
		if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
				aInfo.packageName, userId)) {
			final IIntentSender target = mService.getIntentSenderLocked(
					ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
					callingUid, userId, null, null, 0, new Intent[]{intent},
					new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
							| PendingIntent.FLAG_ONE_SHOT, null);

			Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);

			int flags = intent.getFlags();
			flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;

			/*
			 * Prevent reuse of review activity: Each app needs their own review activity. By
			 * default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities
			 * with the same launch parameters (extras are ignored). Hence to avoid possible
			 * reuse force a new activity via the MULTIPLE_TASK flag.
			 *
			 * Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,
			 * hence no need to add the flag in this case.
			 */
			if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {
				flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
			}
			newIntent.setFlags(flags);

			newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
			newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
			if (resultRecord != null) {
				newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
			}
			intent = newIntent;

			// The permissions review target shouldn't get any permission
			// grants intended for the original destination
			intentGrants = null;

			resolvedType = null;
			callingUid = realCallingUid;
			callingPid = realCallingPid;

			rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
					computeResolveFilterUid(
							callingUid, realCallingUid, request.filterCallingUid),
					realCallingPid);
			aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
					null /*profilerInfo*/);

			if (DEBUG_PERMISSIONS_REVIEW) {
				final Task focusedRootTask =
						mRootWindowContainer.getTopDisplayFocusedRootTask();
				Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
						true, false) + "} from uid " + callingUid + " on display "
						+ (focusedRootTask == null ? DEFAULT_DISPLAY
								: focusedRootTask.getDisplayId()));
			}
		}
	}
   // **** 4,对于Instant app(ephemeral app)启动ephemeral installer
	// 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.auxiliaryInfo != null) {
		intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
				callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
		resolvedType = null;
		callingUid = realCallingUid;
		callingPid = realCallingPid;

		// The ephemeral installer shouldn't get any permission grants
		// intended for the original destination
		intentGrants = null;

		aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
	}
	// TODO (b/187680964) Correcting the caller/pid/uid when start activity from shortcut
	// Pending intent launched from systemui also depends on caller app
	if (callerApp == null && realCallingPid > 0) {
		final WindowProcessController wpc = mService.mProcessMap.getProcess(realCallingPid);
		if (wpc != null) {
			callerApp = wpc;
		}
	}
   // *** 5. 创建ActivityRecord
	final ActivityRecord r = new ActivityRecord.Builder(mService)
			.setCaller(callerApp)
			.setLaunchedFromPid(callingPid)
			.setLaunchedFromUid(callingUid)
			.setLaunchedFromPackage(callingPackage)
			.setLaunchedFromFeature(callingFeatureId)
			.setIntent(intent)
			.setResolvedType(resolvedType)
			.setActivityInfo(aInfo)
			.setConfiguration(mService.getGlobalConfiguration())
			.setResultTo(resultRecord)
			.setResultWho(resultWho)
			.setRequestCode(requestCode)
			.setComponentSpecified(request.componentSpecified)
			.setRootVoiceInteraction(voiceSession != null)
			.setActivityOptions(checkedOptions)
			.setSourceRecord(sourceRecord)
			.build();

	mLastStartActivityRecord = r;

	if (r.appTimeTracker == null && sourceRecord != null) {
		// If the caller didn't specify an explicit time tracker, we want to continue
		// tracking under any it has.
		r.appTimeTracker = sourceRecord.appTimeTracker;
	}

	// Only allow app switching to be resumed if activity is not a restricted background
	// activity and target app is not home process, otherwise any background activity
	// started in background task can stop home button protection mode.
	// As the targeted app is not a home process and we don't need to wait for the 2nd
	// activity to be started to resume app switching, we can just enable app switching
	// directly.
	WindowProcessController homeProcess = mService.mHomeProcess;
	boolean isHomeProcess = homeProcess != null
			&& aInfo.applicationInfo.uid == homeProcess.mUid;
	if (balCode != BAL_BLOCK && !isHomeProcess) {
		mService.resumeAppSwitches();
	}

	mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
			request.voiceInteractor, startFlags, checkedOptions,
			inTask, inTaskFragment, balCode, intentGrants, realCallingUid);

	if (request.outActivity != null) {
		request.outActivity[0] = mLastStartActivityRecord;
	}

	return mLastStartActivityResult;
}

executeRequest是个庞大的方法。做了几件事情:

1. 整理参数,为构建ActivityRecord做准备

其中

caller来自于之前传入的mMainThread.getApplicationThread()

       一般场景中callingPid为-1,realCallingPid为Binder.getCallingPid()。 callingPid如果赋值,和realCallingPid一般是相同的,都来自Binder.getCallingPid(),但在使用PendingIntent的场景,callingPid代表创建了PendingIntent的进程,而realCallingPid代表通过使用PendingIntent.send()执行PendingIntent的进程。(见ActivityStarter.setCallingPid

sourceRecord、resultRecord来自于resultTo要返回的Activity,也就是startActivityForResult要返回的Activity。

     inTaskId:本场景中为空。一般在startActivityFromRecents等场景下,会设置。

2. 合法性检查

包括:

权限检查,比如目标Activity包名是否合法、是否为exported的Activity等通用权限

后台启动检查:通过BackgroundActivityStartController检查是否允许后台启动

拦截器检查:通过ActivityStartInterceptor检查各种拦截情况,如认为是潜在的恶意app(HarmfulApp)则改变intent为警告页面,到时不会跳转到原请求的activity。

3. 权限review(isPermissionsReviewRequired):如果需要在启动真正目标activity前跳转到权限review页面,则将原intent改为pending Intent传给review页面,待review结束后再继续启动。

4. 对于Instant app(ephemeral app)启动ephemeral installer

关于Instant app,详见https://developer.android.com/topic/google-play-instant

https://developer.android.com/topic/google-play-instant/overview

5. 创建ActivityRecored:final ActivityRecord r = new ActivityRecord.Builder(mService)

ActivityRecore的创建

在创建ActivityRecord时,ActivityRecord的构造函数里会设置setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord);需要注意下:

private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent,
		ActivityOptions options, ActivityRecord sourceRecord) {
	int activityType = ACTIVITY_TYPE_UNDEFINED;
	if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
			&& isHomeIntent(intent) && !isResolverOrDelegateActivity()) {
		// This sure looks like a home activity!
		activityType = ACTIVITY_TYPE_HOME;

		if (info.resizeMode == RESIZE_MODE_FORCE_RESIZEABLE
				|| info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
			// We only allow home activities to be resizeable if they explicitly requested it.
			info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
		}
	} else if (mAtmService.getRecentTasks().isRecentsComponent(mActivityComponent,
			info.applicationInfo.uid)) {
		activityType = ACTIVITY_TYPE_RECENTS;
	} else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
			&& canLaunchAssistActivity(launchedFromPackage)) {
		activityType = ACTIVITY_TYPE_ASSISTANT;
	} else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_DREAM
			&& mAtmService.canLaunchDreamActivity(launchedFromPackage)
			&& DreamActivity.class.getName() == info.name) {
		activityType = ACTIVITY_TYPE_DREAM;
	}
	setActivityType(activityType);
}

本场景中activityType为默认值ACTIVITY_TYPE_UNDEFINED

随后调用startActivityUnchecked,进而调用startActivityInner。

至此回顾下,目前整个时序进行到这里:

后续请见下篇。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1534450.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++类型转换及IO流(深度剖析)

文章目录 1. 前言2. C语言的类型转换3. C的强制类型转换3.1 static_cast3.2 reinterpret_cast3.3 const_cast3.4 dynamic_cast 4. RTTI&#xff08;了解&#xff09;5. C语言的输入输出及缓存区理解6. CIO流6.1 C标准IO流6.2 C文件IO流 7. stringstream的简单介绍 1. 前言 C语言…

机器学习-可解释性机器学习:支持向量机与fastshap的可视化模型解析

一、引言 支持向量机(Support Vector Machine, SVM)作为一种经典的监督学习方法&#xff0c;在分类和回归问题中表现出色。其优点之一是生成的模型具有较好的泛化能力和可解释性&#xff0c;能够清晰地展示特征对于分类的重要性。 fastshap是一种用于快速计算SHAP值&#xff08…

华曦传媒陆锋:数字媒体时代,社区电梯广告价值正在被重估

在数字化时代的浪潮中&#xff0c;电梯广告、停车场道闸广告、门禁灯箱广告等线下社区广告似乎面临着生存的挑战。 然而&#xff0c;这一传统广告形式展现出了惊人的韧性和价值。 比如&#xff0c;2023年上半年&#xff0c;作为行业龙头分众传媒&#xff0c;2023年上半年实现…

【Linux】多线程编程基础

&#x1f4bb;文章目录 &#x1f4c4;前言&#x1f33a;linux线程基础线程的概念线程的优缺点线程与进程的区别 线程的创建 &#x1f33b;linux线程冲突概念互斥锁函数介绍加锁的缺点 &#x1f4d3;总结 &#x1f4c4;前言 无论你是否为程序员&#xff0c;相信多线程这个词汇应…

小白也能在3分钟完成短剧解说的剪辑,这是真的!

3分钟的解说视频&#xff0c;真的需要1小时的手工剪辑吗&#xff1f; 生成解说视频需要经过素材准备、解说词创作、声音录制、视频剪辑和视频合成等多个步骤&#xff0c;每个步骤都需要投入一定的时间和精力&#xff0c;因此整个过程较为耗时耗力。 1. 素材准备&#xff1a; 需…

【LINUX笔记】驱动开发框架

应用程序调动驱动程序 驱动模块运行模式 模块加载-卸载 加载卸载注册函数 加载 驱动编译完成以后扩展名为.ko&#xff0c;有两种命令可以加载驱动模块&#xff1a; insmod和modprobe 驱动卸载 驱动注册注销 //查看当前已经被使用掉的设备号 cat /proc/devices 实现设备的具…

AI系统性学习06—开源中文语言大模型

1、ChatGLM ChatGLM-6B的github地址&#xff1a;https://github.com/THUDM/ChatGLM-6B ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级…

【Java Web基础】一些网页设计基础(二)

文章目录 1. Bootstrap导航栏设计1.1 代码copy与删减效果1.2 居中属性与底色设置1.3 占不满问题分析1.4 字体颜色、字体大小、字体间距设置1.5 修改超链接hover颜色&#xff0c;网站首页字体颜色 1. Bootstrap导航栏设计 1.1 代码copy与删减效果 今天设计导航栏&#xff0c;直…

第4关:创建工程项目表J,并插入数据

任务描述 工程项目表J由工程项目代码(JNO)、工程项目名(JNAME)、工程项目所在城市(CITY)组成。创建工程项目表J(JNO,JNAME,CITY)&#xff0c;并在J表中插入下图数据。 相关知识 1、MySQL创建表的基本语法如下&#xff1a; 其中&#xff0c;table_name 是要创建的表的名称&…

Hololens 2应用开发系列(4)——MRTK基础知识及配置文件配置(下)

Hololens 2应用开发系列&#xff08;4&#xff09;——MRTK基础知识及配置文件配置&#xff08;下&#xff09; 一、前言二、边界系统&#xff08;Boundary&#xff09;三、传送系统&#xff08;Teleport&#xff09;四、空间感知系统&#xff08;Spatial Awareness&#xff09…

Pytorch神经网络-元组/列表如何喂到神经网络中

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️感谢大家点赞&#x1f44d;&…

设计编程网站集:生活部分:饮食+农业,植物(暂记)

这里写目录标题 植物相关综合教程**大型植物&#xff1a;****高大乔木&#xff08;Trees&#xff09;&#xff1a;** 具有坚硬的木质茎&#xff0c;通常高度超过6米。例如&#xff0c;橡树、松树、榉树等。松树梧桐 **灌木&#xff08;Shrubs&#xff09;&#xff1a;** 比乔木…

基于Jenkins + Argo 实现多集群的持续交付

作者&#xff1a;周靖峰&#xff0c;青云科技容器顾问&#xff0c;云原生爱好者&#xff0c;目前专注于 DevOps&#xff0c;云原生领域技术涉及 Kubernetes、KubeSphere、Argo。 前文概述 前面我们已经掌握了如何通过 Jenkins Argo CD 的方式实现单集群的持续交付&#xff0c…

基于Springboot的在线投稿系统+数据库+免费远程调试

项目介绍: Javaee项目&#xff0c;springboot项目。采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringBoot Mybatis VueMavenLayui来实现。MySQL数据库作为系统数据储存平台&a…

Java安全 反序列化(3) CC1链-TransformedMap版

Java安全 反序列化(3) CC1链-TransformedMap版 本文尝试从CC1的挖掘思路出发&#xff0c;理解CC1的实现原理 文章目录 Java安全 反序列化(3) CC1链-TransformedMap版配置jdk版本和源代码配置前记 为什么可以利用一.CC链中的命令执行我们可以尝试一下通过InvokerTransformer.tr…

分布式异步任务框架celery

Celery介绍 github地址&#xff1a;GitHub - celery/celery: Distributed Task Queue (development branch) 文档地址&#xff1a;Celery - Distributed Task Queue — Celery 5.3.6 documentation 1.1 Celery是什么 celery时一个灵活且可靠的处理大量消息的分布式系统&…

数据库关系运算理论:传统的集合运算概念解析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

如何在wps的excel表格里面使用动态gif图

1、新建excel表格&#xff0c;粘贴gif图到表格里面&#xff0c;鼠标右键选择超链接。 找到源文件&#xff0c; 鼠标放到图片上的时候&#xff0c;待有个小手图标&#xff0c;双击鼠标可以放大看到动态gif图。 这种方式需要确保链接的原始文件位置和名称不能变化&#xff01;&a…

网工内推 | 云计算工程师,HCIE认证优先,最高18k*14薪

01 杭州中港科技有限公司 招聘岗位&#xff1a;云计算工程师 职责描述&#xff1a; 1、承担云计算相关工程交付、业务上云及售前测试&#xff0c;从事虚拟化、桌面云、存储、服务器、数据中心、大数据、相关产品的工程项目交付或协助项目交付。 2、承担云计算维护工程师职责&…

深入理解Mysql索引底层原理(看这一篇文章就够了)

目录 前言 1、Mysql 索引底层数据结构选型 1.1 哈希表&#xff08;Hash&#xff09; 1.2 二叉查找树(BST) 1.3 AVL 树和红黑树 1.4 B 树 1.5 B树 2、Innodb 引擎和 Myisam 引擎的实现 2.1 MyISAM 引擎的底层实现&#xff08;非聚集索引方式&#xff09; 2.2 Innodb 引…