假如A启动B:
startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,String resultWho, int requestCode,
int callingPid, int callingUid, int startFlags, Bundle options,
boolean componentSpecified, ActivityRecord[] outActivity):
传入参数为:
IApplicationThread caller:AActivity的进程内的ApplicationThread对象
Intent intent:要启动B的Intent
String resolvedType:BActivity的MIME TYPE
ActivityInfo aInfo:BActivity的ActivityInfo
IBinder resultTo:AActivity的token
String resultWho:AActivity的mEmbbedID,唯一标示这个Activity
int requestCode:startActivityForResult传入
int callingPid:调用者的PID
int callingUid:调用者的UID
int startFlags:0
Bundle options:由A传入的,一般为NULL
boolean componentSpecified:如果Intent的Component不为空的话,那么就为ture
<span style="font-size:18px;"> final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, int startFlags, Bundle options,
boolean componentSpecified, ActivityRecord[] outActivity) {
int err = ActivityManager.START_SUCCESS;
ProcessRecord callerApp = null;
if (caller != null) {
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;
}
}
if (err == ActivityManager.START_SUCCESS) {
final int userId = aInfo != null ? UserId.getUserId(aInfo.applicationInfo.uid) : 0;
Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false)
+ " u=" + userId + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
}
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
int index = indexOfTokenLocked(resultTo);
if (DEBUG_RESULTS) Slog.v(
TAG, "Will send result to " + resultTo + " (index " + index + ")");
if (index >= 0) {
sourceRecord = mHistory.get(index);
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
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) {
ActivityOptions.abort(options);
return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
resultRecord = sourceRecord.resultTo;
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(
sourceRecord, resultWho, requestCode);
}
}
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) {
if (resultRecord != null) {
sendActivityResultLocked(-1,
resultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
mDismissKeyguardOnNextActivity = false;
ActivityOptions.abort(options);
return err;
}
final int startAnyPerm = mService.checkPermission(
START_ANY_ACTIVITY, callingPid, callingUid);
final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
callingUid, aInfo.applicationInfo.uid, aInfo.exported);
if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) {
if (resultRecord != null) {
sendActivityResultLocked(-1,
resultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
mDismissKeyguardOnNextActivity = false;
String msg;
if (!aInfo.exported) {
msg = "Permission Denial: starting " + intent.toString()
+ " from " + callerApp + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " not exported from uid " + aInfo.applicationInfo.uid;
} else {
msg = "Permission Denial: starting " + intent.toString()
+ " from " + callerApp + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires " + aInfo.permission;
}
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
if (mMainStack) {
if (mService.mController != null) {
boolean abort = false;
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;
}
if (abort) {
if (resultRecord != null) {
sendActivityResultLocked(-1,
resultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
mDismissKeyguardOnNextActivity = false;
ActivityOptions.abort(options);
return ActivityManager.START_SUCCESS;
}
}
}
ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
intent, resolvedType, aInfo, mService.mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
if (outActivity != null) {
outActivity[0] = r;
}
if (mMainStack) {
if (mResumedActivity == null
|| mResumedActivity.info.applicationInfo.uid != callingUid) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch();
pal.r = r;
pal.sourceRecord = sourceRecord;
pal.startFlags = startFlags;
mService.mPendingActivityLaunches.add(pal);
mDismissKeyguardOnNextActivity = false;
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
if (mService.mDidAppSwitch) {
// This is the second allowed switch since we stopped switches,
// so now just generally allow switches. Use case: user presses
// home (switches disabled, switch to home, mDidAppSwitch now true);
// user taps a home icon (coming from home so allowed, we hit here
// and now allow anyone to switch again).
mService.mAppSwitchesAllowedTime = 0;
} else {
mService.mDidAppSwitch = true;
}
mService.doPendingActivityLaunchesLocked(false);
}
err = startActivityUncheckedLocked(r, sourceRecord,
startFlags, true, options);
if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
// Someone asked to have the keyguard dismissed on the next
// activity start, but we are not actually doing an activity
// switch... just dismiss the keyguard now, because we
// probably want to see whatever is behind it.
mDismissKeyguardOnNextActivity = false;
mService.mWindowManager.dismissKeyguard();
}
return err;
}</span>
1.通过caller来得到ProcessReocrd对象,判断调用者进程是否存在,如果存在的话,那么将callingPid与callingUid重新赋值为ProcessRecord中的值
2.声明了两个ActivityRecord引用,一个为sourceRecord,一个为resultRecord。sourceRecord代表着调用者的ActivityRecord,通过传入的token来得到的,此处就是AActivity的Record,而resultRecord只有在requestCode>1的时候才会被赋值为sourceRecord,否则就是null,可以看出,resultRecord是用来进行回调的,在BActivity中设置了setResult后,会通过resultRecord来传递result值。
3.得到Intent的launchFlags,此时会判断launchFlags中是否有Intent.FLAG_ACTIVITY_FORWARD_RESULT,也就是重定向结果,因为Android允许将结果重定向,也就是A通过startActivityForResult启动B,而B可以通过startActivity,然后加入该标志位启动C,C调用setResult后,A就能的到C中的结果了。此处的逻辑如下:
当launchFlags中有Intent.FLAG_ACTIVITY_FORWARD_RESULT的时候,判断requestCode是否大于等于0,如果大于等于0的话,那么就直接返回错误码了,因为B启动C的时候不允许通过startActivityForResult启动,如果是通过startActivity的话,那么就会执行如下代码:
resultRecord = sourceRecord.resultTo;
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(
sourceRecord, resultWho, requestCode);
}
首先会将resultRecord重新赋值为sourceRecord.resultTo,此时sourceRecord.resultTo就是代表的A,因为A是通过startActivityForResult启动B,然后B通过startActivity启动C,所以resultRecord代表的就是A的ActivityRecord,然后将resultWho也重新赋值为A的ActivityRecord的resultWho,以及requestCode也重新被赋值,并且将B的resultTo设置成null,因为它不需要再接收结果了,所以设成null,然后通过resultRecord.removeResultLocked,将B从A中的回调删除。
接着会判断Intent的Component,以及B的ActivityInfo是否为null,如果有一个为null的话,那么直接返回错误,接着判断调用者是否有启动该Activity的权限,因为Activity中也可以在XML中配置permission,所以需要检查应用程序是否有启动该Activity的权限。
接着创建一个ActivityRecord r,这个ActivityRecord对象就代表着要启动的BActivity,接着如下代码会判断当前处于Resume状态的Activity是否为null,并且当前Resume状态的Activity的uid和调用者的UID是否相同,如果有一个不相同的话,那么直接返回错误码。代码如下:
if (mResumedActivity == null
|| mResumedActivity.info.applicationInfo.uid != callingUid) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch();
pal.r = r;
pal.sourceRecord = sourceRecord;
pal.startFlags = startFlags;
mService.mPendingActivityLaunches.add(pal);
mDismissKeyguardOnNextActivity = false;
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
接着就会检查mPendingActivityLaunches是否为空,这个列表中保存的是正在等待要启动的ActivityRecord,那么就会遍历这个列表,然后调用startActivityUnckedLocked来启动Pending列表中的所有Activity,启动完之后,再清除掉mPendingActivityLaunches中的记录。
接着调用startActivityUnckedLocked函数,来进行下一步的启动。