We start with the analysis parameters in the previous section and finally achieve:
result = mInterface.startActivityAndWait(null, null, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, options != null ? options.toBundle() : null, mUserId);
At this time, we will link the analysis parameters from the preceding to the following:
parameter | Meaning | |
---|---|---|
IApplicationThread caller | Caller Process Controller | null |
String callingPackage | The package name of the caller | null |
Intent intent | The intent of the caller | intent |
String resolvedType | The value returned by getType in the provider, and some pages can handle this uri | mimeType |
IBinder resultTo | ActitytRecord (binder object) that accepts the result | null |
String resultWho | User-defined string, which will be passed back after calling | null |
int requestCode | User-defined code, which will be passed back after calling | 0 |
int startFlags | Start flag | mStartFlags |
ProfilerInfo profilerInfo | statistical data | profilerInfo |
Bundle bOptions | Other startup parameters may be inherited from parent activity | options.toBundle() |
int userId | userId | mUserId |
ActvitiyManagerService.java
@Override public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) { enforceNotIsolatedCaller("startActivityAndWait"); userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null); WaitResult res = new WaitResult(); // TODO: Switch to user app stacks here. mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null, bOptions, false, userId, null, "startActivityAndWait"); return res; }
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, TaskRecord inTask, String reason) { //intent cannot pass file handles if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } mSupervisor.mActivityMetricsLogger.notifyActivityLaunching(); //Specify - n or by looking up the registry in PKMS boolean componentSpecified = intent.getComponent() != null; //Copy two intent s, one is temporary, and the other is to prevent modifications from failing to restore final Intent ephemeralIntent = new Intent(intent); intent = new Intent(intent); //When there is a corresponding component and the data passed is not null, and action specifies that the - a parameter is android.intent.action.VIEW. //And it's the Activity corresponding to the installer //I can't walk here anyway. if (componentSpecified && intent.getData() != null && Intent.ACTION_VIEW.equals(intent.getAction()) && mService.getPackageManagerInternalLocked() .isInstantAppInstallerComponent(intent.getComponent())) {, intent.setComponent(null /*component*/); componentSpecified = false; } //Using PKMS to parse the information that meets the requirements of Intent and other parameters, it contains the information declared from the list file by four components. ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId); //When ResolveInfo is not available if (rInfo == null) { UserInfo userInfo = mSupervisor.getUserInfo(userId); //Use the isManagedProfile() method to determine if this UserInfo is just a profile(Android allows one user to have another profile) if (userInfo != null && userInfo.isManagedProfile()) { UserManager userManager = UserManager.get(mService.mContext); boolean profileLockedAndParentUnlockingOrUnlocked = false; long token = Binder.clearCallingIdentity(); try { UserInfo parent = userManager.getProfileParent(userId); profileLockedAndParentUnlockingOrUnlocked = (parent != null) && userManager.isUserUnlockingOrUnlocked(parent.id) && !userManager.isUserUnlockingOrUnlocked(userId); } finally { Binder.restoreCallingIdentity(token); } if (profileLockedAndParentUnlockingOrUnlocked) { rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); } } } //Here's a piece of logic about multiple users // Get information about the target Activity through ResolveInfo. ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); //Get Activity Options, about which are some additional parameters set through -- task, -- stack, -- display, etc. ActivityOptions options = ActivityOptions.fromBundle(bOptions); //Here comes an AMS lock. synchronized (mService) { //Get the invoked Pid and Uid final int realCallingPid = Binder.getCallingPid(); final int realCallingUid = Binder.getCallingUid(); int callingPid; if (callingUid >= 0) { callingPid = -1; } else if (caller == null) { callingPid = realCallingPid; callingUid = realCallingUid; } else { callingPid = callingUid = -1; } //Get the current stack final ActivityStack stack = mSupervisor.mFocusedStack; //false stack.mConfigWillChange = globalConfig != null && mService.getGlobalConfiguration().diff(globalConfig) != 0; if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = " + stack.mConfigWillChange); //Clear Pid and Uid for security checks final long origId = Binder.clearCallingIdentity(); //If ActivityRecord is not null, the ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE tag means that the caller App belongs to the heavy-weight process. if (aInfo != null && (aInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { //The process name is equal to the package name in Application if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) { //Get a record of the heavyweight process that is currently running final ProcessRecord heavy = mService.mHeavyWeightProcess; //Currently running heavyweight processes do not match the ones to be started if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid || !heavy.processName.equals(aInfo.processName))) { int appCallingUid = callingUid; if (caller != null) { //Get the calling process record ProcessRecord callerApp = mService.getRecordForAppLocked(caller); if (callerApp != null) { appCallingUid = callerApp.info.uid; } else { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting: " + intent.toString()); ActivityOptions.abort(options); return ActivityManager.START_PERMISSION_DENIED; } } IIntentSender target = mService.getIntentSenderLocked( ActivityManager.INTENT_SENDER_ACTIVITY, "android", appCallingUid, userId, null, null, 0, new Intent[] { intent }, new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT, null); //New Intent Intent newIntent = new Intent(); if (requestCode >= 0) { // Caller is requesting a result. newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true); } newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT, new IntentSender(target)); //Current heavyweight processes have more than 0 ActivityRecord s if (heavy.activities.size() > 0) { //Get the first Activity, and put the name and stack set into the new Intent ActivityRecord hist = heavy.activities.get(0); newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName); newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTask().taskId); } newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP, aInfo.packageName); newIntent.setFlags(intent.getFlags()); //The name of the new intent newIntent.setClassName("android", HeavyWeightSwitcherActivity.class.getName()); intent = newIntent; resolvedType = null; caller = null; callingUid = Binder.getCallingUid(); callingPid = Binder.getCallingPid(); componentSpecified = true; rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId); aInfo = rInfo != null ? rInfo.activityInfo : null; if (aInfo != null) { aInfo = mService.getActivityInfoForUser(aInfo, userId); } } } } //Create a new Activity Record final ActivityRecord[] outRecord = new ActivityRecord[1]; //Execute startActivityLocked int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason); //Setting pid, uid, permission checking related Binder.restoreCallingIdentity(origId); //false if (stack.mConfigWillChange) { mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); stack.mConfigWillChange = false; if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Updating to new configuration after starting activity."); mService.updateConfigurationLocked(globalConfig, null, false); } //When the result is not null if (outResult != null) { outResult.result = res; //And it started successfully. //Target Activity is running in a new application process, so it needs to wait for the application process to start normally and process related requests. if (res == ActivityManager.START_SUCCESS) { mSupervisor.mWaitingActivityLaunched.add(outResult); do { try { //Wait until the outResult shows that the Task corresponding to Activity becomes front task mService.wait(); } catch (InterruptedException e) { } //If the request result is not START_TASK_TO_FRONT and there is no timeout, and the caller is not null, wait } while (outResult.result != START_TASK_TO_FRONT && !outResult.timeout && outResult.who == null); if (outResult.result == START_TASK_TO_FRONT) { res = START_TASK_TO_FRONT; } } if (res == START_TASK_TO_FRONT) { final ActivityRecord r = outRecord[0]; if (r.nowVisible && r.state == RESUMED) { outResult.timeout = false; outResult.who = r.realActivity; outResult.totalTime = 0; outResult.thisTime = 0; } else { outResult.thisTime = SystemClock.uptimeMillis(); //The task corresponding to Activity is pulled back to the front desk until the interface is loaded. mSupervisor.waitActivityVisible(r.realActivity, outResult); do { try { mService.wait(); } catch (InterruptedException e) { } } while (!outResult.timeout && outResult.who == null); } } } } }
Summarize this method;
- Resolve ActivityInfo that matches Intent.
- Get the Task that starts the Activity, the Front Desk Task.
- Start Activity by startActivityLocked
- Processing the return value, waiting for Activity to be started because the - W parameter is used