Activity Startup
Contents
Startfrom click shortcut on Launcher.4
Activity.startActivityForResult.7
Instrumentation.execStartActivity.8
Step7: ActivityManagerService.startActivity.9
Step8: ActivityStack.startActivityMayWait.10
Step9: ActivityStack. startActivityLocked.12
Step10: ActivityStack.startActivityUncheckedLocked.17
Step11: ActivityStack. startActivityLocked.25
Step12: ActivityStack.resumeTopActivityLocked.28
Step13: ActivityStack.startPausingLocked.36
Step14: ApplicationThread. schedulePauseActivity.39
Step15: ActivityThread.queueOrSendMessage.39
Step16: ActivityThread.Handler.handleMessage.39
Step17: ActivityThread.handlePauseActivity.40
Step18: ActivityThread.performPauseActivity.41
Step19: ActivityManagerService.activityPaused().42
Step20: ActivityStack.activityPaused().42
Step21: ActivityStack.completePauseLocked().43
Step22: ActivityStack.resumeTopActivityLocked().44
Step23: ActivityStack.startSpecificActivityLocked ().44
Step24: ActivityManagerService. startProcessLocked().45
Step25: ActivityManagerService.startProcessLocked().47
Step27: ActivityThread.main.49
Step28: ActivityThread.attach(false).50
Step 29: ActivityManagerService.attachApplication.50
Step 30: ActivityManagerService.attachApplicationLocked.51
Step31: ActivityStack. realStartActivityLocked.56
Step32: ActivityThread.scheduleLaunchActivity.58
Step33: ActivityThread. queueOrSendMessage(H.LAUNCH_ACTIVITY, r);58
Step34: ActivityThread.Handler.handleMessage.58
ActivityThread.handleLaunchActivity(r, null).58
启动一个新Activity可以通过2种方式,通过点击桌面图标;或者调用startActivity()/StartActivityForResult()。这个文档里主要讨论通过点击桌面应用图标的方式启动Activity。
为了讲解方便,把要启动的Activity命名为MyActivity 。在AndroidManifest.xml文件中做如下配置:
<activity android:name=".MyActivity"
android:label="@string/app_name">
<intent-filter>
<actionandroid:name="android.intent.action.MAIN" />
<categoryandroid:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
先看看时序图有个大概的印象,下面就具体详细分析每一步是如何实现的。
在Android系统中,应用程序是由Launcher启动起来的,其实,Launcher本身也是一个应用程序,就是我们所熟知的Home。其它的应用程序安装后,就会在Launcher的界面上出现一个相应的图标,点击这个图标时,Launcher就会把对应的应用程序启动起来。
在onClick()方法中不仅需要处理某个应用的启动,还包括针对点击folder和AllAppsButton的处理。
http://opengrok.sonyericsson.net/jellybean/xref/jb-lagan/packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
1845 /**
1846 * Launches the intent referred by theclicked shortcut.
1847 *
1848 * @param vThe view representing the clicked shortcut.
1849 */
1850 public voidonClick(View v) {
...
//Tag:
Unlike IDs, tags are not used toidentify views. Tags are essentially an extra piece of information that can beassociated with a view. They are most often used as a convenience to store datarelated to views in the views themselves rather than by putting them in aseparate structure.
1861 Objecttag = v.getTag();
1862 if (taginstanceof ShortcutInfo) {
1863 //Open shortcut
1864 finalIntent intent = ((ShortcutInfo) tag).intent;
1865 int[]pos = new int[2];
1866 v.getLocationOnScreen(pos);
1867 intent.setSourceBounds(newRect(pos[0], pos[1],
1868 pos[0] + v.getWidth(), pos[1] + v.getHeight()));
1869 //这个函数调用是Activity启动的入口
1870 boolean success =startActivitySafely(v, intent, tag);
1871 //设置图标被点击、选中的状态
1872 if(success && v instanceof BubbleTextView) {
1873 mWaitingForResume = (BubbleTextView) v;
1874 mWaitingForResume.setStayPressed(true);
1875 }
1876 } else if(tag instanceof FolderInfo) {
1877 if (vinstanceof FolderIcon) {
1878 FolderIcon fi = (FolderIcon) v;
1879 handleFolderClick(fi);
1880 }
1881 } else if(v == mAllAppsButton) {
1882 if(isAllAppsVisible()) {
1883 showWorkspace(true);
1884 }else {
1885 onClickAllAppsButton(v);
1886 }
1887 }
1888 }
2009 boolean startActivitySafely(View v, Intentintent, Object tag) {
2010 booleansuccess = false;
2011 try {
2012 success = startActivity(v, intent,tag);
2013 } catch(ActivityNotFoundException e) {
2014 Toast.makeText(this,R.string.activity_not_found, Toast.LENGTH_SHORT).show();
2015 Log.e(TAG, "Unable to launch. tag=" + tag + "intent=" + intent, e);
2016 }
2017 returnsuccess;
2018 }
下面继续看Launcher.startActivity()
1982 boolean startActivity(View v, Intentintent, Object tag) {
1983 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1984
1985 try {
1986 //Only launch using the new animation if the shortcut has not opted out (this isa
1987 //private contract between launcher and may be ignored in the future).
1988 boolean useLaunchAnimation = (v != null) &&
1989 !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
//下面这段绿色部分是插入的注释
// useLaunchAnimation should betrue, because “INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION” is NOT set inpackages/apps/Launcher2/src/com/android/launcher2/LauncherProvider.java,
483 if (version < 12) {
484 // Contact shortcuts need adifferent set of flags to be launched now
485 // The updateContactsShortcutschange is idempotent, so we can keep using it like
486 // back in the Donut days
487 updateContactsShortcuts(db);
488 version = 12;
489 }
1990 if(useLaunchAnimation) {
1991 ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
1992 v.getMeasuredWidth(), v.getMeasuredHeight());
1993
1994 startActivity(intent, opts.toBundle());
1995 }else {
1996 startActivity(intent);
1997 }
1998 return true;
1999 } catch(SecurityException e) {
2000 Toast.makeText(this, R.string.activity_not_found,Toast.LENGTH_SHORT).show();
2001 Log.e(TAG, "Launcher does not have the permission to launch "+ intent +
2002 ". Make sure to create a MAIN intent-filter for the correspondingactivity " +
2003 "or use the exportedattribute for this activity. "
2004 + "tag="+ tag + " intent=" + intent, e);
2005 }
2006 returnfalse;
2007 }
Activity.startActivity
这个函数里面直接调用startActivityForResult(),其中requestCode=-1表示不需要返回结果。
Activity.java
public void startActivity(Intentintent, Bundle options) {
if (options!= null) {
startActivityForResult(intent, -1, options);
} else {
// Notewe want to go through this call for compatibility with
//applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
Activity.startActivityForResult
这里的mMainThread是ActivityThread类型的Activity类成员变量,它代表的是应用程序的主线程,也就是Launcher应用程序运行的进程。这里通过mMainThread.getApplicationThread获得它里面的ApplicationThread成员变量,它是一个 Binder对象,后面我们会看到,ActivityManagerService会使用它来和ActivityThread来进行进程间通信。
这里的mToken也是Activity类的成员变量,它是一个Binder对象的远程接口。它在attch()方法中被赋值。
public void startActivityForResult(Intent intent, intrequestCode, Bundle options) {
if (mParent== null) {// mParent == null表示启动的不是sub-activity
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this,mMainThread.getApplicationThread(), mToken, this,
intent, requestCode,options);
if (ar !=null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if(requestCode >= 0) {
// Ifthis 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 keepthe
//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;
}
} else {
if(options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
//Note we want to go through this method for compatibility with
//existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
Instrumentation.execStartActivity
在Instrumentation.java中相同名字的函数一共有2个,一个是为了启动Activity,另外一个是在Fragment中启动Activty。
检查mActivityMonitors列表中是否已经有该Activity对象了,如果存在而且该对象处于block状态,则不启动该Activity
调用AMS.execStartActivity()把启动新Activity的任务通过IPC交给AMS来完成。至此程序的运行已经脱离了Launcher当前运行的进程,进入到AMS的线程中去了。
调用checkStartActivityResult检查异常返回结果。
Instrumentation.java
public ActivityResult execStartActivity(
Contextwho, IBinder contextThread, IBinder token,Activity target,
Intentintent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
//首先检查启动队列中是否已经包含了相同的启动任务,如果已经存在就不需要再启动新的了
if(mActivityMonitors != null) {
synchronized (mSync) {
finalint N = mActivityMonitors.size();
for(int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.setAllowFds(false);
intent.migrateExtraStreamToClipData();
int result =ActivityManagerNative.getDefault()
.startActivity(whoThread,intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ?target.mEmbeddedID : null,
requestCode, 0, null,null, options);
checkStartActivityResult(result, intent);
} catch(RemoteException e) {
}
return null;
}
Step 7: ActivityManagerService.startActivity
此处传入的参数列表:
IApplicationThread caller: |
ApplicationThread类型的Binder实体 |
int callingUid: |
-1 |
Intent intent: |
|
String resolvedType: |
这里的intent.resolveTypeIfNeeded返回这个intent的MIME类型,在这个例子中,没有AndroidManifest.xml设置MainActivity的MIME类型,因此,这里返回null。 |
IBinder resultTo: |
一个代表发出启动新Activity请求的Activity token |
String resultWho: |
target != null ? target.mEmbeddedID : null 这里的target不为null,但是target.mEmbddedID为null |
int requestCode: |
-1 |
int startFlags: |
0 |
String profileFile: |
null |
ParcelFileDescriptor profileFd: |
null |
WaitResult outResult: |
null |
Configuration config: |
null |
Bundle options: |
|
这个函数所做的主要工作:
通过调用enforceNotIsolatedCaller()判断当前的请求者Binder.getCallingUid()是否允许启动Activity
ActivityManagerService.java
public final int startActivity(IApplicationThread caller,
Intent intent, String resolvedType, IBinderresultTo,
StringresultWho, int requestCode, int startFlags,
StringprofileFile, ParcelFileDescriptor profileFd, Bundle options) {
enforceNotIsolatedCaller("startActivity");//安全检查,用户是否已经被隔离,这里的用户id是通过Binder.getCallingUid()取得的
int userId =0;
if(intent.getCategories() != null &&intent.getCategories().contains(Intent.CATEGORY_HOME)) {
//Requesting home, set the identity to the current user
// HACK!
userId =mCurrentUserId;
} else {
// TODO:Fix this in a better way - calls coming from SystemUI should probably carry
// thecurrent user's userId
if(Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
userId = 0;
} else {
userId = Binder.getOrigCallingUser();
}
}
returnmMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
resultTo, resultWho,requestCode, startFlags, profileFile, profileFd,
null, null, options, userId);
}
Step 8: ActivityStack.startActivityMayWait
此处传入的参数列表:
IApplicationThread caller: |
ApplicationThread类型的Binder实体 |
int callingUid: |
-1 |
Intent intent: |
|
String resolvedType: |
这里的intent.resolveTypeIfNeeded返回这个intent的MIME类型,在这个例子中,没有AndroidManifest.xml设置MainActivity的MIME类型,因此,这里返回null。 |
IBinder resultTo: |
一个代表发出启动新Activity请求的Activity token |
String resultWho: |
target != null ? target.mEmbeddedID : null 这里的target不为null,但是target.mEmbddedID为null |
int requestCode: |
-1 |
int startFlags: |
0 |
String profileFile: |
null |
ParcelFileDescriptor profileFd: |
null |
WaitResult outResult: |
null |
Configuration config: |
null |
Bundle options: |
|
int userId: |
Binder.getOrigCallingUser() |
这个函数所做的主要工作:
调用resolveActivity()从PackageMangerService那里获取activity信息aInfo
通过调用ActivityManagementService.startActivityMayWait()获取于此Activity相关的Application信息,并且保存在aInfo.applicationInfo中
final int startActivityMayWait(IApplicationThread caller,int callingUid,
Intentintent, String resolvedType, IBinder resultTo,
StringresultWho, int requestCode, int startFlags, String profileFile,
ParcelFileDescriptor profileFd, WaitResult outResult, Configurationconfig,
Bundle options, int userId) {
// Refusepossible leaked file descriptors
if (intent !=null && intent.hasFileDescriptors()) {
throw newIllegalArgumentException("File descriptors passed in Intent");
}
booleancomponentSpecified = intent.getComponent() != null; // componentSpecified=true
// Don'tmodify the client's object!
intent = newIntent(intent);
// Collectinformation about the target of the Intent.
ActivityInfoaInfo = resolveActivity(intent, resolvedType, startFlags,
profileFile, profileFd, userId);
if (aInfo !=null && mService.isSingleton(aInfo.processName, aInfo.applicationInfo)){
userId =0;
}
aInfo =mService.getActivityInfoForUser(aInfo, userId);
synchronized(mService) {
intcallingPid;
//传入的参数callingUid=-1
if(callingUid >= 0) {
callingPid = -1;
} else if(caller == null) {
callingPid = Binder.getCallingPid();
callingUid = Binder.getCallingUid();
} else {
callingPid = callingUid = -1;
}
//传入参数config=null,所以mConfigWillChange=false
mConfigWillChange = config != null
&& mService.mConfiguration.diff(config) != 0;
if(DEBUG_CONFIGURATION) Slog.v(TAG,
"Starting activity when config will change = " +mConfigWillChange);
//http://blog.chinaunix.net/uid-12469487-id-3050585.html
finallong origId = Binder.clearCallingIdentity();
//对于这个判断(aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0,因为aInfo.applicationInfo.flags中不包含ApplicationInfo.FLAG_CANT_SAVE_STATE标志,所以它的值=false
//下面这段不会执行
if(mMainStack && aInfo != null &&
(aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE)!= 0) {
…
}
int res =startActivityLocked(caller, intent, resolvedType,
aInfo, resultTo, resultWho,requestCode, callingPid, callingUid,
startFlags, options,componentSpecified, null);
if(mConfigWillChange && mMainStack) { // mConfigWillChange=false
// Ifthe 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.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
mConfigWillChange = false;
if(DEBUG_CONFIGURATION) Slog.v(TAG,
"Updating to new configuration after starting activity.");
mService.updateConfigurationLocked(config, null, false, false);
}
Binder.restoreCallingIdentity(origId);
if(outResult != null) { //outResult=null
outResult.result = res;
if(res == ActivityManager.START_SUCCESS) {
mWaitingActivityLaunched.add(outResult);
do {
try {
mService.wait();
} catch (InterruptedException e) {
}
}while (!outResult.timeout && outResult.who == null);
}else if (res == ActivityManager.START_TASK_TO_FRONT) {
ActivityRecordr = this.topRunningActivityLocked(null);
if (r.nowVisible) {
outResult.timeout = false;
outResult.who = new ComponentName(r.info.packageName, r.info.name);
outResult.totalTime = 0;
outResult.thisTime = 0;
}else {
outResult.thisTime = SystemClock.uptimeMillis();
mWaitingActivityVisible.add(outResult);
do {
try {
mService.wait();
} catch (InterruptedException e) {
}
} while (!outResult.timeout && outResult.who == null);
}
}
}
returnres;
}
}
Step 9: ActivityStack. startActivityLocked
这个函数所做的主要工作:
从传进来的参数caller得到调用者的进程信息,并保存在callerApp变量中,这里就是Launcher应用程序的进程信息了。
前面说过,参数resultTo是Launcher这个Activity里面的一个Binder对象,通过它可以获得Launcher这个启动者Activity的相关信息,保存在sourceRecord变量中。
通过launchFlags = intent.getFlags()获取launchFlags信息,对launchFlags中的各种flag进行判断和处理。针对当前场景下,我们只设置了NEW_TASK标志,所以这里的判断和检查都不适用。
判断callingPid和callingUid是否有权限启动新的Activity。
创建即将要启动的Activity的相关信息,并保存在(ActivityRecord)r变量中
如果有pending activities需要先处理,调用mService.doPendingActivityLaunchesLocked(),在doPendingActivityLaunchesLocked() 中会调用startActivityUncheckedLocked()进一步处理,也就是先启动pending acitivies。
上面的事情做完后,才执行startActivityUncheckedLocked()启动我们要启动的Activity。
2403 final intstartActivityLocked(IApplicationThread caller,
2404 Intent intent, String resolvedType,ActivityInfo aInfo, IBinder resultTo,
2405 String resultWho, int requestCode,
2406 int callingPid, int callingUid, intstartFlags, Bundle options,
2407 boolean componentSpecified,ActivityRecord[] outActivity) {
2408
2409 int err =ActivityManager.START_SUCCESS;
2410
2411 ProcessRecord callerApp = null;
//从传进来的参数caller得到调用者的进程信息,并保存在callerApp变量中,这里就是Launcher应用程序的进程信息了。
2412 if(caller != null) {
2413 callerApp = mService.getRecordForAppLocked(caller);
2414 if(callerApp != null) {
2415 callingPid = callerApp.pid;
2416 callingUid= callerApp.info.uid;
2417 }else {
2418 Slog.w(TAG, "Unable to find app for caller " + caller
2419 + " (pid=" + callingPid + ") when starting: "
2420 + intent.toString());
2421 err =ActivityManager.START_PERMISSION_DENIED;
2422 }
2423 }
2424
2425 if (err== ActivityManager.START_SUCCESS) {
2426 finalint userId = aInfo != null ? UserId.getUserId(aInfo.applicationInfo.uid) : 0;
2427 Slog.i(TAG, "START {" + intent.toShortString(true, true, true,false)
2428 + " u=" + userId + "} from pid " + (callerApp !=null ? callerApp.pid : callingPid));
//更新env环境变量信息env->ReleaseStringUTFChars(activity, actStr);
2429 mActivityTrigger.activityStartTrigger(intent);
2430 }
2431
2432 ActivityRecord sourceRecord = null;
2433 ActivityRecord resultRecord = null;
//前面说过,参数resultTo是Launcher这个Activity里面的一个Binder对象,通过它可以获得Launcher这个Activity的相关信息,保存在sourceRecord变量中。
2434 if(resultTo != null) { //resultTo !=null
2435 intindex = indexOfTokenLocked(resultTo);
2436 if(DEBUG_RESULTS) Slog.v(
2437 TAG, "Will send result to " + resultTo + " (index "+ index + ")");
2438 if(index >= 0) {
2439 sourceRecord = mHistory.get(index);
//resultCode=-1
2440 if (requestCode >= 0 && !sourceRecord.finishing) {
2441 resultRecord = sourceRecord;
2442 }
2443 }
2444 }
2445
2446 intlaunchFlags = intent.getFlags();
2447 //条件不满足
2448 if((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2449 && sourceRecord != null) {
…
2464 }
2465 //条件不满足
2466 if (err== ActivityManager.START_SUCCESS && intent.getComponent() == null) {
2467 // We couldn't find a class that canhandle the given Intent.
2468 //That's the end of that!
2469 err =ActivityManager.START_INTENT_NOT_RESOLVED;
2470 }
2471 //ainfo != null
2472 if (err== ActivityManager.START_SUCCESS && aInfo == null) {
2473 // Wecouldn't find the specific class specified in the Intent.
2474 //Also the end of the line.
2475 err =ActivityManager.START_CLASS_NOT_FOUND;
2476 }
2477 //条件不满足
2478 if (err!= ActivityManager.START_SUCCESS) {
2479 if(resultRecord != null) {
2480 sendActivityResultLocked(-1,
2481 resultRecord, resultWho, requestCode,
2482 Activity.RESULT_CANCELED, null);
2483 }
2484 mDismissKeyguardOnNextActivity = false;
2485 ActivityOptions.abort(options);
2486 return err;
2487 }
2488 //此处的启动当然有权限
2489 final intstartAnyPerm = mService.checkPermission(
2490 START_ANY_ACTIVITY, callingPid, callingUid);
2491 final intcomponentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
2492 callingUid, aInfo.applicationInfo.uid, aInfo.exported);
2493 if (startAnyPerm != PERMISSION_GRANTED&& componentPerm != PERMISSION_GRANTED) {
2494 if(resultRecord != null) {
2495 sendActivityResultLocked(-1,
2496 resultRecord, resultWho, requestCode,
2497 Activity.RESULT_CANCELED, null);
2498 }
2499 mDismissKeyguardOnNextActivity = false;
2500 String msg;
2501 if(!aInfo.exported) {
2502 msg = "Permission Denial: starting " + intent.toString()
2503 + " from " + callerApp + " (pid=" + callingPid
2504 + ", uid=" + callingUid + ")"
2505 + " not exported from uid " + aInfo.applicationInfo.uid;
2506 }else {
2507 msg = "Permission Denial:starting " + intent.toString()
2508 + " from " + callerApp + " (pid=" + callingPid
2509 + ", uid=" + callingUid + ")"
2510 + " requires " + aInfo.permission;
2511 }
2512 Slog.w(TAG, msg);
2513 thrownew SecurityException(msg);
2514 }
2515
2516 if(mMainStack) {
2517 if(mService.mController != null) {
2518 boolean abort = false;
2519 try {
2520 // The Intent we give to the watcher has the extra data
2521 // stripped off, since it can contain private information.
2522 Intent watchIntent = intent.cloneFilter();
//mService.mController.activityStarting() always return true
2523 abort = !mService.mController.activityStarting(watchIntent,
2524 aInfo.applicationInfo.packageName);
2525 }catch (RemoteException e) {
2526 mService.mController = null;
2527 }
2528
2529 if (abort) {
2530 if (resultRecord != null) {
2531 sendActivityResultLocked(-1,
2532 resultRecord, resultWho,requestCode,
2533 Activity.RESULT_CANCELED, null);
2534 }
2535 // We pretend to the caller that it was really started, but
2536 // they will just get a cancel result.
2537 mDismissKeyguardOnNextActivity = false;
2538 ActivityOptions.abort(options);
2539 return ActivityManager.START_SUCCESS;
2540 }
2541 }
2542 }
2543 //创建即将要启动的Activity的相关信息,并保存在r变量中
2544 ActivityRecord r = new ActivityRecord(mService, this, callerApp,callingUid,
2545 intent, resolvedType, aInfo, mService.mConfiguration,
2546 resultRecord, resultWho, requestCode, componentSpecified);
2547 if(outActivity != null) {
2548 outActivity[0] = r;
2549 }
2550 // 此场景下 条件不满足,因为mService.checkAppSwitchAllowedLocked() should return true
2551 if(mMainStack) {
2552 if(mResumedActivity == null
2553 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2554 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,"Activity start")) {
2555 PendingActivityLaunch pal = new PendingActivityLaunch();
2556 pal.r = r;
2557 pal.sourceRecord = sourceRecord;
2558 pal.startFlags = startFlags;
2559 mService.mPendingActivityLaunches.add(pal);
2560 mDismissKeyguardOnNextActivity = false;
2561 ActivityOptions.abort(options);
2562 return ActivityManager.START_SWITCHES_CANCELED;
2563 }
2564 }
2565//是否允许Activity switch,这个变量在ActivityManagerService.java.stopAppSwitches()中被设置成false,与之个的一个变量是APP_SWITCH_DELAY_TIME,关于它的解释如下:
// Amount of time after a call to stopAppSwitches() duringwhich we will prevent further untrusted switches from happening.
2566 if(mService.mDidAppSwitch) {
2567 // This is the second allowed switch since we stopped switches,
2568 // so now just generally allow switches. Use case: user presses
2569 // home (switches disabled, switch to home, mDidAppSwitch now true);
2570 // user taps a home icon (coming from home so allowed, we hit here
2571 // and now allow anyone to switch again).
2572 mService.mAppSwitchesAllowedTime = 0;
2573 }else {
2574 mService.mDidAppSwitch = true;
2575 }
2576 //如果有pending activities需要先处理
2577 mService.doPendingActivityLaunchesLocked(false);
2578 }
2579
2580 err = startActivityUncheckedLocked(r,sourceRecord,
2581 startFlags, true, options);
2582 if(mDismissKeyguardOnNextActivity && mPausingActivity == null) {
2583 //Someone asked to have the keyguard dismissed on the next
2584 //activity start, but we are not actually doing an activity
2585 //switch... just dismiss the keyguard now,because we
2586 //probably want to see whatever is behind it.
2587 mDismissKeyguardOnNextActivity = false;
2588 mService.mWindowManager.dismissKeyguard();
2589 }
2590 returnerr;
2591 }
Step 10: ActivityStack.startActivityUncheckedLocked
这个函数所做的主要工作:
这个函数的最重要工作就是确定Activity运行的Task,各种情况判断比较多,但是对于本文涉及的场景就简单些,因为我们的Activity在开始阶段的launcher.startActivity中就已经为intent设置了FLAG_ACTIVITY_NEW_TASK标志,所以最终就会创建一个新的Task。
首先获得intent的标志值,保存在launchFlags变量中。
根据Activity.launchMode来判断是否需要给当前Activity. launchFlags添加Intent.FLAG_ACTIVITY_NEW_TASK标志。为(target activity)r.launchFlags添加FLAG_ACTIVITY_NEW_TASK标志的条件包括:
1)sourceRecord == null
2)sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3)r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
满足(r.resultTo != null &&(launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0)条件,立刻返回结果给调用者。因为startActivityForResult()是不能跨越不同task的。
调用findTaskLocked()搜索当前有没有Task可以用来执行这个Activity。由于r.launchMode的值不为ActivityInfo.LAUNCH_SINGLE_INSTANCE,因此,它通过findTaskLocked函数来查找存不存这样的Task。如果是第一次运行,返回的结果是null,(只有当目标Activity存在而且在task顶端才满足查找条件)即taskTop为null,因此,需要创建一个新的Task来启动这个Activity。
检查需要启动的Activity与现在的topactivity是否相同?不同,因此不需要执行resume top activtity,进一步分析:resume top activity还必须满足其他条件:launchMode中还必须设置了FLAG_ACTIVITY_SINGLE_TOP或者.LAUNCH_SINGLE_TOP或者LAUNCH_SINGLE_TASK。
如果没有可以可用的task,给当前的Activity创建和赋值一个task.
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent),null, true);
调用startActivityLocked(r, newTask,doResume, keepCurTransition, options)继续执行。
2603 final intstartActivityUncheckedLocked(ActivityRecord r,
2604 ActivityRecord sourceRecord, intstartFlags, boolean doResume,
2605 Bundle options) {
//doReume=true
2606 finalIntent intent = r.intent;
2607 final intcallingUid = r.launchedFromUid;
2608 final intuserId = r.userId;
2609 //函数首先获得intent的标志值,保存在launchFlags变量中。
2610 intlaunchFlags = intent.getFlags();
2611 //这个intent的标志值的位Intent.FLAG_ACTIVITY_NO_USER_ACTION没有置位,因此 ,成员变量mUserLeaving的值为true。
2612 // We'llinvoke onUserLeaving before onPause only if the launching
2613 //activity did not explicitly state that this is an automated launch.
2614 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) ==0; // mUserLeaving=true
2615 if(DEBUG_USER_LEAVING) Slog.v(TAG,
2616 "startActivity() => mUserLeaving=" + mUserLeaving);
2617
2618 // If thecaller has asked not to resume at this point, we make note
2619 // ofthis in the record so that we can skip it when trying to find
2620 // thetop running activity.
2621 if(!doResume) {
2622 r.delayedResume = true;
2623 }
2624 //没有设置这个标志,所以notTop=null
2625 ActivityRecord notTop =(launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2626 != 0 ? r : null;
2627 //startFlags = 0 这个参数是从上面一路传下来的
2628 // If theonlyIfNeeded flag is set, then we can do this if the activity
2629 // beinglaunched is the same as the one making the call... or, as
2630 // aspecial case, if we do not know the caller then we count the
2631 //current top activity as the caller.
2632 if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED)!= 0) {
2633 ActivityRecord checkedCaller = sourceRecord;
2634 if(checkedCaller == null) {
2635 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
2636 }
2637 if(!checkedCaller.realActivity.equals(r.realActivity)) {
2638 // Caller is not the same as launcher, so always needed.
2639 startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
2640 }
2641 }
2642
2643 if(sourceRecord == null) {
2644 //This activity is not being started from another... in this
2645 //case we -always- start a new task.
2646 if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
2647 Slog.w(TAG, "startActivity called from non-Activity context;forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
2648 + intent);
2649 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2650 }
2651 } else if(sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2652 //The original activity who is starting us is running as a single
2653 //instance... this new activity it isstarting must go on its
2654 // own task.
2655 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2656 } else if(r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
2657 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2658 //The activity being started is a single instance... it always
2659 //gets launched into its own task.
2660 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2661 }
2662//我们刚好满足了下面这个条件,所以launcher就会通过onActivityResult()收到启动新activity结果的回调
2663 if(r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)!= 0) {
2664 //For whatever reason this activity is being launched into a new
2665 // task... yet the caller has requested a resultback. Well, that
2666 // ispretty messed up, so instead immediately send back a cancel
2667 //and let the new task continue launched as normal without a
2668 //dependency on its originator.
2669 Slog.w(TAG, "Activity is launching as a new task, so cancellingactivity result.");
2670 sendActivityResultLocked(-1,
2671 r.resultTo, r.resultWho, r.requestCode,
2672 Activity.RESULT_CANCELED, null);
2673 r.resultTo = null;
2674 }
2675
2676 booleanaddingToTask = false;
2677 booleanmovedHome = false;
2678 TaskRecord reuseTask = null;
//在要启动new Activity之初的Launcher.startActivity中,Intent.FLAG_ACTIVITY_NEW_TASK就已经被设置了,因此下面的语句将被执行
// 这段代码的逻辑是,当前有没有Task可以用来执行这个Activity。由于r.launchMode的值不为 ActivityInfo.LAUNCH_SINGLE_INSTANCE,因此,它通过findTaskLocked函数来查找存不存这样的Task, 这里返回的结果是null,即taskTop为null,因此,需要创建一个新的Task来启动这个Activity。
2679 if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
2680 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
2681 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2682 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2683 // If bring to front is requested,and no result is requested, and
2684 // we can find a task that wasstarted with this same
2685 // component, then instead oflaunching bring that one to the front.
2686 if (r.resultTo == null) {
2687 // See if there is a task tobring to the front. If this is
2688 // a SINGLE_INSTANCE activity,there can be one and only one
2689 // instance of it in thehistory, and it is always in its own
2690 // unique task, so we do aspecial search.
2691 ActivityRecord taskTop = r.launchMode !=ActivityInfo.LAUNCH_SINGLE_INSTANCE
2692 ? findTaskLocked(intent, r.info)//条件是只有当目标Activity存在而且在task顶端。请牢记这个条件,只有这样后续的moveTaskToFrontLocked()才会成立
2693 : findActivityLocked(intent, r.info);
2694 if (taskTop != null) { //当前场景中,我们假设这是第一次启动,所以taskTop=null
2695 if (taskTop.task.intent == null) {
2696 // This task was started because of movement of
2697 // the activity based on affinity... now that we
2698 // are actually launching it, we can assign the
2699 // base intent.
2700 taskTop.task.setIntent(intent, r.info);
2701 }
2702 // If the target task is not in the front, then we need
2703 // to bring it to the front... except... well, with
2704 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
2705 // to have the same behavior as if a new instance was
2706 // being started, which means not bringing it to the front
2707 // if the caller is not itself in the front.
2708 ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
2709 if (curTop != null && curTop.task != taskTop.task) {//如果当前最顶端运行的activity.task不是我们要恢复的task
2710 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
2711 boolean callerAtFront = sourceRecord == null
2712 || curTop.task== sourceRecord.task;
2713 if (callerAtFront) {//如果是调用者在最顶端
2714 // We really dowant to push this one into the
2715 // user's face,right now.
2716 movedHome = true;
2717 moveHomeToFrontFromLaunchLocked(launchFlags);
2718 moveTaskToFrontLocked(taskTop.task, r, options);
2719 options = null;
2720 }
2721 }
2722 // If the caller has requested that the target task be
2723 // reset, then do so.
2724 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2725 taskTop =resetTaskIfNeededLocked(taskTop, r);
2726 }
2727 if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
2728 // We don't need to start a new activity, and
2729 // the client said not to doanything if that
2730 // is the case, so this is it! And for paranoia, make
2731 // sure we have correctly resumed the top activity.
2732 if (doResume) {
2733 resumeTopActivityLocked(null, options);
2734 } else {
2735 ActivityOptions.abort(options);
2736 }
2737 return ActivityManager.START_RETURN_INTENT_TO_CALLER;
2738 }
2739 if ((launchFlags &
2740 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
2741 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)){
2742 // The caller has requested to completely replace any
2743 // existing task with its new activity. Well that should
2744 // not be too hard...
2745 reuseTask = taskTop.task;
2746 performClearTaskLocked(taskTop.task.taskId);
2747 reuseTask.setIntent(r.intent, r.info);
2748 } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
2749 || r.launchMode ==ActivityInfo.LAUNCH_SINGLE_TASK
2750 || r.launchMode ==ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2751 // In this situation we want to remove all activities
2752 // from the task up to the one being started. In most
2753 // cases this means we are resetting the task to its
2754 // initial state.
2755 ActivityRecord top =performClearTaskLocked(
2756 taskTop.task.taskId, r, launchFlags);
2757 if (top != null) {
2758 if(top.frontOfTask) {
2759 // Activity aliases may meanwe use different
2760 // intents forthe top activity, so make sure
2761 // the task nowhas the identity of the new
2762 // intent.
2763 top.task.setIntent(r.intent, r.info);
2764 }
2765 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
2766 top.deliverNewIntentLocked(callingUid,r.intent);
2767 } else {
2768 // A special case:we need to
2769 // start theactivity because it is not currently
2770 // running, and thecaller has asked to clear the
2771 // current task tohave this activity at the top.
2772 addingToTask =true;
2773 // Now pretend likethis activity is being started
2774 // by the top ofits task, so it is put in the
2775 // right place.
2776 sourceRecord =taskTop;
2777 }
2778 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
2779 // In this case the top activity on the task is the
2780 // same as the one being launched, so we take that
2781 // as a request to bring the task to the foreground.
2782 // If the top activity in the task is the root
2783 // activity, deliver this new intent to it if it
2784 // desires.
2785 if((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2786 &&taskTop.realActivity.equals(r.realActivity)) {
2787 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
2788 if (taskTop.frontOfTask) {
2789 taskTop.task.setIntent(r.intent, r.info);
2790 }
2791 taskTop.deliverNewIntentLocked(callingUid, r.intent);
2792 } else if(!r.intent.filterEquals(taskTop.task.intent)) {
2793 // In this case weare launching the root activity
2794 // of the task, butwith a different intent. We
2795 // should start a newinstance on top.
2796 addingToTask =true;
2797 sourceRecord =taskTop;
2798 }
2799 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)== 0) {
2800