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 // In this case an activity is being launched in to an
2801 // existing task, without resetting that task. This
2802 // is typically the situation of launching an activity
2803 // from a notification or shortcut. We want to place
2804 // the new activity on top of the current task.
2805 addingToTask = true;
2806 sourceRecord = taskTop;
2807 } else if (!taskTop.task.rootWasReset) {
2808 // In this case we are launching in to an existing task
2809 // that has not yet been started from its front door.
2810 // The current task has been brought to the front.
2811 // Ideally, we'd probably like to place this new task
2812 // at the bottom of its stack, but that's a little hard
2813 // to do with the currentorganization of the code so
2814 // for now we'll just drop it.
2815 taskTop.task.setIntent(r.intent, r.info);
2816 }
2817 if (!addingToTask && reuseTask == null) {
2818 // We didn't do anything... butit was needed (a.k.a., client
2819 // don't use that intent!) Andfor paranoia, make
2820 // sure we have correctly resumed the top activity.
2821 if (doResume) {
2822 resumeTopActivityLocked(null, options);
2823 } else {
2824 ActivityOptions.abort(options);
2825 }
2826 return ActivityManager.START_TASK_TO_FRONT;
2827 }
2828 }
2829 }
2830 }
2831
2832 //Stringuri = r.intent.toURI();
2833 //Intentintent2 = new Intent(uri);
2834 //Slog.i(TAG, "Given intent: " + r.intent);
2835 //Slog.i(TAG, "URI is: " + uri);
2836 //Slog.i(TAG, "To intent: " + intent2);
2837
2838 if(r.packageName != null) {
2839 // Ifthe activity being launched is the same as the one currently
2840 // atthe top, then we need to check if it should only be launched
2841 //once.
2842 ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
2843 if(top != null && r.resultTo == null) {
2844 if (top.realActivity.equals(r.realActivity) && top.userId ==r.userId) {//需要启动的Activity与现在的topactivity不同,因此不需要执行resume top activtity,进一步分析:resume top activity还必须满足其他条件:launchMode中还必须设置了FLAG_ACTIVITY_SINGLE_TOP或者.LAUNCH_SINGLE_TOP或者LAUNCH_SINGLE_TASK
2845 if (top.app != null && top.app.thread != null) {
2846 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2847 || r.launchMode ==ActivityInfo.LAUNCH_SINGLE_TOP
2848 || r.launchMode ==ActivityInfo.LAUNCH_SINGLE_TASK) {
2849 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
2850 // For paranoia, makesure we have correctly
2851 // resumed the topactivity.
2852 if (doResume) {
2853 resumeTopActivityLocked(null);
2854 }
2855 ActivityOptions.abort(options);
2856 if((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
2857 // We don'tneed to start a new activity, and
2858 // the client said not todo anything if that
2859 // is the case,so this is it!
2860 returnActivityManager.START_RETURN_INTENT_TO_CALLER;
2861 }
2862 top.deliverNewIntentLocked(callingUid,r.intent);
2863 returnActivityManager.START_DELIVERED_TO_TOP;
2864 }
2865 }
2866 }
2867 }
2868
2869 } else {
2870 if(r.resultTo != null) {
2871 sendActivityResultLocked(-1,
2872 r.resultTo, r.resultWho, r.requestCode,
2873 Activity.RESULT_CANCELED, null);
2874 }
2875 ActivityOptions.abort(options);
2876 return ActivityManager.START_CLASS_NOT_FOUND;
2877 }
2878
2879 booleannewTask = false;
2880 booleankeepCurTransition = false;
2881
2882 // Shouldthis be considered a new task?
2883 if(r.resultTo == null && !addingToTask
2884 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
2885 if(reuseTask == null) {
2886 // todo: should do better management of integers.
2887 mService.mCurTask++;
2888 if (mService.mCurTask <= 0) {
2889 mService.mCurTask = 1;
2890 }
//在这里给activity创建了一个新task,保存在r.task中
2891 r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null,true);
2892 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2893 + " in new task " + r.task);
2894 }else {
2895 r.setTask(reuseTask, reuseTask, true);
2896 }
2897 newTask = true;
2898 if(!movedHome) {//这段代码被执行,但是launchFlags中并没有设置FLAG_ACTIVITY_TASK_ON_HOME
2899 moveHomeToFrontFromLaunchLocked(launchFlags);
2900 }
2901
2902 } else if(sourceRecord != null) {
2903 if(!addingToTask &&
2904 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
2905 // In this case, we are adding the activity to an existing
2906 // task, but the caller has asked to clear that task if the
2907 // activity is already running.
2908 ActivityRecord top = performClearTaskLocked(
2909 sourceRecord.task.taskId, r, launchFlags);
2910 keepCurTransition = true;
2911 if (top != null) {
2912 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
2913 top.deliverNewIntentLocked(callingUid, r.intent);
2914 // For paranoia, make sure we have correctly
2915 // resumed the top activity.
2916 if (doResume) {
2917 resumeTopActivityLocked(null);
2918 }
2919 ActivityOptions.abort(options);
2920 return ActivityManager.START_DELIVERED_TO_TOP;
2921 }
2922 }else if (!addingToTask &&
2923 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
2924 // In this case, we are launching an activity in our own task
2925 // that may already be running somewhere in the history, and
2926 // we want to shuffle it to the front of the stack if so.
2927 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
2928 if (where >= 0) {
2929 ActivityRecord top = moveActivityToFrontLocked(where);
2930 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
2931 top.updateOptionsLocked(options);
2932 top.deliverNewIntentLocked(callingUid, r.intent);
2933 if (doResume) {
2934 resumeTopActivityLocked(null);
2935 }
2936 return ActivityManager.START_DELIVERED_TO_TOP;
2937 }
2938 }
2939 // Anexisting activity is starting this new activity, so we want
2940 // tokeep the new one in the same task as the one that is starting
2941 //it.
2942 r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
2943 if(DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2944 + " in existing task " + r.task);
2945
2946 } else {
2947 //This not being started from an existing activity, and not part
2948 // ofa new task... just put it in the toptask, though these days
2949 //this case should never happen.
2950 finalint N = mHistory.size();
2951 ActivityRecord prev =
2952 N> 0 ? mHistory.get(N-1) : null;
2953 r.setTask(prev != null
2954 ? prev.task
2955 : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
2956 if(DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2957 + " in new guessed " + r.task);
2958 }
2959
2960 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
2961 intent, r.getUriPermissionsLocked());
2962
2963 if(newTask) {
2964 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
2965 }
2966 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
2967 startActivityLocked(r, newTask,doResume, keepCurTransition, options);
2968 returnActivityManager.START_SUCCESS;
2969 }
Step 11: ActivityStack.startActivityLocked
传入参数:
newTask=true
doResume=true
keepCurTransition = false;
此时要启动的activity已经被插入到了mHistory中,调用resumeTopActivityLocked()启动该activity.
private final voidstartActivityLocked(ActivityRecord r, boolean newTask,
booleandoResume, boolean keepCurTransition, Bundle options) {
final int NH= mHistory.size();
int addPos =-1;
if (!newTask){
// Ifstarting in an existing task, find where that is...
booleanstartIt = true;
for (inti = NH-1; i >= 0; i--) {
ActivityRecord p = mHistory.get(i);
if(p.finishing) {
continue;
}
if(p.task == r.task) {
// Here it is! Now, if this isnot yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
addPos = i+1;
if (!startIt) {
if (DEBUG_ADD_REMOVE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.i(TAG, "Adding activity " + r + " to stack at "+ addPos,
here);
}
mHistory.add(addPos, r);
r.putInHistory();
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
ActivityOptions.abort(options);
return;
}
break;
}
if(p.fullscreen) {
startIt = false;
}
}
}
// Place anew activity at top of stack, so it is next to interact
// with theuser.
if (addPos< 0) {
addPos =NH;
}
// If we arenot placing the new activity frontmost, we do not want
// to deliverthe onUserLeaving callback to the actual frontmost
// activity
if (addPos< NH) {
mUserLeaving = false;
if(DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front,mUserLeaving=false");
}
// Slot theactivity into the history stack and proceed
if(DEBUG_ADD_REMOVE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.i(TAG, "Adding activity " + r + " to stack at "+ addPos, here);
}
mHistory.add(addPos, r);
r.putInHistory();
r.frontOfTask= newTask;
if (NH >0) {
// Wewant to show the starting preview window if we are
//switching to a new task, or the next activity's process is
// notcurrently running.
booleanshowStartingIcon = newTask;
ProcessRecord proc = r.app;
if (proc== null) {
proc= mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
}
if (proc== null || proc.thread == null) {
if(!newTask && mResumedActivity == null) {
// This is a special case when stressing the framework
// by starting many activities fast in the same task.