Activity starts the 2-startActivityMayWait method

Keywords: Mobile Android Java

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

Posted by Nilanka on Mon, 28 Jan 2019 03:51:16 -0800