Refactor ActivityManagerService activity stack.
Introdude a new ActivityStack class that holds all of the
state and management of a stack of activities. Paves the way
for having multiple activity stacks, though at this point
there should be no change in functionality and the activity
manager is still assuming there is only one stack.
Change-Id: Iea4859a24c9269061043755ec58a615028d4183b
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 252392b..2c6806b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -26,6 +26,7 @@
import com.android.server.SystemServer;
import com.android.server.Watchdog;
import com.android.server.WindowManagerService;
+import com.android.server.am.ActivityStack.ActivityState;
import dalvik.system.Zygote;
@@ -183,47 +184,21 @@
// Maximum number of recent tasks that we can remember.
static final int MAX_RECENT_TASKS = 20;
-
+
// Amount of time after a call to stopAppSwitches() during which we will
// prevent further untrusted switches from happening.
static final long APP_SWITCH_DELAY_TIME = 5*1000;
-
- // How long until we reset a task when the user returns to it. Currently
- // 30 minutes.
- static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
-
- // Set to true to disable the icon that is shown while a new activity
- // is being started.
- static final boolean SHOW_APP_STARTING_ICON = true;
-
- // How long we wait until giving up on the last activity to pause. This
- // is short because it directly impacts the responsiveness of starting the
- // next activity.
- static final int PAUSE_TIMEOUT = 500;
-
- /**
- * How long we can hold the launch wake lock before giving up.
- */
- static final int LAUNCH_TIMEOUT = 10*1000;
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real.
static final int PROC_START_TIMEOUT = 10*1000;
- // How long we wait until giving up on the last activity telling us it
- // is idle.
- static final int IDLE_TIMEOUT = 10*1000;
-
// How long to wait after going idle before forcing apps to GC.
static final int GC_TIMEOUT = 5*1000;
// The minimum amount of time between successive GC requests for a process.
static final int GC_MIN_INTERVAL = 60*1000;
- // How long we wait until giving up on an activity telling us it has
- // finished destroying itself.
- static final int DESTROY_TIMEOUT = 10*1000;
-
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_TIMEOUT = 10*1000;
@@ -388,29 +363,13 @@
static final String[] EMPTY_STRING_ARRAY = new String[0];
- enum ActivityState {
- INITIALIZING,
- RESUMED,
- PAUSING,
- PAUSED,
- STOPPING,
- STOPPED,
- FINISHING,
- DESTROYING,
- DESTROYED
- }
-
- /**
- * The back history of all previous (and possibly still
- * running) activities. It contains HistoryRecord objects.
- */
- final ArrayList mHistory = new ArrayList();
-
+ public ActivityStack mMainStack;
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
*/
- class PendingActivityLaunch {
+ static class PendingActivityLaunch {
ActivityRecord r;
ActivityRecord sourceRecord;
Uri[] grantedUriPermissions;
@@ -422,18 +381,6 @@
= new ArrayList<PendingActivityLaunch>();
/**
- * List of people waiting to find out about the next launched activity.
- */
- final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
- = new ArrayList<IActivityManager.WaitResult>();
-
- /**
- * List of people waiting to find out about the next visible activity.
- */
- final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
- = new ArrayList<IActivityManager.WaitResult>();
-
- /**
* List of all active broadcasts that are to be executed immediately
* (without waiting for another broadcast to finish). Currently this only
* contains broadcasts to registered receivers, to avoid spinning up
@@ -463,57 +410,9 @@
boolean mBroadcastsScheduled = false;
/**
- * Set to indicate whether to issue an onUserLeaving callback when a
- * newly launched activity is being brought in front of us.
- */
- boolean mUserLeaving = false;
-
- /**
- * When we are in the process of pausing an activity, before starting the
- * next one, this variable holds the activity that is currently being paused.
- */
- ActivityRecord mPausingActivity = null;
-
- /**
- * Current activity that is resumed, or null if there is none.
- */
- ActivityRecord mResumedActivity = null;
-
- /**
* Activity we have told the window manager to have key focus.
*/
ActivityRecord mFocusedActivity = null;
-
- /**
- * This is the last activity that we put into the paused state. This is
- * used to determine if we need to do an activity transition while sleeping,
- * when we normally hold the top activity paused.
- */
- ActivityRecord mLastPausedActivity = null;
-
- /**
- * List of activities that are waiting for a new activity
- * to become visible before completing whatever operation they are
- * supposed to do.
- */
- final ArrayList<ActivityRecord> mWaitingVisibleActivities
- = new ArrayList<ActivityRecord>();
-
- /**
- * List of activities that are ready to be stopped, but waiting
- * for the next activity to settle down before doing so. It contains
- * HistoryRecord objects.
- */
- final ArrayList<ActivityRecord> mStoppingActivities
- = new ArrayList<ActivityRecord>();
-
- /**
- * Animations that for the current transition have requested not to
- * be considered for the transition animation.
- */
- final ArrayList<ActivityRecord> mNoAnimActivities
- = new ArrayList<ActivityRecord>();
-
/**
* List of intents that were used to start the most recent tasks.
*/
@@ -521,14 +420,6 @@
= new ArrayList<TaskRecord>();
/**
- * List of activities that are ready to be finished, but waiting
- * for the previous activity to settle down before doing so. It contains
- * HistoryRecord objects.
- */
- final ArrayList<ActivityRecord> mFinishingActivities
- = new ArrayList<ActivityRecord>();
-
- /**
* All of the applications we currently have running organized by name.
* The keys are strings of the application package name (as
* returned by the package manager), and the keys are ApplicationRecord
@@ -628,16 +519,9 @@
* This is the process holding what we currently consider to be
* the "home" activity.
*/
- private ProcessRecord mHomeProcess;
+ ProcessRecord mHomeProcess;
/**
- * List of running activities, sorted by recent usage.
- * The first entry in the list is the least recently used.
- * It contains HistoryRecord objects.
- */
- private final ArrayList mLRUActivities = new ArrayList();
-
- /**
* Set of PendingResultRecord objects that are currently active.
*/
final HashSet mPendingResultRecords = new HashSet();
@@ -831,12 +715,6 @@
int mConfigurationSeq = 0;
/**
- * Set when we know we are going to be calling updateConfiguration()
- * soon, so want to skip intermediate config checks.
- */
- boolean mConfigWillChange;
-
- /**
* Hardware-reported OpenGLES version.
*/
final int GL_ES_VERSION;
@@ -892,21 +770,6 @@
* Set if we are shutting down the system, similar to sleeping.
*/
boolean mShuttingDown = false;
-
- /**
- * Set when the system is going to sleep, until we have
- * successfully paused the current activity and released our wake lock.
- * At that point the system is allowed to actually sleep.
- */
- PowerManager.WakeLock mGoingToSleep;
-
- /**
- * We don't want to allow the device to go to sleep while in the process
- * of launching an activity. This is primarily to allow alarm intent
- * receivers to launch an activity and get that to run before the device
- * goes back to sleep.
- */
- PowerManager.WakeLock mLaunchingActivity;
/**
* Task identifier that activities are currently being started
@@ -986,8 +849,6 @@
long mLastWriteTime = 0;
- long mInitialStartTime = 0;
-
/**
* Set to true after the system has finished booting.
*/
@@ -1034,16 +895,10 @@
static final int WAIT_FOR_DEBUGGER_MSG = 6;
static final int BROADCAST_INTENT_MSG = 7;
static final int BROADCAST_TIMEOUT_MSG = 8;
- static final int PAUSE_TIMEOUT_MSG = 9;
- static final int IDLE_TIMEOUT_MSG = 10;
- static final int IDLE_NOW_MSG = 11;
static final int SERVICE_TIMEOUT_MSG = 12;
static final int UPDATE_TIME_ZONE = 13;
static final int SHOW_UID_ERROR_MSG = 14;
static final int IM_FEELING_LUCKY_MSG = 15;
- static final int LAUNCH_TIMEOUT_MSG = 16;
- static final int DESTROY_TIMEOUT_MSG = 17;
- static final int RESUME_TOP_ACTIVITY_MSG = 19;
static final int PROC_START_TIMEOUT_MSG = 20;
static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
static final int KILL_APPLICATION_MSG = 22;
@@ -1183,38 +1038,6 @@
broadcastTimeout();
}
} break;
- case PAUSE_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
- // We don't at this point know if the activity is fullscreen,
- // so we need to be conservative and assume it isn't.
- Slog.w(TAG, "Activity pause timeout for " + token);
- activityPaused(token, null, true);
- } break;
- case IDLE_TIMEOUT_MSG: {
- if (mDidDexOpt) {
- mDidDexOpt = false;
- Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
- nmsg.obj = msg.obj;
- mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
- return;
- }
- // We don't at this point know if the activity is fullscreen,
- // so we need to be conservative and assume it isn't.
- IBinder token = (IBinder)msg.obj;
- Slog.w(TAG, "Activity idle timeout for " + token);
- activityIdleInternal(token, true, null);
- } break;
- case DESTROY_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
- // We don't at this point know if the activity is fullscreen,
- // so we need to be conservative and assume it isn't.
- Slog.w(TAG, "Activity destroy timeout for " + token);
- activityDestroyed(token);
- } break;
- case IDLE_NOW_MSG: {
- IBinder token = (IBinder)msg.obj;
- activityIdle(token, null);
- } break;
case SERVICE_TIMEOUT_MSG: {
if (mDidDexOpt) {
mDidDexOpt = false;
@@ -1257,25 +1080,6 @@
mUidAlert = null;
}
} break;
- case LAUNCH_TIMEOUT_MSG: {
- if (mDidDexOpt) {
- mDidDexOpt = false;
- Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
- mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
- return;
- }
- synchronized (ActivityManagerService.this) {
- if (mLaunchingActivity.isHeld()) {
- Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
- mLaunchingActivity.release();
- }
- }
- } break;
- case RESUME_TOP_ACTIVITY_MSG: {
- synchronized (ActivityManagerService.this) {
- resumeTopActivityLocked(null);
- }
- } break;
case PROC_START_TIMEOUT_MSG: {
if (mDidDexOpt) {
mDidDexOpt = false;
@@ -1424,11 +1228,7 @@
Context context = at.getSystemContext();
m.mContext = context;
m.mFactoryTest = factoryTest;
- PowerManager pm =
- (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
- m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
- m.mLaunchingActivity.setReferenceCounted(false);
+ m.mMainStack = new ActivityStack(m, context, true);
m.mBatteryStatsService.publish(context);
m.mUsageStatsService.publish(context);
@@ -1717,7 +1517,7 @@
return mAppBindArgs;
}
- private final void setFocusedActivityLocked(ActivityRecord r) {
+ final void setFocusedActivityLocked(ActivityRecord r) {
if (mFocusedActivity != r) {
mFocusedActivity = r;
mWindowManager.setFocusedApp(r, true);
@@ -1802,65 +1602,13 @@
}
}
- private final void updateLruProcessLocked(ProcessRecord app,
+ final void updateLruProcessLocked(ProcessRecord app,
boolean oomAdj, boolean updateActivityTime) {
mLruSeq++;
updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0);
}
- private final boolean updateLRUListLocked(ActivityRecord r) {
- final boolean hadit = mLRUActivities.remove(r);
- mLRUActivities.add(r);
- return hadit;
- }
-
- private final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
- int i = mHistory.size()-1;
- while (i >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
- if (!r.finishing && r != notTop) {
- return r;
- }
- i--;
- }
- return null;
- }
-
- private final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
- int i = mHistory.size()-1;
- while (i >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
- if (!r.finishing && !r.delayedResume && r != notTop) {
- return r;
- }
- i--;
- }
- return null;
- }
-
- /**
- * This is a simplified version of topRunningActivityLocked that provides a number of
- * optional skip-over modes. It is intended for use with the ActivityController hook only.
- *
- * @param token If non-null, any history records matching this token will be skipped.
- * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
- *
- * @return Returns the HistoryRecord of the next activity on the stack.
- */
- private final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
- int i = mHistory.size()-1;
- while (i >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
- // Note: the taskId check depends on real taskId fields being non-zero
- if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
- return r;
- }
- i--;
- }
- return null;
- }
-
- private final ProcessRecord getProcessRecordLocked(
+ final ProcessRecord getProcessRecordLocked(
String processName, int uid) {
if (uid == Process.SYSTEM_UID) {
// The system gets to run in any process. If there are multiple
@@ -1874,7 +1622,7 @@
return proc;
}
- private void ensurePackageDexOpt(String packageName) {
+ void ensurePackageDexOpt(String packageName) {
IPackageManager pm = AppGlobals.getPackageManager();
try {
if (pm.performDexOpt(packageName)) {
@@ -1884,175 +1632,14 @@
}
}
- private boolean isNextTransitionForward() {
+ boolean isNextTransitionForward() {
int transit = mWindowManager.getPendingAppTransition();
return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
|| transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
|| transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
}
- private final boolean realStartActivityLocked(ActivityRecord r,
- ProcessRecord app, boolean andResume, boolean checkConfig)
- throws RemoteException {
-
- r.startFreezingScreenLocked(app, 0);
- mWindowManager.setAppVisibility(r, true);
-
- // Have the window manager re-evaluate the orientation of
- // the screen based on the new activity order. Note that
- // as a result of this, it can call back into the activity
- // manager with a new orientation. We don't care about that,
- // because the activity is not currently running so we are
- // just restarting it anyway.
- if (checkConfig) {
- Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mConfiguration,
- r.mayFreezeScreenLocked(app) ? r : null);
- updateConfigurationLocked(config, r);
- }
-
- r.app = app;
-
- if (localLOGV) Slog.v(TAG, "Launching: " + r);
-
- int idx = app.activities.indexOf(r);
- if (idx < 0) {
- app.activities.add(r);
- }
- updateLruProcessLocked(app, true, true);
-
- try {
- if (app.thread == null) {
- throw new RemoteException();
- }
- List<ResultInfo> results = null;
- List<Intent> newIntents = null;
- if (andResume) {
- results = r.results;
- newIntents = r.newIntents;
- }
- if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
- + " icicle=" + r.icicle
- + " with results=" + results + " newIntents=" + newIntents
- + " andResume=" + andResume);
- if (andResume) {
- EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
- System.identityHashCode(r),
- r.task.taskId, r.shortComponentName);
- }
- if (r.isHomeActivity) {
- mHomeProcess = app;
- }
- ensurePackageDexOpt(r.intent.getComponent().getPackageName());
- app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
- System.identityHashCode(r),
- r.info, r.icicle, results, newIntents, !andResume,
- isNextTransitionForward());
-
- if ((app.info.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
- // This may be a heavy-weight process! Note that the package
- // manager will ensure that only activity can run in the main
- // process of the .apk, which is the only thing that will be
- // considered heavy-weight.
- if (app.processName.equals(app.info.packageName)) {
- if (mHeavyWeightProcess != null && mHeavyWeightProcess != app) {
- Log.w(TAG, "Starting new heavy weight process " + app
- + " when already running " + mHeavyWeightProcess);
- }
- mHeavyWeightProcess = app;
- Message msg = mHandler.obtainMessage(POST_HEAVY_NOTIFICATION_MSG);
- msg.obj = r;
- mHandler.sendMessage(msg);
- }
- }
-
- } catch (RemoteException e) {
- if (r.launchFailed) {
- // This is the second time we failed -- finish activity
- // and give up.
- Slog.e(TAG, "Second failure launching "
- + r.intent.getComponent().flattenToShortString()
- + ", giving up", e);
- appDiedLocked(app, app.pid, app.thread);
- requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
- "2nd-crash");
- return false;
- }
-
- // This is the first time we failed -- restart process and
- // retry.
- app.activities.remove(r);
- throw e;
- }
-
- r.launchFailed = false;
- if (updateLRUListLocked(r)) {
- Slog.w(TAG, "Activity " + r
- + " being launched, but already in LRU list");
- }
-
- if (andResume) {
- // As part of the process of launching, ActivityThread also performs
- // a resume.
- r.state = ActivityState.RESUMED;
- r.icicle = null;
- r.haveState = false;
- r.stopped = false;
- mResumedActivity = r;
- r.task.touchActiveTime();
- completeResumeLocked(r);
- pauseIfSleepingLocked();
- } else {
- // This activity is not starting in the resumed state... which
- // should look like we asked it to pause+stop (but remain visible),
- // and it has done so and reported back the current icicle and
- // other state.
- r.state = ActivityState.STOPPED;
- r.stopped = true;
- }
-
- // Launch the new version setup screen if needed. We do this -after-
- // launching the initial activity (that is, home), so that it can have
- // a chance to initialize itself while in the background, making the
- // switch back to it faster and look better.
- startSetupActivityLocked();
-
- return true;
- }
-
- private final void startSpecificActivityLocked(ActivityRecord r,
- boolean andResume, boolean checkConfig) {
- // Is this activity's application already running?
- ProcessRecord app = getProcessRecordLocked(r.processName,
- r.info.applicationInfo.uid);
-
- if (r.startTime == 0) {
- r.startTime = SystemClock.uptimeMillis();
- if (mInitialStartTime == 0) {
- mInitialStartTime = r.startTime;
- }
- } else if (mInitialStartTime == 0) {
- mInitialStartTime = SystemClock.uptimeMillis();
- }
-
- if (app != null && app.thread != null) {
- try {
- realStartActivityLocked(r, app, andResume, checkConfig);
- return;
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception when starting activity "
- + r.intent.getComponent().flattenToShortString(), e);
- }
-
- // If a dead object exception was thrown -- fall through to
- // restart the application.
- }
-
- startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
- "activity", r.intent.getComponent(), false);
- }
-
- private final ProcessRecord startProcessLocked(String processName,
+ final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
ProcessRecord app = getProcessRecordLocked(processName, info.uid);
@@ -2253,365 +1840,7 @@
}
}
- private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
- if (mPausingActivity != null) {
- RuntimeException e = new RuntimeException();
- Slog.e(TAG, "Trying to pause when pause is already pending for "
- + mPausingActivity, e);
- }
- ActivityRecord prev = mResumedActivity;
- if (prev == null) {
- RuntimeException e = new RuntimeException();
- Slog.e(TAG, "Trying to pause when nothing is resumed", e);
- resumeTopActivityLocked(null);
- return;
- }
- if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
- mResumedActivity = null;
- mPausingActivity = prev;
- mLastPausedActivity = prev;
- prev.state = ActivityState.PAUSING;
- prev.task.touchActiveTime();
-
- updateCpuStats();
-
- if (prev.app != null && prev.app.thread != null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
- try {
- EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
- System.identityHashCode(prev),
- prev.shortComponentName);
- prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
- prev.configChangeFlags);
- updateUsageStats(prev, false);
- } catch (Exception e) {
- // Ignore exception, if process died other code will cleanup.
- Slog.w(TAG, "Exception thrown during pause", e);
- mPausingActivity = null;
- mLastPausedActivity = null;
- }
- } else {
- mPausingActivity = null;
- mLastPausedActivity = null;
- }
-
- // If we are not going to sleep, we want to ensure the device is
- // awake until the next activity is started.
- if (!mSleeping && !mShuttingDown) {
- mLaunchingActivity.acquire();
- if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
- // To be safe, don't allow the wake lock to be held for too long.
- Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
- mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
- }
- }
-
-
- if (mPausingActivity != null) {
- // Have the window manager pause its key dispatching until the new
- // activity has started. If we're pausing the activity just because
- // the screen is being turned off and the UI is sleeping, don't interrupt
- // key dispatch; the same activity will pick it up again on wakeup.
- if (!uiSleeping) {
- prev.pauseKeyDispatchingLocked();
- } else {
- if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
- }
-
- // Schedule a pause timeout in case the app doesn't respond.
- // We don't give it much time because this directly impacts the
- // responsiveness seen by the user.
- Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
- msg.obj = prev;
- mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
- if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
- } else {
- // This activity failed to schedule the
- // pause, so just treat it as being paused now.
- if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
- resumeTopActivityLocked(null);
- }
- }
-
- private final void completePauseLocked() {
- ActivityRecord prev = mPausingActivity;
- if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
-
- if (prev != null) {
- if (prev.finishing) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
- prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
- } else if (prev.app != null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
- if (prev.waitingVisible) {
- prev.waitingVisible = false;
- mWaitingVisibleActivities.remove(prev);
- if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
- TAG, "Complete pause, no longer waiting: " + prev);
- }
- if (prev.configDestroy) {
- // The previous is being paused because the configuration
- // is changing, which means it is actually stopping...
- // To juggle the fact that we are also starting a new
- // instance right now, we need to first completely stop
- // the current instance before starting the new one.
- if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
- destroyActivityLocked(prev, true);
- } else {
- mStoppingActivities.add(prev);
- if (mStoppingActivities.size() > 3) {
- // If we already have a few activities waiting to stop,
- // then give up on things going idle and start clearing
- // them out.
- if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
- Message msg = Message.obtain();
- msg.what = ActivityManagerService.IDLE_NOW_MSG;
- mHandler.sendMessage(msg);
- }
- }
- } else {
- if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
- prev = null;
- }
- mPausingActivity = null;
- }
-
- if (!mSleeping && !mShuttingDown) {
- resumeTopActivityLocked(prev);
- } else {
- if (mGoingToSleep.isHeld()) {
- mGoingToSleep.release();
- }
- if (mShuttingDown) {
- notifyAll();
- }
- }
-
- if (prev != null) {
- prev.resumeKeyDispatchingLocked();
- }
-
- if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
- long diff = 0;
- synchronized (mProcessStatsThread) {
- diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
- }
- if (diff > 0) {
- BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
- synchronized (bsi) {
- BatteryStatsImpl.Uid.Proc ps =
- bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
- prev.info.packageName);
- if (ps != null) {
- ps.addForegroundTimeLocked(diff);
- }
- }
- }
- }
- prev.cpuTimeAtResume = 0; // reset it
- }
-
- /**
- * Once we know that we have asked an application to put an activity in
- * the resumed state (either by launching it or explicitly telling it),
- * this function updates the rest of our state to match that fact.
- */
- private final void completeResumeLocked(ActivityRecord next) {
- next.idle = false;
- next.results = null;
- next.newIntents = null;
-
- // schedule an idle timeout in case the app doesn't do it for us.
- Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
- msg.obj = next;
- mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
-
- if (false) {
- // The activity was never told to pause, so just keep
- // things going as-is. To maintain our own state,
- // we need to emulate it coming back and saying it is
- // idle.
- msg = mHandler.obtainMessage(IDLE_NOW_MSG);
- msg.obj = next;
- mHandler.sendMessage(msg);
- }
-
- reportResumedActivityLocked(next);
-
- next.thumbnail = null;
- setFocusedActivityLocked(next);
- next.resumeKeyDispatchingLocked();
- ensureActivitiesVisibleLocked(null, 0);
- mWindowManager.executeAppTransition();
- mNoAnimActivities.clear();
-
- // Mark the point when the activity is resuming
- // TODO: To be more accurate, the mark should be before the onCreate,
- // not after the onResume. But for subsequent starts, onResume is fine.
- if (next.app != null) {
- synchronized (mProcessStatsThread) {
- next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
- }
- } else {
- next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
- }
- }
-
- /**
- * Make sure that all activities that need to be visible (that is, they
- * currently can be seen by the user) actually are.
- */
- private final void ensureActivitiesVisibleLocked(ActivityRecord top,
- ActivityRecord starting, String onlyThisProcess, int configChanges) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "ensureActivitiesVisible behind " + top
- + " configChanges=0x" + Integer.toHexString(configChanges));
-
- // If the top activity is not fullscreen, then we need to
- // make sure any activities under it are now visible.
- final int count = mHistory.size();
- int i = count-1;
- while (mHistory.get(i) != top) {
- i--;
- }
- ActivityRecord r;
- boolean behindFullscreen = false;
- for (; i>=0; i--) {
- r = (ActivityRecord)mHistory.get(i);
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Make visible? " + r + " finishing=" + r.finishing
- + " state=" + r.state);
- if (r.finishing) {
- continue;
- }
-
- final boolean doThisProcess = onlyThisProcess == null
- || onlyThisProcess.equals(r.processName);
-
- // First: if this is not the current activity being started, make
- // sure it matches the current configuration.
- if (r != starting && doThisProcess) {
- ensureActivityConfigurationLocked(r, 0);
- }
-
- if (r.app == null || r.app.thread == null) {
- if (onlyThisProcess == null
- || onlyThisProcess.equals(r.processName)) {
- // This activity needs to be visible, but isn't even
- // running... get it started, but don't resume it
- // at this point.
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Start and freeze screen for " + r);
- if (r != starting) {
- r.startFreezingScreenLocked(r.app, configChanges);
- }
- if (!r.visible) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Starting and making visible: " + r);
- mWindowManager.setAppVisibility(r, true);
- }
- if (r != starting) {
- startSpecificActivityLocked(r, false, false);
- }
- }
-
- } else if (r.visible) {
- // If this activity is already visible, then there is nothing
- // else to do here.
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Skipping: already visible at " + r);
- r.stopFreezingScreenLocked(false);
-
- } else if (onlyThisProcess == null) {
- // This activity is not currently visible, but is running.
- // Tell it to become visible.
- r.visible = true;
- if (r.state != ActivityState.RESUMED && r != starting) {
- // If this activity is paused, tell it
- // to now show its window.
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Making visible and scheduling visibility: " + r);
- try {
- mWindowManager.setAppVisibility(r, true);
- r.app.thread.scheduleWindowVisibility(r, true);
- r.stopFreezingScreenLocked(false);
- } catch (Exception e) {
- // Just skip on any failure; we'll make it
- // visible when it next restarts.
- Slog.w(TAG, "Exception thrown making visibile: "
- + r.intent.getComponent(), e);
- }
- }
- }
-
- // Aggregate current change flags.
- configChanges |= r.configChangeFlags;
-
- if (r.fullscreen) {
- // At this point, nothing else needs to be shown
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Stopping: fullscreen at " + r);
- behindFullscreen = true;
- i--;
- break;
- }
- }
-
- // Now for any activities that aren't visible to the user, make
- // sure they no longer are keeping the screen frozen.
- while (i >= 0) {
- r = (ActivityRecord)mHistory.get(i);
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Make invisible? " + r + " finishing=" + r.finishing
- + " state=" + r.state
- + " behindFullscreen=" + behindFullscreen);
- if (!r.finishing) {
- if (behindFullscreen) {
- if (r.visible) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Making invisible: " + r);
- r.visible = false;
- try {
- mWindowManager.setAppVisibility(r, false);
- if ((r.state == ActivityState.STOPPING
- || r.state == ActivityState.STOPPED)
- && r.app != null && r.app.thread != null) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Scheduling invisibility: " + r);
- r.app.thread.scheduleWindowVisibility(r, false);
- }
- } catch (Exception e) {
- // Just skip on any failure; we'll make it
- // visible when it next restarts.
- Slog.w(TAG, "Exception thrown making hidden: "
- + r.intent.getComponent(), e);
- }
- } else {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Already invisible: " + r);
- }
- } else if (r.fullscreen) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Now behindFullscreen: " + r);
- behindFullscreen = true;
- }
- }
- i--;
- }
- }
-
- /**
- * Version of ensureActivitiesVisible that can easily be called anywhere.
- */
- private final void ensureActivitiesVisibleLocked(ActivityRecord starting,
- int configChanges) {
- ActivityRecord r = topRunningActivityLocked(null);
- if (r != null) {
- ensureActivitiesVisibleLocked(r, starting, null, configChanges);
- }
- }
-
- private void updateUsageStats(ActivityRecord resumedComponent, boolean resumed) {
+ void updateUsageStats(ActivityRecord resumedComponent, boolean resumed) {
if (resumed) {
mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
} else {
@@ -2619,7 +1848,7 @@
}
}
- private boolean startHomeActivityLocked() {
+ boolean startHomeActivityLocked() {
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
// We are running in factory test mode, but unable to find
@@ -2646,7 +1875,7 @@
aInfo.applicationInfo.uid);
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivityLocked(null, intent, null, null, 0, aInfo,
+ mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo,
null, null, 0, 0, 0, false, false);
}
}
@@ -2658,7 +1887,7 @@
/**
* Starts the "new version setup screen" if appropriate.
*/
- private void startSetupActivityLocked() {
+ void startSetupActivityLocked() {
// Only do this once per boot.
if (mCheckedForSetup) {
return;
@@ -2702,14 +1931,14 @@
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
- startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
+ mMainStack.startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
null, null, 0, 0, 0, false, false);
}
}
}
}
- private void reportResumedActivityLocked(ActivityRecord r) {
+ void reportResumedActivityLocked(ActivityRecord r) {
//Slog.i(TAG, "**** REPORT RESUME: " + r);
final int identHash = System.identityHashCode(r);
@@ -2728,1278 +1957,27 @@
}
mWatchers.finishBroadcast();
}
-
- /**
- * Ensure that the top activity in the stack is resumed.
- *
- * @param prev The previously resumed activity, for when in the process
- * of pausing; can be null to call from elsewhere.
- *
- * @return Returns true if something is being resumed, or false if
- * nothing happened.
- */
- private final boolean resumeTopActivityLocked(ActivityRecord prev) {
- // Find the first activity that is not finishing.
- ActivityRecord next = topRunningActivityLocked(null);
- // Remember how we'll process this pause/resume situation, and ensure
- // that the state is reset however we wind up proceeding.
- final boolean userLeaving = mUserLeaving;
- mUserLeaving = false;
-
- if (next == null) {
- // There are no more activities! Let's just start up the
- // Launcher...
- return startHomeActivityLocked();
- }
-
- next.delayedResume = false;
-
- // If the top activity is the resumed one, nothing to do.
- if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
- // Make sure we have executed any pending transitions, since there
- // should be nothing left to do at this point.
- mWindowManager.executeAppTransition();
- mNoAnimActivities.clear();
- return false;
- }
-
- // If we are sleeping, and there is no resumed activity, and the top
- // activity is paused, well that is the state we want.
- if ((mSleeping || mShuttingDown)
- && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
- // Make sure we have executed any pending transitions, since there
- // should be nothing left to do at this point.
- mWindowManager.executeAppTransition();
- mNoAnimActivities.clear();
- return false;
- }
-
- // The activity may be waiting for stop, but that is no longer
- // appropriate for it.
- mStoppingActivities.remove(next);
- mWaitingVisibleActivities.remove(next);
-
- if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
-
- // If we are currently pausing an activity, then don't do anything
- // until that is done.
- if (mPausingActivity != null) {
- if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
- return false;
- }
-
- // We need to start pausing the current activity so the top one
- // can be resumed...
- if (mResumedActivity != null) {
- if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
- startPausingLocked(userLeaving, false);
- return true;
- }
-
- if (prev != null && prev != next) {
- if (!prev.waitingVisible && next != null && !next.nowVisible) {
- prev.waitingVisible = true;
- mWaitingVisibleActivities.add(prev);
- if (DEBUG_SWITCH) Slog.v(
- TAG, "Resuming top, waiting visible to hide: " + prev);
- } else {
- // The next activity is already visible, so hide the previous
- // activity's windows right now so we can show the new one ASAP.
- // We only do this if the previous is finishing, which should mean
- // it is on top of the one being resumed so hiding it quickly
- // is good. Otherwise, we want to do the normal route of allowing
- // the resumed activity to be shown so we can decide if the
- // previous should actually be hidden depending on whether the
- // new one is found to be full-screen or not.
- if (prev.finishing) {
- mWindowManager.setAppVisibility(prev, false);
- if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
- + prev + ", waitingVisible="
- + (prev != null ? prev.waitingVisible : null)
- + ", nowVisible=" + next.nowVisible);
- } else {
- if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
- + prev + ", waitingVisible="
- + (prev != null ? prev.waitingVisible : null)
- + ", nowVisible=" + next.nowVisible);
- }
- }
- }
-
- // We are starting up the next activity, so tell the window manager
- // that the previous one will be hidden soon. This way it can know
- // to ignore it when computing the desired screen orientation.
- if (prev != null) {
- if (prev.finishing) {
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare close transition: prev=" + prev);
- if (mNoAnimActivities.contains(prev)) {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
- } else {
- mWindowManager.prepareAppTransition(prev.task == next.task
- ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
- : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
- }
- mWindowManager.setAppWillBeHidden(prev);
- mWindowManager.setAppVisibility(prev, false);
- } else {
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare open transition: prev=" + prev);
- if (mNoAnimActivities.contains(next)) {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
- } else {
- mWindowManager.prepareAppTransition(prev.task == next.task
- ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
- : WindowManagerPolicy.TRANSIT_TASK_OPEN);
- }
- }
- if (false) {
- mWindowManager.setAppWillBeHidden(prev);
- mWindowManager.setAppVisibility(prev, false);
- }
- } else if (mHistory.size() > 1) {
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare open transition: no previous");
- if (mNoAnimActivities.contains(next)) {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
- } else {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
- }
- }
-
- if (next.app != null && next.app.thread != null) {
- if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
-
- // This activity is now becoming visible.
- mWindowManager.setAppVisibility(next, true);
-
- ActivityRecord lastResumedActivity = mResumedActivity;
- ActivityState lastState = next.state;
-
- updateCpuStats();
-
- next.state = ActivityState.RESUMED;
- mResumedActivity = next;
- next.task.touchActiveTime();
- updateLruProcessLocked(next.app, true, true);
- updateLRUListLocked(next);
-
- // Have the window manager re-evaluate the orientation of
- // the screen based on the new activity order.
- boolean updated;
- synchronized (this) {
- Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mConfiguration,
- next.mayFreezeScreenLocked(next.app) ? next : null);
- if (config != null) {
- next.frozenBeforeDestroy = true;
- }
- updated = updateConfigurationLocked(config, next);
- }
- if (!updated) {
- // The configuration update wasn't able to keep the existing
- // instance of the activity, and instead started a new one.
- // We should be all done, but let's just make sure our activity
- // is still at the top and schedule another run if something
- // weird happened.
- ActivityRecord nextNext = topRunningActivityLocked(null);
- if (DEBUG_SWITCH) Slog.i(TAG,
- "Activity config changed during resume: " + next
- + ", new next: " + nextNext);
- if (nextNext != next) {
- // Do over!
- mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
- }
- setFocusedActivityLocked(next);
- ensureActivitiesVisibleLocked(null, 0);
- mWindowManager.executeAppTransition();
- mNoAnimActivities.clear();
- return true;
- }
-
- try {
- // Deliver all pending results.
- ArrayList a = next.results;
- if (a != null) {
- final int N = a.size();
- if (!next.finishing && N > 0) {
- if (DEBUG_RESULTS) Slog.v(
- TAG, "Delivering results to " + next
- + ": " + a);
- next.app.thread.scheduleSendResult(next, a);
- }
- }
-
- if (next.newIntents != null) {
- next.app.thread.scheduleNewIntent(next.newIntents, next);
- }
-
- EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
- System.identityHashCode(next),
- next.task.taskId, next.shortComponentName);
-
- next.app.thread.scheduleResumeActivity(next,
- isNextTransitionForward());
-
- pauseIfSleepingLocked();
-
- } catch (Exception e) {
- // Whoops, need to restart this activity!
- next.state = lastState;
- mResumedActivity = lastResumedActivity;
- Slog.i(TAG, "Restarting because process died: " + next);
- if (!next.hasBeenLaunched) {
- next.hasBeenLaunched = true;
- } else {
- if (SHOW_APP_STARTING_ICON) {
- mWindowManager.setAppStartingWindow(
- next, next.packageName, next.theme,
- next.nonLocalizedLabel,
- next.labelRes, next.icon, null, true);
- }
- }
- startSpecificActivityLocked(next, true, false);
- return true;
- }
-
- // From this point on, if something goes wrong there is no way
- // to recover the activity.
- try {
- next.visible = true;
- completeResumeLocked(next);
- } catch (Exception e) {
- // If any exception gets thrown, toss away this
- // activity and try the next one.
- Slog.w(TAG, "Exception thrown during resume of " + next, e);
- requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
- "resume-exception");
- return true;
- }
-
- // Didn't need to use the icicle, and it is now out of date.
- next.icicle = null;
- next.haveState = false;
- next.stopped = false;
-
- } else {
- // Whoops, need to restart this activity!
- if (!next.hasBeenLaunched) {
- next.hasBeenLaunched = true;
- } else {
- if (SHOW_APP_STARTING_ICON) {
- mWindowManager.setAppStartingWindow(
- next, next.packageName, next.theme,
- next.nonLocalizedLabel,
- next.labelRes, next.icon, null, true);
- }
- if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
- }
- startSpecificActivityLocked(next, true, true);
- }
-
- return true;
- }
-
- private final void startActivityLocked(ActivityRecord r, boolean newTask,
- boolean doResume) {
- final int NH = mHistory.size();
-
- int addPos = -1;
-
- if (!newTask) {
- // If starting in an existing task, find where that is...
- ActivityRecord next = null;
- boolean startIt = true;
- for (int i = NH-1; i >= 0; i--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(i);
- if (p.finishing) {
- continue;
- }
- if (p.task == r.task) {
- // Here it is! Now, if this is not 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) {
- mHistory.add(addPos, r);
- r.inHistory = true;
- r.task.numActivities++;
- mWindowManager.addAppToken(addPos, r, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
- if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
- }
- return;
- }
- break;
- }
- if (p.fullscreen) {
- startIt = false;
- }
- next = p;
- }
- }
-
- // Place a new activity at top of stack, so it is next to interact
- // with the user.
- if (addPos < 0) {
- addPos = mHistory.size();
- }
-
- // If we are not placing the new activity frontmost, we do not want
- // to deliver the 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 the activity into the history stack and proceed
- mHistory.add(addPos, r);
- r.inHistory = true;
- r.frontOfTask = newTask;
- r.task.numActivities++;
- if (NH > 0) {
- // We want to show the starting preview window if we are
- // switching to a new task, or the next activity's process is
- // not currently running.
- boolean showStartingIcon = newTask;
- ProcessRecord proc = r.app;
- if (proc == null) {
- proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
- }
- if (proc == null || proc.thread == null) {
- showStartingIcon = true;
- }
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare open transition: starting " + r);
- if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
- mNoAnimActivities.add(r);
- } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
- mNoAnimActivities.remove(r);
- } else {
- mWindowManager.prepareAppTransition(newTask
- ? WindowManagerPolicy.TRANSIT_TASK_OPEN
- : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
- mNoAnimActivities.remove(r);
- }
- mWindowManager.addAppToken(
- addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
- boolean doShow = true;
- if (newTask) {
- // Even though this activity is starting fresh, we still need
- // to reset it to make sure we apply affinities to move any
- // existing activities from other tasks in to it.
- // If the caller has requested that the target task be
- // reset, then do so.
- if ((r.intent.getFlags()
- &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
- resetTaskIfNeededLocked(r, r);
- doShow = topRunningNonDelayedActivityLocked(null) == r;
- }
- }
- if (SHOW_APP_STARTING_ICON && doShow) {
- // Figure out if we are transitioning from another activity that is
- // "has the same starting icon" as the next one. This allows the
- // window manager to keep the previous window it had previously
- // created, if it still had one.
- ActivityRecord prev = mResumedActivity;
- if (prev != null) {
- // We don't want to reuse the previous starting preview if:
- // (1) The current activity is in a different task.
- if (prev.task != r.task) prev = null;
- // (2) The current activity is already displayed.
- else if (prev.nowVisible) prev = null;
- }
- mWindowManager.setAppStartingWindow(
- r, r.packageName, r.theme, r.nonLocalizedLabel,
- r.labelRes, r.icon, prev, showStartingIcon);
- }
- } else {
- // If this is the first activity, don't do any fancy animations,
- // because there is nothing for it to animate on top of.
- mWindowManager.addAppToken(addPos, r, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
- }
- if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
- }
-
- if (doResume) {
- resumeTopActivityLocked(null);
- }
- }
-
- /**
- * Perform clear operation as requested by
- * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
- * stack to the given task, then look for
- * an instance of that activity in the stack and, if found, finish all
- * activities on top of it and return the instance.
- *
- * @param newR Description of the new activity being started.
- * @return Returns the old activity that should be continue to be used,
- * or null if none was found.
- */
- private final ActivityRecord performClearTaskLocked(int taskId,
- ActivityRecord newR, int launchFlags, boolean doClear) {
- int i = mHistory.size();
-
- // First find the requested task.
- while (i > 0) {
- i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
- if (r.task.taskId == taskId) {
- i++;
- break;
- }
- }
-
- // Now clear it.
- while (i > 0) {
- i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
- if (r.finishing) {
- continue;
- }
- if (r.task.taskId != taskId) {
- return null;
- }
- if (r.realActivity.equals(newR.realActivity)) {
- // Here it is! Now finish everything in front...
- ActivityRecord ret = r;
- if (doClear) {
- while (i < (mHistory.size()-1)) {
- i++;
- r = (ActivityRecord)mHistory.get(i);
- if (r.finishing) {
- continue;
- }
- if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
- null, "clear")) {
- i--;
- }
- }
- }
-
- // Finally, if this is a normal launch mode (that is, not
- // expecting onNewIntent()), then we will finish the current
- // instance of the activity so a new fresh one can be started.
- if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
- && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
- if (!ret.finishing) {
- int index = indexOfTokenLocked(ret);
- if (index >= 0) {
- finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
- null, "clear");
- }
- return null;
- }
- }
-
- return ret;
- }
- }
-
- return null;
- }
-
- /**
- * Find the activity in the history stack within the given task. Returns
- * the index within the history at which it's found, or < 0 if not found.
- */
- private final int findActivityInHistoryLocked(ActivityRecord r, int task) {
- int i = mHistory.size();
- while (i > 0) {
- i--;
- ActivityRecord candidate = (ActivityRecord)mHistory.get(i);
- if (candidate.task.taskId != task) {
- break;
- }
- if (candidate.realActivity.equals(r.realActivity)) {
- return i;
- }
- }
-
- return -1;
- }
-
- /**
- * Reorder the history stack so that the activity at the given index is
- * brought to the front.
- */
- private final ActivityRecord moveActivityToFrontLocked(int where) {
- ActivityRecord newTop = (ActivityRecord)mHistory.remove(where);
- int top = mHistory.size();
- ActivityRecord oldTop = (ActivityRecord)mHistory.get(top-1);
- mHistory.add(top, newTop);
- oldTop.frontOfTask = false;
- newTop.frontOfTask = true;
- return newTop;
- }
-
- /**
- * Deliver a new Intent to an existing activity, so that its onNewIntent()
- * method will be called at the proper time.
- */
- private final void deliverNewIntentLocked(ActivityRecord r, Intent intent) {
- boolean sent = false;
- if (r.state == ActivityState.RESUMED
- && r.app != null && r.app.thread != null) {
- try {
- ArrayList<Intent> ar = new ArrayList<Intent>();
- ar.add(new Intent(intent));
- r.app.thread.scheduleNewIntent(ar, r);
- sent = true;
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown sending new intent to " + r, e);
- }
- }
- if (!sent) {
- r.addNewIntentLocked(new Intent(intent));
- }
- }
-
- private final void logStartActivity(int tag, ActivityRecord r,
- TaskRecord task) {
- EventLog.writeEvent(tag,
- System.identityHashCode(r), task.taskId,
- r.shortComponentName, r.intent.getAction(),
- r.intent.getType(), r.intent.getDataString(),
- r.intent.getFlags());
- }
-
- private final int startActivityLocked(IApplicationThread caller,
- Intent intent, String resolvedType,
- Uri[] grantedUriPermissions,
- int grantedMode, ActivityInfo aInfo, IBinder resultTo,
- String resultWho, int requestCode,
- int callingPid, int callingUid, boolean onlyIfNeeded,
- boolean componentSpecified) {
- Slog.i(TAG, "Starting activity: " + intent);
-
- ActivityRecord sourceRecord = null;
- ActivityRecord resultRecord = null;
- if (resultTo != null) {
- int index = indexOfTokenLocked(resultTo);
- if (DEBUG_RESULTS) Slog.v(
- TAG, "Sending result to " + resultTo + " (index " + index + ")");
- if (index >= 0) {
- sourceRecord = (ActivityRecord)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) {
- return 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);
- }
- }
-
- int err = START_SUCCESS;
-
- if (intent.getComponent() == null) {
- // We couldn't find a class that can handle the given Intent.
- // That's the end of that!
- err = START_INTENT_NOT_RESOLVED;
- }
-
- if (err == START_SUCCESS && aInfo == null) {
- // We couldn't find the specific class specified in the Intent.
- // Also the end of the line.
- err = START_CLASS_NOT_FOUND;
- }
-
- ProcessRecord callerApp = null;
- if (err == START_SUCCESS && caller != null) {
- callerApp = 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 = START_PERMISSION_DENIED;
- }
- }
-
- if (err != START_SUCCESS) {
- if (resultRecord != null) {
- sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- return err;
- }
-
- final int perm = checkComponentPermission(aInfo.permission, callingPid,
- callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- if (resultRecord != null) {
- sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- String msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ")"
- + " requires " + aInfo.permission;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
-
- if (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 = !mController.activityStarting(watchIntent,
- aInfo.applicationInfo.packageName);
- } catch (RemoteException e) {
- 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.
- return START_SUCCESS;
- }
- }
-
- ActivityRecord r = new ActivityRecord(this, callerApp, callingUid,
- intent, resolvedType, aInfo, mConfiguration,
- resultRecord, resultWho, requestCode, componentSpecified);
-
- if (mResumedActivity == null
- || mResumedActivity.info.applicationInfo.uid != callingUid) {
- if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
- PendingActivityLaunch pal = new PendingActivityLaunch();
- pal.r = r;
- pal.sourceRecord = sourceRecord;
- pal.grantedUriPermissions = grantedUriPermissions;
- pal.grantedMode = grantedMode;
- pal.onlyIfNeeded = onlyIfNeeded;
- mPendingActivityLaunches.add(pal);
- return START_SWITCHES_CANCELED;
- }
- }
-
- if (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).
- mAppSwitchesAllowedTime = 0;
- } else {
- mDidAppSwitch = true;
- }
-
- doPendingActivityLaunchesLocked(false);
-
- return startActivityUncheckedLocked(r, sourceRecord,
- grantedUriPermissions, grantedMode, onlyIfNeeded, true);
- }
-
- private final void doPendingActivityLaunchesLocked(boolean doResume) {
+ final void doPendingActivityLaunchesLocked(boolean doResume) {
final int N = mPendingActivityLaunches.size();
if (N <= 0) {
return;
}
for (int i=0; i<N; i++) {
PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
- startActivityUncheckedLocked(pal.r, pal.sourceRecord,
+ mMainStack.startActivityUncheckedLocked(pal.r, pal.sourceRecord,
pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
doResume && i == (N-1));
}
mPendingActivityLaunches.clear();
}
- private final int startActivityUncheckedLocked(ActivityRecord r,
- ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
- int grantedMode, boolean onlyIfNeeded, boolean doResume) {
- final Intent intent = r.intent;
- final int callingUid = r.launchedFromUid;
-
- int launchFlags = intent.getFlags();
-
- // We'll invoke onUserLeaving before onPause only if the launching
- // activity did not explicitly state that this is an automated launch.
- mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
- if (DEBUG_USER_LEAVING) Slog.v(TAG,
- "startActivity() => mUserLeaving=" + mUserLeaving);
-
- // If the caller has asked not to resume at this point, we make note
- // of this in the record so that we can skip it when trying to find
- // the top running activity.
- if (!doResume) {
- r.delayedResume = true;
- }
-
- ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
- != 0 ? r : null;
-
- // If the onlyIfNeeded flag is set, then we can do this if the activity
- // being launched is the same as the one making the call... or, as
- // a special case, if we do not know the caller then we count the
- // current top activity as the caller.
- if (onlyIfNeeded) {
- ActivityRecord checkedCaller = sourceRecord;
- if (checkedCaller == null) {
- checkedCaller = topRunningNonDelayedActivityLocked(notTop);
- }
- if (!checkedCaller.realActivity.equals(r.realActivity)) {
- // Caller is not the same as launcher, so always needed.
- onlyIfNeeded = false;
- }
- }
-
- if (grantedUriPermissions != null && callingUid > 0) {
- for (int i=0; i<grantedUriPermissions.length; i++) {
- grantUriPermissionLocked(callingUid, r.packageName,
- grantedUriPermissions[i], grantedMode, r);
- }
- }
-
- grantUriPermissionFromIntentLocked(callingUid, r.packageName,
- intent, r);
-
- if (sourceRecord == null) {
- // This activity is not being started from another... in this
- // case we -always- start a new task.
- if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
- Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
- + intent);
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
- }
- } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- // The original activity who is starting us is running as a single
- // instance... this new activity it is starting must go on its
- // own task.
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
- } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
- || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
- // The activity being started is a single instance... it always
- // gets launched into its own task.
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
- }
-
- if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- // For whatever reason this activity is being launched into a new
- // task... yet the caller has requested a result back. Well, that
- // is pretty messed up, so instead immediately send back a cancel
- // and let the new task continue launched as normal without a
- // dependency on its originator.
- Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
- sendActivityResultLocked(-1,
- r.resultTo, r.resultWho, r.requestCode,
- Activity.RESULT_CANCELED, null);
- r.resultTo = null;
- }
-
- boolean addingToTask = false;
- if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
- (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
- || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
- || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- // If bring to front is requested, and no result is requested, and
- // we can find a task that was started with this same
- // component, then instead of launching bring that one to the front.
- if (r.resultTo == null) {
- // See if there is a task to bring to the front. If this is
- // a SINGLE_INSTANCE activity, there can be one and only one
- // instance of it in the history, and it is always in its own
- // unique task, so we do a special search.
- ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
- ? findTaskLocked(intent, r.info)
- : findActivityLocked(intent, r.info);
- if (taskTop != null) {
- if (taskTop.task.intent == null) {
- // This task was started because of movement of
- // the activity based on affinity... now that we
- // are actually launching it, we can assign the
- // base intent.
- taskTop.task.setIntent(intent, r.info);
- }
- // If the target task is not in the front, then we need
- // to bring it to the front... except... well, with
- // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
- // to have the same behavior as if a new instance was
- // being started, which means not bringing it to the front
- // if the caller is not itself in the front.
- ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
- if (curTop.task != taskTop.task) {
- r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
- boolean callerAtFront = sourceRecord == null
- || curTop.task == sourceRecord.task;
- if (callerAtFront) {
- // We really do want to push this one into the
- // user's face, right now.
- moveTaskToFrontLocked(taskTop.task, r);
- }
- }
- // If the caller has requested that the target task be
- // reset, then do so.
- if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
- taskTop = resetTaskIfNeededLocked(taskTop, r);
- }
- if (onlyIfNeeded) {
- // We don't need to start a new activity, and
- // the client said not to do anything if that
- // is the case, so this is it! And for paranoia, make
- // sure we have correctly resumed the top activity.
- if (doResume) {
- resumeTopActivityLocked(null);
- }
- return START_RETURN_INTENT_TO_CALLER;
- }
- if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
- || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
- || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- // In this situation we want to remove all activities
- // from the task up to the one being started. In most
- // cases this means we are resetting the task to its
- // initial state.
- ActivityRecord top = performClearTaskLocked(
- taskTop.task.taskId, r, launchFlags, true);
- if (top != null) {
- if (top.frontOfTask) {
- // Activity aliases may mean we use different
- // intents for the top activity, so make sure
- // the task now has the identity of the new
- // intent.
- top.task.setIntent(r.intent, r.info);
- }
- logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
- deliverNewIntentLocked(top, r.intent);
- } else {
- // A special case: we need to
- // start the activity because it is not currently
- // running, and the caller has asked to clear the
- // current task to have this activity at the top.
- addingToTask = true;
- // Now pretend like this activity is being started
- // by the top of its task, so it is put in the
- // right place.
- sourceRecord = taskTop;
- }
- } else if (r.realActivity.equals(taskTop.task.realActivity)) {
- // In this case the top activity on the task is the
- // same as the one being launched, so we take that
- // as a request to bring the task to the foreground.
- // If the top activity in the task is the root
- // activity, deliver this new intent to it if it
- // desires.
- if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
- && taskTop.realActivity.equals(r.realActivity)) {
- logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
- if (taskTop.frontOfTask) {
- taskTop.task.setIntent(r.intent, r.info);
- }
- deliverNewIntentLocked(taskTop, r.intent);
- } else if (!r.intent.filterEquals(taskTop.task.intent)) {
- // In this case we are launching the root activity
- // of the task, but with a different intent. We
- // should start a new instance on top.
- addingToTask = true;
- sourceRecord = taskTop;
- }
- } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
- // In this case an activity is being launched in to an
- // existing task, without resetting that task. This
- // is typically the situation of launching an activity
- // from a notification or shortcut. We want to place
- // the new activity on top of the current task.
- addingToTask = true;
- sourceRecord = taskTop;
- } else if (!taskTop.task.rootWasReset) {
- // In this case we are launching in to an existing task
- // that has not yet been started from its front door.
- // The current task has been brought to the front.
- // Ideally, we'd probably like to place this new task
- // at the bottom of its stack, but that's a little hard
- // to do with the current organization of the code so
- // for now we'll just drop it.
- taskTop.task.setIntent(r.intent, r.info);
- }
- if (!addingToTask) {
- // We didn't do anything... but it was needed (a.k.a., client
- // don't use that intent!) And for paranoia, make
- // sure we have correctly resumed the top activity.
- if (doResume) {
- resumeTopActivityLocked(null);
- }
- return START_TASK_TO_FRONT;
- }
- }
- }
- }
-
- //String uri = r.intent.toURI();
- //Intent intent2 = new Intent(uri);
- //Slog.i(TAG, "Given intent: " + r.intent);
- //Slog.i(TAG, "URI is: " + uri);
- //Slog.i(TAG, "To intent: " + intent2);
-
- if (r.packageName != null) {
- // If the activity being launched is the same as the one currently
- // at the top, then we need to check if it should only be launched
- // once.
- ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
- if (top != null && r.resultTo == null) {
- if (top.realActivity.equals(r.realActivity)) {
- if (top.app != null && top.app.thread != null) {
- if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
- || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
- || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
- logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
- // For paranoia, make sure we have correctly
- // resumed the top activity.
- if (doResume) {
- resumeTopActivityLocked(null);
- }
- if (onlyIfNeeded) {
- // We don't need to start a new activity, and
- // the client said not to do anything if that
- // is the case, so this is it!
- return START_RETURN_INTENT_TO_CALLER;
- }
- deliverNewIntentLocked(top, r.intent);
- return START_DELIVERED_TO_TOP;
- }
- }
- }
- }
-
- } else {
- if (r.resultTo != null) {
- sendActivityResultLocked(-1,
- r.resultTo, r.resultWho, r.requestCode,
- Activity.RESULT_CANCELED, null);
- }
- return START_CLASS_NOT_FOUND;
- }
-
- boolean newTask = false;
-
- // Should this be considered a new task?
- if (r.resultTo == null && !addingToTask
- && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- // todo: should do better management of integers.
- mCurTask++;
- if (mCurTask <= 0) {
- mCurTask = 1;
- }
- r.task = new TaskRecord(mCurTask, r.info, intent,
- (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
- if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
- + " in new task " + r.task);
- newTask = true;
- addRecentTaskLocked(r.task);
-
- } else if (sourceRecord != null) {
- if (!addingToTask &&
- (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
- // In this case, we are adding the activity to an existing
- // task, but the caller has asked to clear that task if the
- // activity is already running.
- ActivityRecord top = performClearTaskLocked(
- sourceRecord.task.taskId, r, launchFlags, true);
- if (top != null) {
- logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
- deliverNewIntentLocked(top, r.intent);
- // For paranoia, make sure we have correctly
- // resumed the top activity.
- if (doResume) {
- resumeTopActivityLocked(null);
- }
- return START_DELIVERED_TO_TOP;
- }
- } else if (!addingToTask &&
- (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
- // In this case, we are launching an activity in our own task
- // that may already be running somewhere in the history, and
- // we want to shuffle it to the front of the stack if so.
- int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
- if (where >= 0) {
- ActivityRecord top = moveActivityToFrontLocked(where);
- logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
- deliverNewIntentLocked(top, r.intent);
- if (doResume) {
- resumeTopActivityLocked(null);
- }
- return START_DELIVERED_TO_TOP;
- }
- }
- // An existing activity is starting this new activity, so we want
- // to keep the new one in the same task as the one that is starting
- // it.
- r.task = sourceRecord.task;
- if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
- + " in existing task " + r.task);
-
- } else {
- // This not being started from an existing activity, and not part
- // of a new task... just put it in the top task, though these days
- // this case should never happen.
- final int N = mHistory.size();
- ActivityRecord prev =
- N > 0 ? (ActivityRecord)mHistory.get(N-1) : null;
- r.task = prev != null
- ? prev.task
- : new TaskRecord(mCurTask, r.info, intent,
- (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
- if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
- + " in new guessed " + r.task);
- }
- if (newTask) {
- EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
- }
- logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
- startActivityLocked(r, newTask, doResume);
- return START_SUCCESS;
- }
-
- void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
- long thisTime, long totalTime) {
- for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
- WaitResult w = mWaitingActivityLaunched.get(i);
- w.timeout = timeout;
- if (r != null) {
- w.who = new ComponentName(r.info.packageName, r.info.name);
- }
- w.thisTime = thisTime;
- w.totalTime = totalTime;
- }
- notify();
- }
-
- void reportActivityVisibleLocked(ActivityRecord r) {
- for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
- WaitResult w = mWaitingActivityVisible.get(i);
- w.timeout = false;
- if (r != null) {
- w.who = new ComponentName(r.info.packageName, r.info.name);
- }
- w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
- w.thisTime = w.totalTime;
- }
- notify();
- }
-
- private final int startActivityMayWait(IApplicationThread caller,
- Intent intent, String resolvedType, Uri[] grantedUriPermissions,
- int grantedMode, IBinder resultTo,
- String resultWho, int requestCode, boolean onlyIfNeeded,
- boolean debug, WaitResult outResult, Configuration config) {
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
-
- boolean componentSpecified = intent.getComponent() != null;
-
- // Don't modify the client's object!
- intent = new Intent(intent);
-
- // Collect information about the target of the Intent.
- ActivityInfo aInfo;
- try {
- ResolveInfo rInfo =
- AppGlobals.getPackageManager().resolveIntent(
- intent, resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY
- | STOCK_PM_FLAGS);
- aInfo = rInfo != null ? rInfo.activityInfo : null;
- } catch (RemoteException e) {
- aInfo = null;
- }
-
- if (aInfo != null) {
- // Store the found target back into the intent, because now that
- // we have it we never want to do this again. For example, if the
- // user navigates back to this point in the history, we should
- // always restart the exact same activity.
- intent.setComponent(new ComponentName(
- aInfo.applicationInfo.packageName, aInfo.name));
-
- // Don't debug things in the system process
- if (debug) {
- if (!aInfo.processName.equals("system")) {
- setDebugApp(aInfo.processName, true, false);
- }
- }
- }
-
- synchronized (this) {
- int callingPid;
- int callingUid;
- if (caller == null) {
- callingPid = Binder.getCallingPid();
- callingUid = Binder.getCallingUid();
- } else {
- callingPid = callingUid = -1;
- }
-
- mConfigWillChange = config != null && mConfiguration.diff(config) != 0;
- if (DEBUG_CONFIGURATION) Slog.v(TAG,
- "Starting activity when config will change = " + mConfigWillChange);
-
- final long origId = Binder.clearCallingIdentity();
-
- if (aInfo != null &&
- (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
- // This may be a heavy-weight process! Check to see if we already
- // have another, different heavy-weight process running.
- if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
- if (mHeavyWeightProcess != null &&
- (mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
- !mHeavyWeightProcess.processName.equals(aInfo.processName))) {
- int realCallingPid = callingPid;
- int realCallingUid = callingUid;
- if (caller != null) {
- ProcessRecord callerApp = getRecordForAppLocked(caller);
- if (callerApp != null) {
- realCallingPid = callerApp.pid;
- realCallingUid = callerApp.info.uid;
- } else {
- Slog.w(TAG, "Unable to find app for caller " + caller
- + " (pid=" + realCallingPid + ") when starting: "
- + intent.toString());
- return START_PERMISSION_DENIED;
- }
- }
-
- IIntentSender target = getIntentSenderLocked(
- IActivityManager.INTENT_SENDER_ACTIVITY, "android",
- realCallingUid, null, null, 0, intent,
- resolvedType, PendingIntent.FLAG_CANCEL_CURRENT
- | PendingIntent.FLAG_ONE_SHOT);
-
- Intent newIntent = new Intent();
- if (requestCode >= 0) {
- // Caller is requesting a result.
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
- }
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
- new IntentSender(target));
- if (mHeavyWeightProcess.activities.size() > 0) {
- ActivityRecord hist = mHeavyWeightProcess.activities.get(0);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
- hist.packageName);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
- hist.task.taskId);
- }
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
- aInfo.packageName);
- newIntent.setFlags(intent.getFlags());
- newIntent.setClassName("android",
- HeavyWeightSwitcherActivity.class.getName());
- intent = newIntent;
- resolvedType = null;
- caller = null;
- callingUid = Binder.getCallingUid();
- callingPid = Binder.getCallingPid();
- componentSpecified = true;
- try {
- ResolveInfo rInfo =
- AppGlobals.getPackageManager().resolveIntent(
- intent, null,
- PackageManager.MATCH_DEFAULT_ONLY
- | STOCK_PM_FLAGS);
- aInfo = rInfo != null ? rInfo.activityInfo : null;
- } catch (RemoteException e) {
- aInfo = null;
- }
- }
- }
- }
-
- int res = startActivityLocked(caller, intent, resolvedType,
- grantedUriPermissions, grantedMode, aInfo,
- resultTo, resultWho, requestCode, callingPid, callingUid,
- onlyIfNeeded, componentSpecified);
-
- if (mConfigWillChange) {
- // 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.
- enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
- "updateConfiguration()");
- mConfigWillChange = false;
- if (DEBUG_CONFIGURATION) Slog.v(TAG,
- "Updating to new configuration after starting activity.");
- updateConfigurationLocked(config, null);
- }
-
- Binder.restoreCallingIdentity(origId);
-
- if (outResult != null) {
- outResult.result = res;
- if (res == IActivityManager.START_SUCCESS) {
- mWaitingActivityLaunched.add(outResult);
- do {
- try {
- wait();
- } catch (InterruptedException e) {
- }
- } while (!outResult.timeout && outResult.who == null);
- } else if (res == IActivityManager.START_TASK_TO_FRONT) {
- ActivityRecord r = 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 {
- wait();
- } catch (InterruptedException e) {
- }
- } while (!outResult.timeout && outResult.who == null);
- }
- }
- }
-
- return res;
- }
- }
-
public final int startActivity(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug) {
- return startActivityMayWait(caller, intent, resolvedType,
+ return mMainStack.startActivityMayWait(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, null, null);
}
@@ -4010,7 +1988,7 @@
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug) {
WaitResult res = new WaitResult();
- startActivityMayWait(caller, intent, resolvedType,
+ mMainStack.startActivityMayWait(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, res, null);
return res;
@@ -4021,7 +1999,7 @@
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, Configuration config) {
- return startActivityMayWait(caller, intent, resolvedType,
+ return mMainStack.startActivityMayWait(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, null, config);
}
@@ -4045,8 +2023,8 @@
synchronized (this) {
// If this is coming from the currently resumed activity, it is
// effectively saying that app switches are allowed at this point.
- if (mResumedActivity != null
- && mResumedActivity.info.applicationInfo.uid ==
+ if (mMainStack.mResumedActivity != null
+ && mMainStack.mResumedActivity.info.applicationInfo.uid ==
Binder.getCallingUid()) {
mAppSwitchesAllowedTime = 0;
}
@@ -4064,11 +2042,11 @@
}
synchronized (this) {
- int index = indexOfTokenLocked(callingActivity);
+ int index = mMainStack.indexOfTokenLocked(callingActivity);
if (index < 0) {
return false;
}
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
if (r.app == null || r.app.thread == null) {
// The caller is not running... d'oh!
return false;
@@ -4137,7 +2115,7 @@
final long origId = Binder.clearCallingIdentity();
// XXX we are not dealing with propagating grantedUriPermissions...
// those are not yet exposed to user code, so there is no need.
- int res = startActivityLocked(r.app.thread, intent,
+ int res = mMainStack.startActivityLocked(r.app.thread, intent,
r.resolvedType, null, 0, aInfo, resultTo, resultWho,
requestCode, -1, r.launchedFromUid, false, false);
Binder.restoreCallingIdentity(origId);
@@ -4189,13 +2167,13 @@
}
synchronized(this) {
- return startActivityLocked(null, intent, resolvedType,
+ return mMainStack.startActivityLocked(null, intent, resolvedType,
null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
onlyIfNeeded, componentSpecified);
}
}
- private final void addRecentTaskLocked(TaskRecord task) {
+ final void addRecentTaskLocked(TaskRecord task) {
// Remove any existing entries that are the same kind of task.
int N = mRecentTasks.size();
for (int i=0; i<N; i++) {
@@ -4221,11 +2199,11 @@
public void setRequestedOrientation(IBinder token,
int requestedOrientation) {
synchronized (this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index < 0) {
return;
}
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
mWindowManager.setAppOrientation(r, requestedOrientation);
Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -4234,7 +2212,7 @@
if (config != null) {
r.frozenBeforeDestroy = true;
if (!updateConfigurationLocked(config, r)) {
- resumeTopActivityLocked(null);
+ mMainStack.resumeTopActivityLocked(null);
}
}
Binder.restoreCallingIdentity(origId);
@@ -4243,250 +2221,15 @@
public int getRequestedOrientation(IBinder token) {
synchronized (this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index < 0) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return mWindowManager.getAppOrientation(r);
}
}
- private final void stopActivityLocked(ActivityRecord r) {
- if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
- if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
- || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
- if (!r.finishing) {
- requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
- "no-history");
- }
- } else if (r.app != null && r.app.thread != null) {
- if (mFocusedActivity == r) {
- setFocusedActivityLocked(topRunningActivityLocked(null));
- }
- r.resumeKeyDispatchingLocked();
- try {
- r.stopped = false;
- r.state = ActivityState.STOPPING;
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Stopping visible=" + r.visible + " for " + r);
- if (!r.visible) {
- mWindowManager.setAppVisibility(r, false);
- }
- r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
- } catch (Exception e) {
- // Maybe just ignore exceptions here... if the process
- // has crashed, our death notification will clean things
- // up.
- Slog.w(TAG, "Exception thrown during pause", e);
- // Just in case, assume it to be stopped.
- r.stopped = true;
- r.state = ActivityState.STOPPED;
- if (r.configDestroy) {
- destroyActivityLocked(r, true);
- }
- }
- }
- }
-
- /**
- * @return Returns true if the activity is being finished, false if for
- * some reason it is being left as-is.
- */
- private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
- Intent resultData, String reason) {
- if (DEBUG_RESULTS) Slog.v(
- TAG, "Finishing activity: token=" + token
- + ", result=" + resultCode + ", data=" + resultData);
-
- int index = indexOfTokenLocked(token);
- if (index < 0) {
- return false;
- }
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
-
- // Is this the last activity left?
- boolean lastActivity = true;
- for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(i);
- if (!p.finishing && p != r) {
- lastActivity = false;
- break;
- }
- }
-
- // If this is the last activity, but it is the home activity, then
- // just don't finish it.
- if (lastActivity) {
- if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
- return false;
- }
- }
-
- finishActivityLocked(r, index, resultCode, resultData, reason);
- return true;
- }
-
- /**
- * @return Returns true if this activity has been removed from the history
- * list, or false if it is still in the list and will be removed later.
- */
- private final boolean finishActivityLocked(ActivityRecord r, int index,
- int resultCode, Intent resultData, String reason) {
- if (r.finishing) {
- Slog.w(TAG, "Duplicate finish request for " + r);
- return false;
- }
-
- r.finishing = true;
- EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
- System.identityHashCode(r),
- r.task.taskId, r.shortComponentName, reason);
- r.task.numActivities--;
- if (index < (mHistory.size()-1)) {
- ActivityRecord next = (ActivityRecord)mHistory.get(index+1);
- if (next.task == r.task) {
- if (r.frontOfTask) {
- // The next activity is now the front of the task.
- next.frontOfTask = true;
- }
- if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
- // If the caller asked that this activity (and all above it)
- // be cleared when the task is reset, don't lose that information,
- // but propagate it up to the next activity.
- next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- }
- }
- }
-
- r.pauseKeyDispatchingLocked();
- if (mFocusedActivity == r) {
- setFocusedActivityLocked(topRunningActivityLocked(null));
- }
-
- // send the result
- ActivityRecord resultTo = r.resultTo;
- if (resultTo != null) {
- if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
- + " who=" + r.resultWho + " req=" + r.requestCode
- + " res=" + resultCode + " data=" + resultData);
- if (r.info.applicationInfo.uid > 0) {
- grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
- r.packageName, resultData, r);
- }
- resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
- resultData);
- r.resultTo = null;
- }
- else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
-
- // Make sure this HistoryRecord is not holding on to other resources,
- // because clients have remote IPC references to this object so we
- // can't assume that will go away and want to avoid circular IPC refs.
- r.results = null;
- r.pendingResults = null;
- r.newIntents = null;
- r.icicle = null;
-
- if (mPendingThumbnails.size() > 0) {
- // There are clients waiting to receive thumbnails so, in case
- // this is an activity that someone is waiting for, add it
- // to the pending list so we can correctly update the clients.
- mCancelledThumbnails.add(r);
- }
-
- if (mResumedActivity == r) {
- boolean endTask = index <= 0
- || ((ActivityRecord)mHistory.get(index-1)).task != r.task;
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare close transition: finishing " + r);
- mWindowManager.prepareAppTransition(endTask
- ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
- : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
-
- // Tell window manager to prepare for this one to be removed.
- mWindowManager.setAppVisibility(r, false);
-
- if (mPausingActivity == null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
- if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
- startPausingLocked(false, false);
- }
-
- } else if (r.state != ActivityState.PAUSING) {
- // If the activity is PAUSING, we will complete the finish once
- // it is done pausing; else we can just directly finish it here.
- if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
- return finishCurrentActivityLocked(r, index,
- FINISH_AFTER_PAUSE) == null;
- } else {
- if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
- }
-
- return false;
- }
-
- private static final int FINISH_IMMEDIATELY = 0;
- private static final int FINISH_AFTER_PAUSE = 1;
- private static final int FINISH_AFTER_VISIBLE = 2;
-
- private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
- int mode) {
- final int index = indexOfTokenLocked(r);
- if (index < 0) {
- return null;
- }
-
- return finishCurrentActivityLocked(r, index, mode);
- }
-
- private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
- int index, int mode) {
- // First things first: if this activity is currently visible,
- // and the resumed activity is not yet visible, then hold off on
- // finishing until the resumed one becomes visible.
- if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
- if (!mStoppingActivities.contains(r)) {
- mStoppingActivities.add(r);
- if (mStoppingActivities.size() > 3) {
- // If we already have a few activities waiting to stop,
- // then give up on things going idle and start clearing
- // them out.
- Message msg = Message.obtain();
- msg.what = ActivityManagerService.IDLE_NOW_MSG;
- mHandler.sendMessage(msg);
- }
- }
- r.state = ActivityState.STOPPING;
- updateOomAdjLocked();
- return r;
- }
-
- // make sure the record is cleaned out of other places.
- mStoppingActivities.remove(r);
- mWaitingVisibleActivities.remove(r);
- if (mResumedActivity == r) {
- mResumedActivity = null;
- }
- final ActivityState prevState = r.state;
- r.state = ActivityState.FINISHING;
-
- if (mode == FINISH_IMMEDIATELY
- || prevState == ActivityState.STOPPED
- || prevState == ActivityState.INITIALIZING) {
- // If this activity is already stopped, we can just finish
- // it right now.
- return destroyActivityLocked(r, true) ? null : r;
- } else {
- // Need to go through the full pause cycle to get this
- // activity into the stopped state and then finish it.
- if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
- mFinishingActivities.add(r);
- resumeTopActivityLocked(null);
- }
- return r;
- }
-
/**
* This is the internal entry point for handling Activity.finish().
*
@@ -4505,7 +2248,7 @@
synchronized(this) {
if (mController != null) {
// Find the first activity that is not finishing.
- ActivityRecord next = topRunningActivityLocked(token, 0);
+ ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
if (next != null) {
// ask watcher if this is allowed
boolean resumeOK = true;
@@ -4521,7 +2264,7 @@
}
}
final long origId = Binder.clearCallingIdentity();
- boolean res = requestFinishActivityLocked(token, resultCode,
+ boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
resultData, "app-request");
Binder.restoreCallingIdentity(origId);
return res;
@@ -4549,9 +2292,9 @@
for (int i=0; i<activities.size(); i++) {
ActivityRecord r = activities.get(i);
if (!r.finishing) {
- int index = indexOfTokenLocked(r);
+ int index = mMainStack.indexOfTokenLocked(r);
if (index >= 0) {
- finishActivityLocked(r, index, Activity.RESULT_CANCELED,
+ mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
null, "finish-heavy");
}
}
@@ -4616,50 +2359,24 @@
}
}
- void sendActivityResultLocked(int callingUid, ActivityRecord r,
- String resultWho, int requestCode, int resultCode, Intent data) {
-
- if (callingUid > 0) {
- grantUriPermissionFromIntentLocked(callingUid, r.packageName,
- data, r);
- }
-
- if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
- + " : who=" + resultWho + " req=" + requestCode
- + " res=" + resultCode + " data=" + data);
- if (mResumedActivity == r && r.app != null && r.app.thread != null) {
- try {
- ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
- list.add(new ResultInfo(resultWho, requestCode,
- resultCode, data));
- r.app.thread.scheduleSendResult(r, list);
- return;
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown sending result to " + r, e);
- }
- }
-
- r.addResultLocked(null, resultWho, requestCode, resultCode, data);
- }
-
public final void finishSubActivity(IBinder token, String resultWho,
int requestCode) {
synchronized(this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index < 0) {
return;
}
- ActivityRecord self = (ActivityRecord)mHistory.get(index);
+ ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
int i;
- for (i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.resultTo == self && r.requestCode == requestCode) {
if ((r.resultWho == null && resultWho == null) ||
(r.resultWho != null && r.resultWho.equals(resultWho))) {
- finishActivityLocked(r, i,
+ mMainStack.finishActivityLocked(r, i,
Activity.RESULT_CANCELED, null, "request-sub");
}
}
@@ -4672,8 +2389,8 @@
public boolean willActivityBeVisible(IBinder token) {
synchronized(this) {
int i;
- for (i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r == token) {
return true;
}
@@ -4688,11 +2405,11 @@
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) {
synchronized(this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index < 0) {
return;
}
- ActivityRecord self = (ActivityRecord)mHistory.get(index);
+ ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
@@ -4707,192 +2424,6 @@
}
/**
- * Perform clean-up of service connections in an activity record.
- */
- private final void cleanUpActivityServicesLocked(ActivityRecord r) {
- // Throw away any services that have been bound by this activity.
- if (r.connections != null) {
- Iterator<ConnectionRecord> it = r.connections.iterator();
- while (it.hasNext()) {
- ConnectionRecord c = it.next();
- removeConnectionLocked(c, null, r);
- }
- r.connections = null;
- }
- }
-
- /**
- * Perform the common clean-up of an activity record. This is called both
- * as part of destroyActivityLocked() (when destroying the client-side
- * representation) and cleaning things up as a result of its hosting
- * processing going away, in which case there is no remaining client-side
- * state to destroy so only the cleanup here is needed.
- */
- private final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices) {
- if (mResumedActivity == r) {
- mResumedActivity = null;
- }
- if (mFocusedActivity == r) {
- mFocusedActivity = null;
- }
-
- r.configDestroy = false;
- r.frozenBeforeDestroy = false;
-
- // Make sure this record is no longer in the pending finishes list.
- // This could happen, for example, if we are trimming activities
- // down to the max limit while they are still waiting to finish.
- mFinishingActivities.remove(r);
- mWaitingVisibleActivities.remove(r);
-
- // Remove any pending results.
- if (r.finishing && r.pendingResults != null) {
- for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
- PendingIntentRecord rec = apr.get();
- if (rec != null) {
- cancelIntentSenderLocked(rec, false);
- }
- }
- r.pendingResults = null;
- }
-
- if (cleanServices) {
- cleanUpActivityServicesLocked(r);
- }
-
- if (mPendingThumbnails.size() > 0) {
- // There are clients waiting to receive thumbnails so, in case
- // this is an activity that someone is waiting for, add it
- // to the pending list so we can correctly update the clients.
- mCancelledThumbnails.add(r);
- }
-
- // Get rid of any pending idle timeouts.
- mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
- mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
- }
-
- private final void removeActivityFromHistoryLocked(ActivityRecord r) {
- if (r.state != ActivityState.DESTROYED) {
- mHistory.remove(r);
- r.inHistory = false;
- r.state = ActivityState.DESTROYED;
- mWindowManager.removeAppToken(r);
- if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
- }
- cleanUpActivityServicesLocked(r);
- removeActivityUriPermissionsLocked(r);
- }
- }
-
- /**
- * Destroy the current CLIENT SIDE instance of an activity. This may be
- * called both when actually finishing an activity, or when performing
- * a configuration switch where we destroy the current client-side object
- * but then create a new client-side object for this same HistoryRecord.
- */
- private final boolean destroyActivityLocked(ActivityRecord r,
- boolean removeFromApp) {
- if (DEBUG_SWITCH) Slog.v(
- TAG, "Removing activity: token=" + r
- + ", app=" + (r.app != null ? r.app.processName : "(null)"));
- EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
- System.identityHashCode(r),
- r.task.taskId, r.shortComponentName);
-
- boolean removedFromHistory = false;
-
- cleanUpActivityLocked(r, false);
-
- final boolean hadApp = r.app != null;
-
- if (hadApp) {
- if (removeFromApp) {
- int idx = r.app.activities.indexOf(r);
- if (idx >= 0) {
- r.app.activities.remove(idx);
- }
- if (mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
- mHeavyWeightProcess = null;
- mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
- }
- if (r.persistent) {
- decPersistentCountLocked(r.app);
- }
- if (r.app.activities.size() == 0) {
- // No longer have activities, so update location in
- // LRU list.
- updateLruProcessLocked(r.app, true, false);
- }
- }
-
- boolean skipDestroy = false;
-
- try {
- if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
- r.app.thread.scheduleDestroyActivity(r, r.finishing,
- r.configChangeFlags);
- } catch (Exception e) {
- // We can just ignore exceptions here... if the process
- // has crashed, our death notification will clean things
- // up.
- //Slog.w(TAG, "Exception thrown during finish", e);
- if (r.finishing) {
- removeActivityFromHistoryLocked(r);
- removedFromHistory = true;
- skipDestroy = true;
- }
- }
-
- r.app = null;
- r.nowVisible = false;
-
- if (r.finishing && !skipDestroy) {
- r.state = ActivityState.DESTROYING;
- Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
- msg.obj = r;
- mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
- } else {
- r.state = ActivityState.DESTROYED;
- }
- } else {
- // remove this record from the history.
- if (r.finishing) {
- removeActivityFromHistoryLocked(r);
- removedFromHistory = true;
- } else {
- r.state = ActivityState.DESTROYED;
- }
- }
-
- r.configChangeFlags = 0;
-
- if (!mLRUActivities.remove(r) && hadApp) {
- Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
- }
-
- return removedFromHistory;
- }
-
- private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
- int i = list.size();
- if (localLOGV) Slog.v(
- TAG, "Removing app " + app + " from list " + list
- + " with " + i + " entries");
- while (i > 0) {
- i--;
- ActivityRecord r = (ActivityRecord)list.get(i);
- if (localLOGV) Slog.v(
- TAG, "Record #" + i + " " + r + ": app=" + r.app);
- if (r.app == app) {
- if (localLOGV) Slog.v(TAG, "Removing this entry!");
- list.remove(i);
- }
- }
- }
-
- /**
* Main function for removing an existing process from the activity manager
* as a result of that process going away. Clears out all connections
* to the process.
@@ -4905,30 +2436,27 @@
}
// Just in case...
- if (mPausingActivity != null && mPausingActivity.app == app) {
- if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + mPausingActivity);
- mPausingActivity = null;
+ if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
+ if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity);
+ mMainStack.mPausingActivity = null;
}
- if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
- mLastPausedActivity = null;
+ if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
+ mMainStack.mLastPausedActivity = null;
}
// Remove this application's activities from active lists.
- removeHistoryRecordsForAppLocked(mLRUActivities, app);
- removeHistoryRecordsForAppLocked(mStoppingActivities, app);
- removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
- removeHistoryRecordsForAppLocked(mFinishingActivities, app);
+ mMainStack.removeHistoryRecordsForAppLocked(app);
boolean atTop = true;
boolean hasVisibleActivities = false;
// Clean out the history list.
- int i = mHistory.size();
+ int i = mMainStack.mHistory.size();
if (localLOGV) Slog.v(
TAG, "Removing app " + app + " from history with " + i + " entries");
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (localLOGV) Slog.v(
TAG, "Record #" + i + " " + r + ": app=" + r.app);
if (r.app == app) {
@@ -4936,14 +2464,14 @@
if (localLOGV) Slog.v(
TAG, "Removing this entry! frozen=" + r.haveState
+ " finishing=" + r.finishing);
- mHistory.remove(i);
+ mMainStack.mHistory.remove(i);
r.inHistory = false;
mWindowManager.removeAppToken(r);
if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
+ mWindowManager.validateAppTokens(mMainStack.mHistory);
}
- removeActivityUriPermissionsLocked(r);
+ r.removeUriPermissionsLocked();
} else {
// We have the current state for this activity, so
@@ -4960,7 +2488,7 @@
}
}
- cleanUpActivityLocked(r, true);
+ r.stack.cleanUpActivityLocked(r, true);
r.state = ActivityState.STOPPED;
}
atTop = false;
@@ -4977,14 +2505,14 @@
}
if (!restarting) {
- if (!resumeTopActivityLocked(null)) {
+ if (!mMainStack.resumeTopActivityLocked(null)) {
// If there was nothing to resume, and we are not already
// restarting this process, but there is a visible activity that
// is hosted by the process... then make sure all visible
// activities are running, taking care of restarting this
// process.
if (hasVisibleActivities) {
- ensureActivitiesVisibleLocked(null, 0);
+ mMainStack.ensureActivitiesVisibleLocked(null, 0);
}
}
}
@@ -5003,7 +2531,7 @@
return -1;
}
- private final ProcessRecord getRecordForAppLocked(
+ final ProcessRecord getRecordForAppLocked(
IApplicationThread thread) {
if (thread == null) {
return null;
@@ -5013,7 +2541,7 @@
return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
}
- private final void appDiedLocked(ProcessRecord app, int pid,
+ final void appDiedLocked(ProcessRecord app, int pid,
IApplicationThread thread) {
mProcDeaths[0]++;
@@ -5253,8 +2781,7 @@
}
}
- private final void decPersistentCountLocked(ProcessRecord app)
- {
+ final void decPersistentCountLocked(ProcessRecord app) {
app.persistentActivities--;
if (app.persistentActivities > 0) {
// Still more of 'em...
@@ -5282,11 +2809,11 @@
}
synchronized(this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index < 0) {
return;
}
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
ProcessRecord app = r.app;
if (localLOGV) Slog.v(
@@ -5497,10 +3024,10 @@
mWindowManager.closeSystemDialogs(reason);
- for (i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
- finishActivityLocked(r, i,
+ r.stack.finishActivityLocked(r, i,
Activity.RESULT_CANCELED, null, "close-sys");
}
}
@@ -5621,8 +3148,8 @@
boolean didSomething = killPackageProcessesLocked(name, uid, -100,
callerWillRestart, doit);
- for (i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.packageName.equals(name)) {
if (!doit) {
return true;
@@ -5633,7 +3160,7 @@
r.app.removed = true;
}
r.app = null;
- finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
+ r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
}
}
@@ -5665,7 +3192,7 @@
ac.removePackage(name);
}
}
- resumeTopActivityLocked(null);
+ mMainStack.resumeTopActivityLocked(null);
}
return didSomething;
@@ -5894,12 +3421,12 @@
boolean didSomething = false;
// See if the top visible activity is waiting to run in this process...
- ActivityRecord hr = topRunningActivityLocked(null);
+ ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr != null && normalMode) {
if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
- if (realStartActivityLocked(hr, app, true, true)) {
+ if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
@@ -5908,7 +3435,7 @@
badApp = true;
}
} else {
- ensureActivitiesVisibleLocked(hr, null, processName, 0);
+ mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0);
}
}
@@ -5992,195 +3519,16 @@
public final void activityIdle(IBinder token, Configuration config) {
final long origId = Binder.clearCallingIdentity();
- activityIdleInternal(token, false, config);
+ mMainStack.activityIdleInternal(token, false, config);
Binder.restoreCallingIdentity(origId);
}
- final ArrayList<ActivityRecord> processStoppingActivitiesLocked(
- boolean remove) {
- int N = mStoppingActivities.size();
- if (N <= 0) return null;
-
- ArrayList<ActivityRecord> stops = null;
-
- final boolean nowVisible = mResumedActivity != null
- && mResumedActivity.nowVisible
- && !mResumedActivity.waitingVisible;
- for (int i=0; i<N; i++) {
- ActivityRecord s = mStoppingActivities.get(i);
- if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
- + nowVisible + " waitingVisible=" + s.waitingVisible
- + " finishing=" + s.finishing);
- if (s.waitingVisible && nowVisible) {
- mWaitingVisibleActivities.remove(s);
- s.waitingVisible = false;
- if (s.finishing) {
- // If this activity is finishing, it is sitting on top of
- // everyone else but we now know it is no longer needed...
- // so get rid of it. Otherwise, we need to go through the
- // normal flow and hide it once we determine that it is
- // hidden by the activities in front of it.
- if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
- mWindowManager.setAppVisibility(s, false);
- }
- }
- if (!s.waitingVisible && remove) {
- if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
- if (stops == null) {
- stops = new ArrayList<ActivityRecord>();
- }
- stops.add(s);
- mStoppingActivities.remove(i);
- N--;
- i--;
- }
- }
-
- return stops;
- }
-
void enableScreenAfterBoot() {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
}
- final void activityIdleInternal(IBinder token, boolean fromTimeout,
- Configuration config) {
- if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
-
- ArrayList<ActivityRecord> stops = null;
- ArrayList<ActivityRecord> finishes = null;
- ArrayList<ActivityRecord> thumbnails = null;
- int NS = 0;
- int NF = 0;
- int NT = 0;
- IApplicationThread sendThumbnail = null;
- boolean booting = false;
- boolean enableScreen = false;
-
- synchronized (this) {
- if (token != null) {
- mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
- }
-
- // Get the activity record.
- int index = indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
-
- if (fromTimeout) {
- reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
- }
-
- // This is a hack to semi-deal with a race condition
- // in the client where it can be constructed with a
- // newer configuration from when we asked it to launch.
- // We'll update with whatever configuration it now says
- // it used to launch.
- if (config != null) {
- r.configuration = config;
- }
-
- // No longer need to keep the device awake.
- if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
- mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
- mLaunchingActivity.release();
- }
-
- // We are now idle. If someone is waiting for a thumbnail from
- // us, we can now deliver.
- r.idle = true;
- scheduleAppGcsLocked();
- if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
- sendThumbnail = r.app.thread;
- r.thumbnailNeeded = false;
- }
-
- // If this activity is fullscreen, set up to hide those under it.
-
- if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
- ensureActivitiesVisibleLocked(null, 0);
-
- //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
- if (!mBooted && !fromTimeout) {
- mBooted = true;
- enableScreen = true;
- }
-
- } else if (fromTimeout) {
- reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
- }
-
- // Atomically retrieve all of the other things to do.
- stops = processStoppingActivitiesLocked(true);
- NS = stops != null ? stops.size() : 0;
- if ((NF=mFinishingActivities.size()) > 0) {
- finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
- mFinishingActivities.clear();
- }
- if ((NT=mCancelledThumbnails.size()) > 0) {
- thumbnails = new ArrayList<ActivityRecord>(mCancelledThumbnails);
- mCancelledThumbnails.clear();
- }
-
- booting = mBooting;
- mBooting = false;
- }
-
- int i;
-
- // Send thumbnail if requested.
- if (sendThumbnail != null) {
- try {
- sendThumbnail.requestThumbnail(token);
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
- sendPendingThumbnail(null, token, null, null, true);
- }
- }
-
- // Stop any activities that are scheduled to do so but have been
- // waiting for the next one to start.
- for (i=0; i<NS; i++) {
- ActivityRecord r = (ActivityRecord)stops.get(i);
- synchronized (this) {
- if (r.finishing) {
- finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
- } else {
- stopActivityLocked(r);
- }
- }
- }
-
- // Finish any activities that are scheduled to do so but have been
- // waiting for the next one to start.
- for (i=0; i<NF; i++) {
- ActivityRecord r = (ActivityRecord)finishes.get(i);
- synchronized (this) {
- destroyActivityLocked(r, true);
- }
- }
-
- // Report back to any thumbnail receivers.
- for (i=0; i<NT; i++) {
- ActivityRecord r = (ActivityRecord)thumbnails.get(i);
- sendPendingThumbnail(r, null, null, null, true);
- }
-
- if (booting) {
- finishBooting();
- }
-
- trimApplications();
- //dump();
- //mWindowManager.dump();
-
- if (enableScreen) {
- enableScreenAfterBoot();
- }
- }
-
final void finishBooting() {
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
@@ -6249,39 +3597,10 @@
}
final long origId = Binder.clearCallingIdentity();
- activityPaused(token, icicle, false);
+ mMainStack.activityPaused(token, icicle, false);
Binder.restoreCallingIdentity(origId);
}
- final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
- if (DEBUG_PAUSE) Slog.v(
- TAG, "Activity paused: token=" + token + ", icicle=" + icicle
- + ", timeout=" + timeout);
-
- ActivityRecord r = null;
-
- synchronized (this) {
- int index = indexOfTokenLocked(token);
- if (index >= 0) {
- r = (ActivityRecord)mHistory.get(index);
- if (!timeout) {
- r.icicle = icicle;
- r.haveState = true;
- }
- mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
- if (mPausingActivity == r) {
- r.state = ActivityState.PAUSED;
- completePauseLocked();
- } else {
- EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
- System.identityHashCode(r), r.shortComponentName,
- mPausingActivity != null
- ? mPausingActivity.shortComponentName : "(none)");
- }
- }
- }
- }
-
public final void activityStopped(IBinder token, Bitmap thumbnail,
CharSequence description) {
if (localLOGV) Slog.v(
@@ -6292,17 +3611,17 @@
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index >= 0) {
- r = (ActivityRecord)mHistory.get(index);
+ r = (ActivityRecord)mMainStack.mHistory.get(index);
r.thumbnail = thumbnail;
r.description = description;
r.stopped = true;
r.state = ActivityState.STOPPED;
if (!r.finishing) {
if (r.configDestroy) {
- destroyActivityLocked(r, true);
- resumeTopActivityLocked(null);
+ r.stack.destroyActivityLocked(r, true);
+ r.stack.resumeTopActivityLocked(null);
}
}
}
@@ -6319,19 +3638,7 @@
public final void activityDestroyed(IBinder token) {
if (DEBUG_SWITCH) Slog.v(TAG, "ACTIVITY DESTROYED: " + token);
- synchronized (this) {
- mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
-
- int index = indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
- if (r.state == ActivityState.DESTROYING) {
- final long origId = Binder.clearCallingIdentity();
- removeActivityFromHistoryLocked(r);
- Binder.restoreCallingIdentity(origId);
- }
- }
- }
+ mMainStack.activityDestroyed(token);
}
public String getCallingPackage(IBinder token) {
@@ -6349,9 +3656,9 @@
}
private ActivityRecord getCallingRecordLocked(IBinder token) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
if (r != null) {
return r.resultTo;
}
@@ -6361,9 +3668,9 @@
public ComponentName getActivityClassForToken(IBinder token) {
synchronized(this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return r.intent.getComponent();
}
return null;
@@ -6372,9 +3679,9 @@
public String getPackageForToken(IBinder token) {
synchronized(this) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return r.packageName;
}
return null;
@@ -6428,11 +3735,11 @@
int requestCode, Intent intent, String resolvedType, int flags) {
ActivityRecord activity = null;
if (type == INTENT_SENDER_ACTIVITY_RESULT) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index < 0) {
return null;
}
- activity = (ActivityRecord)mHistory.get(index);
+ activity = (ActivityRecord)mMainStack.mHistory.get(index);
if (activity.finishing) {
return null;
}
@@ -6749,7 +4056,7 @@
}
}
- private void grantUriPermissionLocked(int callingUid,
+ void grantUriPermissionLocked(int callingUid,
String targetPkg, Uri uri, int modeFlags, ActivityRecord activity) {
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
@@ -6878,7 +4185,7 @@
}
}
- private void grantUriPermissionFromIntentLocked(int callingUid,
+ void grantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent, ActivityRecord activity) {
if (intent == null) {
return;
@@ -6914,7 +4221,7 @@
}
}
- private void removeUriPermissionIfNeededLocked(UriPermission perm) {
+ void removeUriPermissionIfNeededLocked(UriPermission perm) {
if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
|Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
HashMap<Uri, UriPermission> perms
@@ -6930,29 +4237,6 @@
}
}
- private void removeActivityUriPermissionsLocked(ActivityRecord activity) {
- if (activity.readUriPermissions != null) {
- for (UriPermission perm : activity.readUriPermissions) {
- perm.readActivities.remove(activity);
- if (perm.readActivities.size() == 0 && (perm.globalModeFlags
- &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
- perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
- removeUriPermissionIfNeededLocked(perm);
- }
- }
- }
- if (activity.writeUriPermissions != null) {
- for (UriPermission perm : activity.writeUriPermissions) {
- perm.writeActivities.remove(activity);
- if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
- &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
- perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- removeUriPermissionIfNeededLocked(perm);
- }
- }
- }
- }
-
private void revokeUriPermissionLocked(int callingUid, Uri uri,
int modeFlags) {
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
@@ -7137,9 +4421,9 @@
throw new SecurityException(msg);
}
- int pos = mHistory.size()-1;
+ int pos = mMainStack.mHistory.size()-1;
ActivityRecord next =
- pos >= 0 ? (ActivityRecord)mHistory.get(pos) : null;
+ pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
ActivityRecord top = null;
CharSequence topDescription = null;
TaskRecord curTask = null;
@@ -7148,7 +4432,7 @@
while (pos >= 0 && maxNum > 0) {
final ActivityRecord r = next;
pos--;
- next = pos >= 0 ? (ActivityRecord)mHistory.get(pos) : null;
+ next = pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
// Initialize state for next task if needed.
if (top == null ||
@@ -7297,12 +4581,12 @@
private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
int j;
- TaskRecord startTask = ((ActivityRecord)mHistory.get(startIndex)).task;
+ TaskRecord startTask = ((ActivityRecord)mMainStack.mHistory.get(startIndex)).task;
TaskRecord jt = startTask;
// First look backwards
for (j=startIndex-1; j>=0; j--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(j);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
if (r.task != jt) {
jt = r.task;
if (affinity.equals(jt.affinity)) {
@@ -7312,10 +4596,10 @@
}
// Now look forwards
- final int N = mHistory.size();
+ final int N = mMainStack.mHistory.size();
jt = startTask;
for (j=startIndex+1; j<N; j++) {
- ActivityRecord r = (ActivityRecord)mHistory.get(j);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
if (r.task != jt) {
if (affinity.equals(jt.affinity)) {
return j;
@@ -7325,7 +4609,7 @@
}
// Might it be at the top?
- if (affinity.equals(((ActivityRecord)mHistory.get(N-1)).task.affinity)) {
+ if (affinity.equals(((ActivityRecord)mMainStack.mHistory.get(N-1)).task.affinity)) {
return N-1;
}
@@ -7333,293 +4617,6 @@
}
/**
- * Perform a reset of the given task, if needed as part of launching it.
- * Returns the new HistoryRecord at the top of the task.
- */
- private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
- ActivityRecord newActivity) {
- boolean forceReset = (newActivity.info.flags
- &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
- if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
- if ((newActivity.info.flags
- &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
- forceReset = true;
- }
- }
-
- final TaskRecord task = taskTop.task;
-
- // We are going to move through the history list so that we can look
- // at each activity 'target' with 'below' either the interesting
- // activity immediately below it in the stack or null.
- ActivityRecord target = null;
- int targetI = 0;
- int taskTopI = -1;
- int replyChainEnd = -1;
- int lastReparentPos = -1;
- for (int i=mHistory.size()-1; i>=-1; i--) {
- ActivityRecord below = i >= 0 ? (ActivityRecord)mHistory.get(i) : null;
-
- if (below != null && below.finishing) {
- continue;
- }
- if (target == null) {
- target = below;
- targetI = i;
- // If we were in the middle of a reply chain before this
- // task, it doesn't appear like the root of the chain wants
- // anything interesting, so drop it.
- replyChainEnd = -1;
- continue;
- }
-
- final int flags = target.info.flags;
-
- final boolean finishOnTaskLaunch =
- (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
- final boolean allowTaskReparenting =
- (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
-
- if (target.task == task) {
- // We are inside of the task being reset... we'll either
- // finish this activity, push it out for another task,
- // or leave it as-is. We only do this
- // for activities that are not the root of the task (since
- // if we finish the root, we may no longer have the task!).
- if (taskTopI < 0) {
- taskTopI = targetI;
- }
- if (below != null && below.task == task) {
- final boolean clearWhenTaskReset =
- (target.intent.getFlags()
- &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
- if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
- // If this activity is sending a reply to a previous
- // activity, we can't do anything with it now until
- // we reach the start of the reply chain.
- // XXX note that we are assuming the result is always
- // to the previous activity, which is almost always
- // the case but we really shouldn't count on.
- if (replyChainEnd < 0) {
- replyChainEnd = targetI;
- }
- } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
- && target.taskAffinity != null
- && !target.taskAffinity.equals(task.affinity)) {
- // If this activity has an affinity for another
- // task, then we need to move it out of here. We will
- // move it as far out of the way as possible, to the
- // bottom of the activity stack. This also keeps it
- // correctly ordered with any activities we previously
- // moved.
- ActivityRecord p = (ActivityRecord)mHistory.get(0);
- if (target.taskAffinity != null
- && target.taskAffinity.equals(p.task.affinity)) {
- // If the activity currently at the bottom has the
- // same task affinity as the one we are moving,
- // then merge it into the same task.
- target.task = p.task;
- if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
- + " out to bottom task " + p.task);
- } else {
- mCurTask++;
- if (mCurTask <= 0) {
- mCurTask = 1;
- }
- target.task = new TaskRecord(mCurTask, target.info, null,
- (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
- target.task.affinityIntent = target.intent;
- if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
- + " out to new task " + target.task);
- }
- mWindowManager.setAppGroupId(target, task.taskId);
- if (replyChainEnd < 0) {
- replyChainEnd = targetI;
- }
- int dstPos = 0;
- for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
- p = (ActivityRecord)mHistory.get(srcPos);
- if (p.finishing) {
- continue;
- }
- if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
- + " out to target's task " + target.task);
- task.numActivities--;
- p.task = target.task;
- target.task.numActivities++;
- mHistory.remove(srcPos);
- mHistory.add(dstPos, p);
- mWindowManager.moveAppToken(dstPos, p);
- mWindowManager.setAppGroupId(p, p.task.taskId);
- dstPos++;
- if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
- }
- i++;
- }
- if (taskTop == p) {
- taskTop = below;
- }
- if (taskTopI == replyChainEnd) {
- taskTopI = -1;
- }
- replyChainEnd = -1;
- addRecentTaskLocked(target.task);
- } else if (forceReset || finishOnTaskLaunch
- || clearWhenTaskReset) {
- // If the activity should just be removed -- either
- // because it asks for it, or the task should be
- // cleared -- then finish it and anything that is
- // part of its reply chain.
- if (clearWhenTaskReset) {
- // In this case, we want to finish this activity
- // and everything above it, so be sneaky and pretend
- // like these are all in the reply chain.
- replyChainEnd = targetI+1;
- while (replyChainEnd < mHistory.size() &&
- ((ActivityRecord)mHistory.get(
- replyChainEnd)).task == task) {
- replyChainEnd++;
- }
- replyChainEnd--;
- } else if (replyChainEnd < 0) {
- replyChainEnd = targetI;
- }
- ActivityRecord p = null;
- for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
- p = (ActivityRecord)mHistory.get(srcPos);
- if (p.finishing) {
- continue;
- }
- if (finishActivityLocked(p, srcPos,
- Activity.RESULT_CANCELED, null, "reset")) {
- replyChainEnd--;
- srcPos--;
- }
- }
- if (taskTop == p) {
- taskTop = below;
- }
- if (taskTopI == replyChainEnd) {
- taskTopI = -1;
- }
- replyChainEnd = -1;
- } else {
- // If we were in the middle of a chain, well the
- // activity that started it all doesn't want anything
- // special, so leave it all as-is.
- replyChainEnd = -1;
- }
- } else {
- // Reached the bottom of the task -- any reply chain
- // should be left as-is.
- replyChainEnd = -1;
- }
-
- } else if (target.resultTo != null) {
- // If this activity is sending a reply to a previous
- // activity, we can't do anything with it now until
- // we reach the start of the reply chain.
- // XXX note that we are assuming the result is always
- // to the previous activity, which is almost always
- // the case but we really shouldn't count on.
- if (replyChainEnd < 0) {
- replyChainEnd = targetI;
- }
-
- } else if (taskTopI >= 0 && allowTaskReparenting
- && task.affinity != null
- && task.affinity.equals(target.taskAffinity)) {
- // We are inside of another task... if this activity has
- // an affinity for our task, then either remove it if we are
- // clearing or move it over to our task. Note that
- // we currently punt on the case where we are resetting a
- // task that is not at the top but who has activities above
- // with an affinity to it... this is really not a normal
- // case, and we will need to later pull that task to the front
- // and usually at that point we will do the reset and pick
- // up those remaining activities. (This only happens if
- // someone starts an activity in a new task from an activity
- // in a task that is not currently on top.)
- if (forceReset || finishOnTaskLaunch) {
- if (replyChainEnd < 0) {
- replyChainEnd = targetI;
- }
- ActivityRecord p = null;
- for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
- p = (ActivityRecord)mHistory.get(srcPos);
- if (p.finishing) {
- continue;
- }
- if (finishActivityLocked(p, srcPos,
- Activity.RESULT_CANCELED, null, "reset")) {
- taskTopI--;
- lastReparentPos--;
- replyChainEnd--;
- srcPos--;
- }
- }
- replyChainEnd = -1;
- } else {
- if (replyChainEnd < 0) {
- replyChainEnd = targetI;
- }
- for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(srcPos);
- if (p.finishing) {
- continue;
- }
- if (lastReparentPos < 0) {
- lastReparentPos = taskTopI;
- taskTop = p;
- } else {
- lastReparentPos--;
- }
- mHistory.remove(srcPos);
- p.task.numActivities--;
- p.task = task;
- mHistory.add(lastReparentPos, p);
- if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
- + " in to resetting task " + task);
- task.numActivities++;
- mWindowManager.moveAppToken(lastReparentPos, p);
- mWindowManager.setAppGroupId(p, p.task.taskId);
- if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
- }
- }
- replyChainEnd = -1;
-
- // Now we've moved it in to place... but what if this is
- // a singleTop activity and we have put it on top of another
- // instance of the same activity? Then we drop the instance
- // below so it remains singleTop.
- if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
- for (int j=lastReparentPos-1; j>=0; j--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(j);
- if (p.finishing) {
- continue;
- }
- if (p.intent.getComponent().equals(target.intent.getComponent())) {
- if (finishActivityLocked(p, j,
- Activity.RESULT_CANCELED, null, "replace")) {
- taskTopI--;
- lastReparentPos--;
- }
- }
- }
- }
- }
- }
-
- target = below;
- targetI = i;
- }
-
- return taskTop;
- }
-
- /**
* TODO: Add mController hook
*/
public void moveTaskToFront(int task) {
@@ -7637,14 +4634,14 @@
for (int i=0; i<N; i++) {
TaskRecord tr = mRecentTasks.get(i);
if (tr.taskId == task) {
- moveTaskToFrontLocked(tr, null);
+ mMainStack.moveTaskToFrontLocked(tr, null);
return;
}
}
- for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord hr = (ActivityRecord)mHistory.get(i);
+ for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ ActivityRecord hr = (ActivityRecord)mMainStack.mHistory.get(i);
if (hr.task.taskId == task) {
- moveTaskToFrontLocked(hr.task, null);
+ mMainStack.moveTaskToFrontLocked(hr.task, null);
return;
}
}
@@ -7654,84 +4651,20 @@
}
}
- private final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) {
- if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
-
- final int task = tr.taskId;
- int top = mHistory.size()-1;
-
- if (top < 0 || ((ActivityRecord)mHistory.get(top)).task.taskId == task) {
- // nothing to do!
- return;
- }
-
- ArrayList moved = new ArrayList();
-
- // Applying the affinities may have removed entries from the history,
- // so get the size again.
- top = mHistory.size()-1;
- int pos = top;
-
- // Shift all activities with this task up to the top
- // of the stack, keeping them in the same internal order.
- while (pos >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(pos);
- if (localLOGV) Slog.v(
- TAG, "At " + pos + " ckp " + r.task + ": " + r);
- boolean first = true;
- if (r.task.taskId == task) {
- if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
- mHistory.remove(pos);
- mHistory.add(top, r);
- moved.add(0, r);
- top--;
- if (first) {
- addRecentTaskLocked(r.task);
- first = false;
- }
- }
- pos--;
- }
-
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare to front transition: task=" + tr);
- if (reason != null &&
- (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
- ActivityRecord r = topRunningActivityLocked(null);
- if (r != null) {
- mNoAnimActivities.add(r);
- }
- } else {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
- }
-
- mWindowManager.moveAppTokensToTop(moved);
- if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
- }
-
- finishTaskMoveLocked(task);
- EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
- }
-
- private final void finishTaskMoveLocked(int task) {
- resumeTopActivityLocked(null);
- }
-
public void moveTaskToBack(int task) {
enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
"moveTaskToBack()");
synchronized(this) {
- if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
+ if (mMainStack.mResumedActivity != null
+ && mMainStack.mResumedActivity.task.taskId == task) {
if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
Binder.getCallingUid(), "Task to back")) {
return;
}
}
final long origId = Binder.clearCallingIdentity();
- moveTaskToBackLocked(task, null);
+ mMainStack.moveTaskToBackLocked(task, null);
Binder.restoreCallingIdentity(origId);
}
}
@@ -7750,93 +4683,13 @@
final long origId = Binder.clearCallingIdentity();
int taskId = getTaskForActivityLocked(token, !nonRoot);
if (taskId >= 0) {
- return moveTaskToBackLocked(taskId, null);
+ return mMainStack.moveTaskToBackLocked(taskId, null);
}
Binder.restoreCallingIdentity(origId);
}
return false;
}
- /**
- * Worker method for rearranging history stack. Implements the function of moving all
- * activities for a specific task (gathering them if disjoint) into a single group at the
- * bottom of the stack.
- *
- * If a watcher is installed, the action is preflighted and the watcher has an opportunity
- * to premeptively cancel the move.
- *
- * @param task The taskId to collect and move to the bottom.
- * @return Returns true if the move completed, false if not.
- */
- private final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
- Slog.i(TAG, "moveTaskToBack: " + task);
-
- // If we have a watcher, preflight the move before committing to it. First check
- // for *other* available tasks, but if none are available, then try again allowing the
- // current task to be selected.
- if (mController != null) {
- ActivityRecord next = topRunningActivityLocked(null, task);
- if (next == null) {
- next = topRunningActivityLocked(null, 0);
- }
- if (next != null) {
- // ask watcher if this is allowed
- boolean moveOK = true;
- try {
- moveOK = mController.activityResuming(next.packageName);
- } catch (RemoteException e) {
- mController = null;
- }
- if (!moveOK) {
- return false;
- }
- }
- }
-
- ArrayList moved = new ArrayList();
-
- if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare to back transition: task=" + task);
-
- final int N = mHistory.size();
- int bottom = 0;
- int pos = 0;
-
- // Shift all activities with this task down to the bottom
- // of the stack, keeping them in the same internal order.
- while (pos < N) {
- ActivityRecord r = (ActivityRecord)mHistory.get(pos);
- if (localLOGV) Slog.v(
- TAG, "At " + pos + " ckp " + r.task + ": " + r);
- if (r.task.taskId == task) {
- if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
- mHistory.remove(pos);
- mHistory.add(bottom, r);
- moved.add(r);
- bottom++;
- }
- pos++;
- }
-
- if (reason != null &&
- (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
- ActivityRecord r = topRunningActivityLocked(null);
- if (r != null) {
- mNoAnimActivities.add(r);
- }
- } else {
- mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
- }
- mWindowManager.moveAppTokensToBottom(moved);
- if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mHistory);
- }
-
- finishTaskMoveLocked(task);
- return true;
- }
-
public void moveTaskBackwards(int task) {
enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
"moveTaskBackwards()");
@@ -7863,10 +4716,10 @@
}
int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
- final int N = mHistory.size();
+ final int N = mMainStack.mHistory.size();
TaskRecord lastTask = null;
for (int i=0; i<N; i++) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r == token) {
if (!onlyRoot || lastTask != r.task) {
return r.task.taskId;
@@ -7879,89 +4732,17 @@
return -1;
}
- /**
- * Returns the top activity in any existing task matching the given
- * Intent. Returns null if no such task is found.
- */
- private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
- ComponentName cls = intent.getComponent();
- if (info.targetActivity != null) {
- cls = new ComponentName(info.packageName, info.targetActivity);
- }
-
- TaskRecord cp = null;
-
- final int N = mHistory.size();
- for (int i=(N-1); i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
- if (!r.finishing && r.task != cp
- && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- cp = r.task;
- //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
- // + "/aff=" + r.task.affinity + " to new cls="
- // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
- if (r.task.affinity != null) {
- if (r.task.affinity.equals(info.taskAffinity)) {
- //Slog.i(TAG, "Found matching affinity!");
- return r;
- }
- } else if (r.task.intent != null
- && r.task.intent.getComponent().equals(cls)) {
- //Slog.i(TAG, "Found matching class!");
- //dump();
- //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
- return r;
- } else if (r.task.affinityIntent != null
- && r.task.affinityIntent.getComponent().equals(cls)) {
- //Slog.i(TAG, "Found matching class!");
- //dump();
- //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
- return r;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Returns the first activity (starting from the top of the stack) that
- * is the same as the given activity. Returns null if no such activity
- * is found.
- */
- private ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
- ComponentName cls = intent.getComponent();
- if (info.targetActivity != null) {
- cls = new ComponentName(info.packageName, info.targetActivity);
- }
-
- final int N = mHistory.size();
- for (int i=(N-1); i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
- if (!r.finishing) {
- if (r.intent.getComponent().equals(cls)) {
- //Slog.i(TAG, "Found matching class!");
- //dump();
- //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
- return r;
- }
- }
- }
-
- return null;
- }
-
public void finishOtherInstances(IBinder token, ComponentName className) {
synchronized(this) {
final long origId = Binder.clearCallingIdentity();
- int N = mHistory.size();
+ int N = mMainStack.mHistory.size();
TaskRecord lastTask = null;
for (int i=0; i<N; i++) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.realActivity.equals(className)
&& r != token && lastTask != r.task) {
- if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+ if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
null, "others")) {
i--;
N--;
@@ -7995,11 +4776,11 @@
synchronized(this) {
if (r == null) {
- int index = indexOfTokenLocked(token);
+ int index = mMainStack.indexOfTokenLocked(token);
if (index < 0) {
return;
}
- r = (ActivityRecord)mHistory.get(index);
+ r = (ActivityRecord)mMainStack.mHistory.get(index);
}
if (thumbnail == null) {
thumbnail = r.thumbnail;
@@ -8531,12 +5312,12 @@
"unhandledBack()");
synchronized(this) {
- int count = mHistory.size();
+ int count = mMainStack.mHistory.size();
if (DEBUG_SWITCH) Slog.d(
TAG, "Performing unhandledBack(): stack size = " + count);
if (count > 1) {
final long origId = Binder.clearCallingIdentity();
- finishActivityLocked((ActivityRecord)mHistory.get(count-1),
+ mMainStack.finishActivityLocked((ActivityRecord)mMainStack.mHistory.get(count-1),
count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
Binder.restoreCallingIdentity(origId);
}
@@ -8579,8 +5360,8 @@
mSleeping = true;
mWindowManager.setEventDispatching(false);
- if (mResumedActivity != null) {
- pauseIfSleepingLocked();
+ if (mMainStack.mResumedActivity != null) {
+ mMainStack.pauseIfSleepingLocked();
} else {
Slog.w(TAG, "goingToSleep with no resumed activity!");
}
@@ -8600,10 +5381,11 @@
mShuttingDown = true;
mWindowManager.setEventDispatching(false);
- if (mResumedActivity != null) {
- pauseIfSleepingLocked();
+ if (mMainStack.mResumedActivity != null) {
+ mMainStack.pauseIfSleepingLocked();
final long endTime = System.currentTimeMillis() + timeout;
- while (mResumedActivity != null || mPausingActivity != null) {
+ while (mMainStack.mResumedActivity != null
+ || mMainStack.mPausingActivity != null) {
long delay = endTime - System.currentTimeMillis();
if (delay <= 0) {
Slog.w(TAG, "Activity manager shutdown timed out");
@@ -8624,35 +5406,14 @@
return timedout;
}
- void pauseIfSleepingLocked() {
- if (mSleeping || mShuttingDown) {
- if (!mGoingToSleep.isHeld()) {
- mGoingToSleep.acquire();
- if (mLaunchingActivity.isHeld()) {
- mLaunchingActivity.release();
- mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
- }
- }
-
- // If we are not currently pausing an activity, get the current
- // one to pause. If we are pausing one, we will just let that stuff
- // run and release the wake lock when all done.
- if (mPausingActivity == null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause...");
- if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
- startPausingLocked(false, true);
- }
- }
- }
-
public void wakingUp() {
synchronized(this) {
- if (mGoingToSleep.isHeld()) {
- mGoingToSleep.release();
+ if (mMainStack.mGoingToSleep.isHeld()) {
+ mMainStack.mGoingToSleep.release();
}
mWindowManager.setEventDispatching(true);
mSleeping = false;
- resumeTopActivityLocked(null);
+ mMainStack.resumeTopActivityLocked(null);
}
}
@@ -8782,29 +5543,29 @@
public void setImmersive(IBinder token, boolean immersive) {
synchronized(this) {
- int index = (token != null) ? indexOfTokenLocked(token) : -1;
+ int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
if (index < 0) {
throw new IllegalArgumentException();
}
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
r.immersive = immersive;
}
}
public boolean isImmersive(IBinder token) {
synchronized (this) {
- int index = (token != null) ? indexOfTokenLocked(token) : -1;
+ int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
if (index < 0) {
throw new IllegalArgumentException();
}
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return r.immersive;
}
}
public boolean isTopActivityImmersive() {
synchronized (this) {
- ActivityRecord r = topRunningActivityLocked(null);
+ ActivityRecord r = mMainStack.topRunningActivityLocked(null);
return (r != null) ? r.immersive : false;
}
}
@@ -9238,7 +5999,7 @@
} catch (RemoteException e) {
}
- resumeTopActivityLocked(null);
+ mMainStack.resumeTopActivityLocked(null);
}
}
@@ -9326,12 +6087,12 @@
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.info.processName, app.info.uid);
killServicesLocked(app, false);
- for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.app == app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
+ r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
}
}
if (!app.persistent) {
@@ -9349,28 +6110,28 @@
return false;
}
} else {
- ActivityRecord r = topRunningActivityLocked(null);
+ ActivityRecord r = mMainStack.topRunningActivityLocked(null);
if (r.app == app) {
// If the top running activity is from this crashing
// process, then terminate it to avoid getting in a loop.
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- int index = indexOfTokenLocked(r);
- finishActivityLocked(r, index,
+ int index = mMainStack.indexOfTokenLocked(r);
+ r.stack.finishActivityLocked(r, index,
Activity.RESULT_CANCELED, null, "crashed");
// Also terminate an activities below it that aren't yet
// stopped, to avoid a situation where one will get
// re-start our crashing activity once it gets resumed again.
index--;
if (index >= 0) {
- r = (ActivityRecord)mHistory.get(index);
+ r = (ActivityRecord)mMainStack.mHistory.get(index);
if (r.state == ActivityState.RESUMED
|| r.state == ActivityState.PAUSING
|| r.state == ActivityState.PAUSED) {
if (!r.isHomeActivity) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- finishActivityLocked(r, index,
+ r.stack.finishActivityLocked(r, index,
Activity.RESULT_CANCELED, null, "crashed");
}
}
@@ -10075,31 +6836,31 @@
if (needHeader) {
pw.println(" Activity stack:");
}
- dumpHistoryList(pw, mHistory, " ", "Hist", true);
+ dumpHistoryList(pw, mMainStack.mHistory, " ", "Hist", true);
pw.println(" ");
pw.println(" Running activities (most recent first):");
- dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
- if (mWaitingVisibleActivities.size() > 0) {
+ dumpHistoryList(pw, mMainStack.mLRUActivities, " ", "Run", false);
+ if (mMainStack.mWaitingVisibleActivities.size() > 0) {
pw.println(" ");
pw.println(" Activities waiting for another to become visible:");
- dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
+ dumpHistoryList(pw, mMainStack.mWaitingVisibleActivities, " ", "Wait", false);
}
- if (mStoppingActivities.size() > 0) {
+ if (mMainStack.mStoppingActivities.size() > 0) {
pw.println(" ");
pw.println(" Activities waiting to stop:");
- dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
+ dumpHistoryList(pw, mMainStack.mStoppingActivities, " ", "Stop", false);
}
- if (mFinishingActivities.size() > 0) {
+ if (mMainStack.mFinishingActivities.size() > 0) {
pw.println(" ");
pw.println(" Activities waiting to finish:");
- dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
+ dumpHistoryList(pw, mMainStack.mFinishingActivities, " ", "Fin", false);
}
pw.println(" ");
- pw.println(" mPausingActivity: " + mPausingActivity);
- pw.println(" mResumedActivity: " + mResumedActivity);
+ pw.println(" mPausingActivity: " + mMainStack.mPausingActivity);
+ pw.println(" mResumedActivity: " + mMainStack.mResumedActivity);
pw.println(" mFocusedActivity: " + mFocusedActivity);
- pw.println(" mLastPausedActivity: " + mLastPausedActivity);
+ pw.println(" mLastPausedActivity: " + mMainStack.mLastPausedActivity);
if (dumpAll && mRecentTasks.size() > 0) {
pw.println(" ");
@@ -10268,7 +7029,7 @@
pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
}
pw.println(" mConfiguration: " + mConfiguration);
- pw.println(" mConfigWillChange: " + mConfigWillChange);
+ pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange);
pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
@@ -10287,8 +7048,8 @@
+ " mBooting=" + mBooting
+ " mBooted=" + mBooted
+ " mFactoryTest=" + mFactoryTest);
- pw.println(" mGoingToSleep=" + mGoingToSleep);
- pw.println(" mLaunchingActivity=" + mLaunchingActivity);
+ pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep);
+ pw.println(" mLaunchingActivity=" + mMainStack.mLaunchingActivity);
pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
}
@@ -10778,22 +7539,6 @@
return false;
}
- private final int indexOfTokenLocked(IBinder token) {
- int count = mHistory.size();
-
- // convert the token to an entry in the history.
- int index = -1;
- for (int i=count-1; i>=0; i--) {
- Object o = mHistory.get(i);
- if (o == token) {
- index = i;
- break;
- }
- }
-
- return index;
- }
-
private final void killServicesLocked(ProcessRecord app,
boolean allowRestart) {
// Report disconnected services.
@@ -12071,12 +8816,12 @@
ActivityRecord activity = null;
if (token != null) {
- int aindex = indexOfTokenLocked(token);
+ int aindex = mMainStack.indexOfTokenLocked(token);
if (aindex < 0) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
- activity = (ActivityRecord)mHistory.get(aindex);
+ activity = (ActivityRecord)mMainStack.mHistory.get(aindex);
}
int clientLabel = 0;
@@ -12180,7 +8925,7 @@
return 1;
}
- private void removeConnectionLocked(
+ void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
@@ -14012,18 +10757,18 @@
// If the configuration changed, and the caller is not already
// in the process of starting an activity, then find the top
// activity to check if its configuration needs to change.
- starting = topRunningActivityLocked(null);
+ starting = mMainStack.topRunningActivityLocked(null);
}
if (starting != null) {
- kept = ensureActivityConfigurationLocked(starting, changes);
+ kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
if (kept) {
// If this didn't result in the starting activity being
// destroyed, then we need to make sure at this point that all
// other activities are made visible.
if (DEBUG_SWITCH) Slog.i(TAG, "Config didn't destroy " + starting
+ ", ensuring others are correct.");
- ensureActivitiesVisibleLocked(starting, changes);
+ mMainStack.ensureActivitiesVisibleLocked(starting, changes);
}
}
@@ -14033,160 +10778,6 @@
return kept;
}
-
- private final boolean relaunchActivityLocked(ActivityRecord r,
- int changes, boolean andResume) {
- List<ResultInfo> results = null;
- List<Intent> newIntents = null;
- if (andResume) {
- results = r.results;
- newIntents = r.newIntents;
- }
- if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
- + " with results=" + results + " newIntents=" + newIntents
- + " andResume=" + andResume);
- EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
- : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
- r.task.taskId, r.shortComponentName);
-
- r.startFreezingScreenLocked(r.app, 0);
-
- try {
- if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
- r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
- changes, !andResume, mConfiguration);
- // Note: don't need to call pauseIfSleepingLocked() here, because
- // the caller will only pass in 'andResume' if this activity is
- // currently resumed, which implies we aren't sleeping.
- } catch (RemoteException e) {
- return false;
- }
-
- if (andResume) {
- r.results = null;
- r.newIntents = null;
- reportResumedActivityLocked(r);
- }
-
- return true;
- }
-
- /**
- * Make sure the given activity matches the current configuration. Returns
- * false if the activity had to be destroyed. Returns true if the
- * configuration is the same, or the activity will remain running as-is
- * for whatever reason. Ensures the HistoryRecord is updated with the
- * correct configuration and all other bookkeeping is handled.
- */
- private final boolean ensureActivityConfigurationLocked(ActivityRecord r,
- int globalChanges) {
- if (mConfigWillChange) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Skipping config check (will change): " + r);
- return true;
- }
-
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Ensuring correct configuration: " + r);
-
- // Short circuit: if the two configurations are the exact same
- // object (the common case), then there is nothing to do.
- Configuration newConfig = mConfiguration;
- if (r.configuration == newConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Configuration unchanged in " + r);
- return true;
- }
-
- // We don't worry about activities that are finishing.
- if (r.finishing) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Configuration doesn't matter in finishing " + r);
- r.stopFreezingScreenLocked(false);
- return true;
- }
-
- // Okay we now are going to make this activity have the new config.
- // But then we need to figure out how it needs to deal with that.
- Configuration oldConfig = r.configuration;
- r.configuration = newConfig;
-
- // If the activity isn't currently running, just leave the new
- // configuration and it will pick that up next time it starts.
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Configuration doesn't matter not running " + r);
- r.stopFreezingScreenLocked(false);
- return true;
- }
-
- // If the activity isn't persistent, there is a chance we will
- // need to restart it.
- if (!r.persistent) {
-
- // Figure out what has changed between the two configurations.
- int changes = oldConfig.diff(newConfig);
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(r.info.configChanges)
- + ", newConfig=" + newConfig);
- }
- if ((changes&(~r.info.configChanges)) != 0) {
- // Aha, the activity isn't handling the change, so DIE DIE DIE.
- r.configChangeFlags |= changes;
- r.startFreezingScreenLocked(r.app, globalChanges);
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is destroying non-running " + r);
- destroyActivityLocked(r, true);
- } else if (r.state == ActivityState.PAUSING) {
- // A little annoying: we are waiting for this activity to
- // finish pausing. Let's not do anything now, but just
- // flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is skipping already pausing " + r);
- r.configDestroy = true;
- return true;
- } else if (r.state == ActivityState.RESUMED) {
- // Try to optimize this case: the configuration is changing
- // and we need to restart the top, resumed activity.
- // Instead of doing the normal handshaking, just say
- // "restart!".
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, true);
- r.configChangeFlags = 0;
- } else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting non-resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, false);
- r.configChangeFlags = 0;
- }
-
- // All done... tell the caller we weren't able to keep this
- // activity around.
- return false;
- }
- }
-
- // Default case: the activity can handle this new configuration, so
- // hand it over. Note that we don't need to give it the new
- // configuration, since we always send configuration changes to all
- // process when they happen so it can just use whatever configuration
- // it last got.
- if (r.app != null && r.app.thread != null) {
- try {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
- r.app.thread.scheduleActivityConfigurationChanged(r);
- } catch (RemoteException e) {
- // If process died, whatever.
- }
- }
- r.stopFreezingScreenLocked(false);
-
- return true;
- }
/**
* Save the locale. You must be inside a synchronized (this) block.
@@ -14542,8 +11133,8 @@
private final boolean canGcNowLocked() {
return mParallelBroadcasts.size() == 0
&& mOrderedBroadcasts.size() == 0
- && (mSleeping || (mResumedActivity != null &&
- mResumedActivity.idle));
+ && (mSleeping || (mMainStack.mResumedActivity != null &&
+ mMainStack.mResumedActivity.idle));
}
/**
@@ -14714,11 +11305,11 @@
}
private final ActivityRecord resumedAppLocked() {
- ActivityRecord resumedActivity = mResumedActivity;
+ ActivityRecord resumedActivity = mMainStack.mResumedActivity;
if (resumedActivity == null || resumedActivity.app == null) {
- resumedActivity = mPausingActivity;
+ resumedActivity = mMainStack.mPausingActivity;
if (resumedActivity == null || resumedActivity.app == null) {
- resumedActivity = topRunningActivityLocked(null);
+ resumedActivity = mMainStack.topRunningActivityLocked(null);
}
}
return resumedActivity;
@@ -14746,7 +11337,7 @@
return res;
}
- private final boolean updateOomAdjLocked() {
+ final boolean updateOomAdjLocked() {
boolean didOomAdj = true;
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -14810,7 +11401,7 @@
return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
}
- private final void trimApplications() {
+ final void trimApplications() {
synchronized (this) {
int i;
@@ -14942,7 +11533,7 @@
for (j=0; j<NUMA; j++) {
ActivityRecord r = app.activities.get(j);
if (!r.finishing) {
- destroyActivityLocked(r, false);
+ r.stack.destroyActivityLocked(r, false);
}
r.resultTo = null;
}
@@ -14979,25 +11570,25 @@
// Finally, if there are too many activities now running, try to
// finish as many as we can to get back down to the limit.
for ( i=0;
- i<mLRUActivities.size()
- && mLRUActivities.size() > curMaxActivities;
+ i<mMainStack.mLRUActivities.size()
+ && mMainStack.mLRUActivities.size() > curMaxActivities;
i++) {
final ActivityRecord r
- = (ActivityRecord)mLRUActivities.get(i);
+ = (ActivityRecord)mMainStack.mLRUActivities.get(i);
// We can finish this one if we have its icicle saved and
// it is not persistent.
if ((r.haveState || !r.stateNotNeeded) && !r.visible
&& r.stopped && !r.persistent && !r.finishing) {
- final int origSize = mLRUActivities.size();
- destroyActivityLocked(r, true);
+ final int origSize = mMainStack.mLRUActivities.size();
+ r.stack.destroyActivityLocked(r, true);
// This will remove it from the LRU list, so keep
// our index at the same value. Note that this check to
// see if the size changes is just paranoia -- if
// something unexpected happens, we don't want to end up
// in an infinite loop.
- if (origSize > mLRUActivities.size()) {
+ if (origSize > mMainStack.mLRUActivities.size()) {
i--;
}
}