一般启动Activity会调用StartActivity(),由此开始分析:
base/core/java/android/app/Activity.java
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);//1
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
if (TextUtils.equals(getPackageName(),
intent.resolveActivity(getPackageManager()).getPackageName())) {
// Apply Autofill restore mechanism on the started activity by startActivity()
final IBinder token =
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
// Remove restore ability from current activity
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
// Put restore token
intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
}
}
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);//2
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);//3
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);//4
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);//4.1
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
@Deprecated
public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,
int requestCode, @Nullable Bundle options) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, child,
intent, requestCode, options);//4.1.1
if (ar != null) {
mMainThread.sendActivityResult(
mToken, child.mEmbeddedID, requestCode,
ar.getResultCode(), ar.getResultData());
}
cancelInputsAndStartExitTransition(options);
}
IBinder:
intent:
options:
base/core/java/android/app/Instrumentation.java
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String resultWho,
Intent intent, int requestCode, Bundle options, UserHandle user) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
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(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho,
requestCode, 0, null, options, user.getIdentifier());//5
checkStartActivityResult(result, intent);//6
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
//5:获取到ATMS,然后调用ATMS的对象
base/core/java/android/app/ActivityTaskManager.java
/** @hide */
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
ACTIVITY_TASK_SERVICE:ActivityTaskManagerService
base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@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) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
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(bOptions)
.setUserId(userId)
.execute();//7
}
//6:
//7:
base/services/core/java/com/android/server/wm/ActivityStarter.java
/**
* Resolve necessary information according the request parameters provided earlier, and execute
* the request which begin the journey of starting an activity.
* @return The starter result.
*/
int execute() {
try {
// Refuse possible leaked file descriptors
if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
final LaunchingState launchingState;
synchronized (mService.mGlobalLock) {
final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
mRequest.intent, caller);
}
// If the caller hasn't already resolved the activity, we're willing
// to do so here. If the caller is already holding the WM lock here,
// and we need to check dynamic Uri permissions, then we're forced
// to assume those permissions are denied to avoid deadlocking.
if (mRequest.activityInfo == null) {
mRequest.resolveActivity(mSupervisor);
}
int res;
synchronized (mService.mGlobalLock) {
final boolean globalConfigWillChange = mRequest.globalConfig != null
&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
if (stack != null) {
stack.mConfigWillChange = globalConfigWillChange;
}
if (DEBUG_CONFIGURATION) {
Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
+ globalConfigWillChange);
}
final long origId = Binder.clearCallingIdentity();
res = resolveToHeavyWeightSwitcherIfNeeded();
if (res != START_SUCCESS) {
return res;
}
res = executeRequest(mRequest);//8
Binder.restoreCallingIdentity(origId);
if (globalConfigWillChange) {
// If the caller also wants to switch to a new configuration, do so now.
// This allows a clean switch, as we are waiting for the current activity
// to pause (so we will not destroy it), and have not yet started the
// next activity.
mService.mAmInternal.enforceCallingPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
if (stack != null) {
stack.mConfigWillChange = false;
}
if (DEBUG_CONFIGURATION) {
Slog.v(TAG_CONFIGURATION,
"Updating to new configuration after starting activity.");
}
mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
}
// Notify ActivityMetricsLogger that the activity has launched.
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
mLastStartActivityRecord);
return getExternalResult(mRequest.waitResult == null ? res
: waitForResult(res, mLastStartActivityRecord));
}
} finally {
onExecutionComplete();
}
}
//8:
private int executeRequest(Request request) {
if (TextUtils.isEmpty(request.reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
}
mLastStartReason = request.reason;
mLastStartActivityTimeMs = System.currentTimeMillis();
mLastStartActivityRecord = null;
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;
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 = ActivityManager.START_PERMISSION_DENIED;
}
}
final int userId = aInfo != null && aInfo.applicationInfo != null
? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
if (err == ActivityManager.START_SUCCESS) {
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+ "} from uid " + callingUid);
}
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
sourceRecord = mRootWindowContainer.isInAnyStack(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.isInStackLocked()) {
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().activitySupportsIntent(
intent.getComponent(), intent, resolvedType)) {
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().activitySupportsIntent(intent.getComponent(),
intent, resolvedType)) {
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 ActivityStack resultStack = 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;
}
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord, resultStack);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
callingPackage);
boolean restrictedBgActivity = false;
if (!abort) {
try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
"shouldAbortBackgroundActivityStart");
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
intent);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
// Merge the two options bundles, while realCallerOptions takes precedence.
ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
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;
}
}
//Hct add by liuyi for check camera password start
if (mService.mContext.getResources().getBoolean(R.bool.use_camera_need_input_password)
&& "com.android.camera".equals(aInfo.applicationInfo.packageName)) {
try {
ContentResolver resolver = mService.mContext.getContentResolver();
if (Settings.System.getInt(resolver, "check_camera_password", 0) != 1) {
// String password = Settings.System.getString(resolver, "hct_install_password");
String password_camera = Settings.System.getString(resolver, "use_camera_input_password");
Intent pwdIntent = new Intent(intent);
pwdIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
mService.mUiHandler.post(() -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mService.mUiContext);
final EditText et = new EditText(mService.mUiContext);
builder.setView(et)
.setTitle(R.string.use_camera_input_password_title)
.setPositiveButton(R.string.ok, (dialog, which) -> {
if (et.getText().toString().equals(password_camera)) {
Settings.System.putInt(resolver,
"check_camera_password", 1);
mService.mUiContext.startActivity(pwdIntent);
dialog.dismiss();
} else {
Toast.makeText(mService.mUiContext, R.string.use_camera_input_password_false,
Toast.LENGTH_SHORT).show();
}
}).setNegativeButton(R.string.cancel, (dialog, which) -> {
dialog.dismiss();
});
AlertDialog dialog = builder.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
dialog.setCancelable(false);
dialog.show();
});
abort = true;
}
} catch (Exception e) {
}
}
if (mService.mContext.getResources().getBoolean(R.bool.use_toolbag_need_input_password)
&& "com.hct.tool".equals(aInfo.applicationInfo.packageName)
) {
try {
ContentResolver resolver = mService.mContext.getContentResolver();
if (Settings.System.getInt(resolver, "check_toolbag_password", 0) != 1) {
// String password = Settings.System.getString(resolver, "hct_install_password");
String password_toolbag = Settings.System.getString(resolver, "use_toolbag_input_password");
Intent pwdIntent = new Intent(intent);
pwdIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
mService.mUiHandler.post(() -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mService.mUiContext);
final EditText et = new EditText(mService.mUiContext);
builder.setView(et)
.setTitle(R.string.use_toolbag_input_password_title)
.setPositiveButton(R.string.ok, (dialog, which) -> {
if (et.getText().toString().equals(password_toolbag)) {
Settings.System.putInt(resolver,
"check_toolbag_password", 1);
mService.mUiContext.startActivity(pwdIntent);
dialog.dismiss();
} else {
Toast.makeText(mService.mUiContext, R.string.use_toolbag_input_password_false,
Toast.LENGTH_SHORT).show();
}
}).setNegativeButton(R.string.cancel, (dialog, which) -> {
dialog.dismiss();
});
AlertDialog dialog = builder.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
dialog.setCancelable(false);
dialog.show();
});
abort = true;
}
} catch (Exception e) {
}
}
//Hct add by liuyi for check camera password end
mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
callingFeatureId);
if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, 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;
}
// 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));
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
if (DEBUG_PERMISSIONS_REVIEW) {
final ActivityStack focusedStack =
mRootWindowContainer.getTopDisplayFocusedStack();
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
true, false) + "} from uid " + callingUid + " on display "
+ (focusedStack == null ? DEFAULT_DISPLAY
: focusedStack.getDisplayId()));
}
}
}
// 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*/);
}
final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, callingFeatureId, intent, resolvedType, aInfo,
mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
sourceRecord);
//*/ freeme.zhongkai.zhu. 20160630. Prevent AutoStart
if (android.os.SystemProperties.get("ro.freeme_freemanager").equals("1")) {
if (mService.shouldPreventActivity(intent, aInfo, r)) {
Slog.w(ActivityStarter.TAG, "forbiden launch for activity: " + r);
SafeActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
//*/
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;
}
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
// If we are starting an activity that is not from the same uid as the currently resumed
// one, check whether app switches are allowed.
if (voiceSession == null && stack != null && (stack.getResumedActivity() == null
|| stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) {
mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp, intentGrants));
}
ActivityOptions.abort(checkedOptions);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
mService.onStartActivitySetDidAppSwitch();
mController.doPendingActivityLaunches(false);
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);
if (request.outActivity != null) {
request.outActivity[0] = mLastStartActivityRecord;
}
return mLastStartActivityResult;
}