diff options
Diffstat (limited to 'services/java/com/android/server/am/ActivityManagerService.java')
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 4712 |
1 files changed, 881 insertions, 3831 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 804af9c..b2cb941 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -16,6 +16,8 @@ package com.android.server.am; +import com.android.internal.R; +import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.os.BatteryStatsImpl; import com.android.server.AttributeCache; import com.android.server.IntentResolver; @@ -24,6 +26,7 @@ import com.android.server.ProcessStats; 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; @@ -32,6 +35,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.AlertDialog; +import android.app.AppGlobals; import android.app.ApplicationErrorReport; import android.app.Dialog; import android.app.IActivityController; @@ -39,10 +43,12 @@ import android.app.IActivityManager; import android.app.IActivityWatcher; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; +import android.app.INotificationManager; import android.app.IServiceConnection; import android.app.IThumbnailReceiver; import android.app.Instrumentation; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ResultInfo; import android.app.Service; @@ -70,6 +76,7 @@ import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.graphics.Bitmap; import android.net.Uri; @@ -93,6 +100,7 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; @@ -177,47 +185,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // 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; @@ -284,6 +266,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // system/rootdir/init.rc on startup. static final int SECONDARY_SERVER_ADJ; + // This is a process with a heavy-weight application. It is in the + // background, but we want to try to avoid killing it. Value set in + // system/rootdir/init.rc on startup. + static final int HEAVY_WEIGHT_APP_ADJ; + + // This is a process only hosting components that are perceptible to the + // user, and we really want to avoid killing them, but they are not + // immediately visible. An example is background music playback. Value set in + // system/rootdir/init.rc on startup. + static final int PERCEPTIBLE_APP_ADJ; + // This is a process only hosting activities that are visible to the // user, so we'd prefer they don't disappear. Value set in // system/rootdir/init.rc on startup. @@ -309,6 +302,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen static final int HOME_APP_MEM; static final int BACKUP_APP_MEM; static final int SECONDARY_SERVER_MEM; + static final int HEAVY_WEIGHT_APP_MEM; + static final int PERCEPTIBLE_APP_MEM; static final int VISIBLE_APP_MEM; static final int FOREGROUND_APP_MEM; @@ -329,68 +324,55 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // been idle for less than 120 seconds. static final long EMPTY_APP_IDLE_OFFSET = 120*1000; + static int getIntProp(String name, boolean allowZero) { + String str = SystemProperties.get(name); + if (str == null) { + throw new IllegalArgumentException("Property not defined: " + name); + } + int val = Integer.valueOf(str); + if (val == 0 && !allowZero) { + throw new IllegalArgumentException("Property must not be zero: " + name); + } + return val; + } + static { // These values are set in system/rootdir/init.rc on startup. - FOREGROUND_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ")); - VISIBLE_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ")); - SECONDARY_SERVER_ADJ = - Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ")); - BACKUP_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ")); - HOME_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ")); - HIDDEN_APP_MIN_ADJ = - Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ")); - EMPTY_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ")); - HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1; - FOREGROUND_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE; - VISIBLE_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE; - SECONDARY_SERVER_MEM = - Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE; - BACKUP_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE; - HOME_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE; - HIDDEN_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE; - EMPTY_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE; + FOREGROUND_APP_ADJ = getIntProp("ro.FOREGROUND_APP_ADJ", true); + VISIBLE_APP_ADJ = getIntProp("ro.VISIBLE_APP_ADJ", true); + PERCEPTIBLE_APP_ADJ = getIntProp("ro.PERCEPTIBLE_APP_ADJ", true); + HEAVY_WEIGHT_APP_ADJ = getIntProp("ro.HEAVY_WEIGHT_APP_ADJ", true); + SECONDARY_SERVER_ADJ = getIntProp("ro.SECONDARY_SERVER_ADJ", true); + BACKUP_APP_ADJ = getIntProp("ro.BACKUP_APP_ADJ", true); + HOME_APP_ADJ = getIntProp("ro.HOME_APP_ADJ", true); + HIDDEN_APP_MIN_ADJ = getIntProp("ro.HIDDEN_APP_MIN_ADJ", true); + EMPTY_APP_ADJ = getIntProp("ro.EMPTY_APP_ADJ", true); + // These days we use the last empty slot for hidden apps as well. + HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ; + FOREGROUND_APP_MEM = getIntProp("ro.FOREGROUND_APP_MEM", false)*PAGE_SIZE; + VISIBLE_APP_MEM = getIntProp("ro.VISIBLE_APP_MEM", false)*PAGE_SIZE; + PERCEPTIBLE_APP_MEM = getIntProp("ro.PERCEPTIBLE_APP_MEM", false)*PAGE_SIZE; + HEAVY_WEIGHT_APP_MEM = getIntProp("ro.HEAVY_WEIGHT_APP_MEM", false)*PAGE_SIZE; + SECONDARY_SERVER_MEM = getIntProp("ro.SECONDARY_SERVER_MEM", false)*PAGE_SIZE; + BACKUP_APP_MEM = getIntProp("ro.BACKUP_APP_MEM", false)*PAGE_SIZE; + HOME_APP_MEM = getIntProp("ro.HOME_APP_MEM", false)*PAGE_SIZE; + HIDDEN_APP_MEM = getIntProp("ro.HIDDEN_APP_MEM", false)*PAGE_SIZE; + EMPTY_APP_MEM = getIntProp("ro.EMPTY_APP_MEM", false)*PAGE_SIZE; } static final int MY_PID = Process.myPid(); 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 { - HistoryRecord r; - HistoryRecord sourceRecord; + static class PendingActivityLaunch { + ActivityRecord r; + ActivityRecord sourceRecord; Uri[] grantedUriPermissions; int grantedMode; boolean onlyIfNeeded; @@ -400,18 +382,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen = 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 @@ -441,56 +411,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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. - */ - HistoryRecord mPausingActivity = null; - - /** - * Current activity that is resumed, or null if there is none. - */ - HistoryRecord mResumedActivity = null; - - /** * Activity we have told the window manager to have key focus. */ - HistoryRecord 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. - */ - HistoryRecord 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 mWaitingVisibleActivities = new ArrayList(); - - /** - * 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<HistoryRecord> mStoppingActivities - = new ArrayList<HistoryRecord>(); - - /** - * Animations that for the current transition have requested not to - * be considered for the transition animation. - */ - final ArrayList<HistoryRecord> mNoAnimActivities - = new ArrayList<HistoryRecord>(); - + ActivityRecord mFocusedActivity = null; /** * List of intents that were used to start the most recent tasks. */ @@ -498,13 +421,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen = 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 mFinishingActivities = new ArrayList(); - - /** * 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 @@ -514,6 +430,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen = new ProcessMap<ProcessRecord>(); /** + * The currently running heavy-weight process, if any. + */ + ProcessRecord mHeavyWeightProcess = null; + + /** * The last time that various processes have crashed. */ final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>(); @@ -599,16 +520,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * 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(); @@ -620,6 +534,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>(); /** + * Fingerprints (String.hashCode()) of stack traces that we've + * already logged DropBox entries for. Guarded by itself. If + * something (rogue user app) forces this over + * MAX_DUP_SUPPRESSED_STACKS entries, the contents are cleared. + */ + private final HashSet<Integer> mAlreadyLoggedViolatedStacks = new HashSet<Integer>(); + private static final int MAX_DUP_SUPPRESSED_STACKS = 5000; + + /** + * Strict Mode background batched logging state. + * + * The string buffer is guarded by itself, and its lock is also + * used to determine if another batched write is already + * in-flight. + */ + private final StringBuilder mStrictModeBuffer = new StringBuilder(); + + /** * Intent broadcast that we have tried to start, but are * waiting for its application's process to be created. We only * need one (instead of a list) because we always process broadcasts @@ -727,21 +659,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * that a single provider may be published under multiple names, so * there may be multiple entries here for a single one in mProvidersByClass. */ - final HashMap mProvidersByName = new HashMap(); + final HashMap<String, ContentProviderRecord> mProvidersByName + = new HashMap<String, ContentProviderRecord>(); /** * All of the currently running global content providers. Keys are a * string containing the provider's implementation class and values are a * ContentProviderRecord object containing the data about it. */ - final HashMap mProvidersByClass = new HashMap(); + final HashMap<String, ContentProviderRecord> mProvidersByClass + = new HashMap<String, ContentProviderRecord>(); /** * List of content providers who have clients waiting for them. The * application is currently being launched and the provider will be * removed from this list once it is published. */ - final ArrayList mLaunchingProviders = new ArrayList(); + final ArrayList<ContentProviderRecord> mLaunchingProviders + = new ArrayList<ContentProviderRecord>(); /** * Global set of specific Uri permissions that have been granted. @@ -790,12 +725,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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; @@ -851,21 +780,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * 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 @@ -945,8 +859,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen long mLastWriteTime = 0; - long mInitialStartTime = 0; - /** * Set to true after the system has finished booting. */ @@ -978,7 +890,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (localLOGV) Slog.v( TAG, "Death received in " + this + " for thread " + mAppThread.asBinder()); - removeRequestedPss(mApp); synchronized(ActivityManagerService.this) { appDiedLocked(mApp, mPid, mAppThread); } @@ -993,20 +904,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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; static final int FINALIZE_PENDING_INTENT_MSG = 23; + static final int POST_HEAVY_NOTIFICATION_MSG = 24; + static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25; + static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26; AlertDialog mUidAlert; @@ -1053,13 +961,38 @@ public final class ActivityManagerService extends ActivityManagerNative implemen false, false, MY_PID, Process.SYSTEM_UID); Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, - mContext, proc, (HistoryRecord)data.get("activity")); + mContext, proc, (ActivityRecord)data.get("activity")); d.show(); proc.anrDialog = d; } ensureBootCompleted(); } break; + case SHOW_STRICT_MODE_VIOLATION_MSG: { + HashMap<String, Object> data = (HashMap<String, Object>) msg.obj; + synchronized (ActivityManagerService.this) { + ProcessRecord proc = (ProcessRecord) data.get("app"); + if (proc == null) { + Slog.e(TAG, "App not found when showing strict mode dialog."); + break; + } + if (proc.crashDialog != null) { + Slog.e(TAG, "App already has strict mode dialog: " + proc); + return; + } + AppErrorResult res = (AppErrorResult) data.get("result"); + if (!mSleeping && !mShuttingDown) { + Dialog d = new StrictModeViolationDialog(mContext, res, proc); + d.show(); + proc.crashDialog = d; + } else { + // The device is asleep, so just pretend that the user + // saw a crash dialog and hit "force quit". + res.set(0); + } + } + ensureBootCompleted(); + } break; case SHOW_FACTORY_ERROR_MSG: { Dialog d = new FactoryErrorDialog( mContext, msg.getData().getCharSequence("msg")); @@ -1114,38 +1047,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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; @@ -1188,25 +1089,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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; @@ -1236,6 +1118,62 @@ public final class ActivityManagerService extends ActivityManagerNative implemen case FINALIZE_PENDING_INTENT_MSG: { ((PendingIntentRecord)msg.obj).completeFinalize(); } break; + case POST_HEAVY_NOTIFICATION_MSG: { + INotificationManager inm = NotificationManager.getService(); + if (inm == null) { + return; + } + + ActivityRecord root = (ActivityRecord)msg.obj; + ProcessRecord process = root.app; + if (process == null) { + return; + } + + try { + Context context = mContext.createPackageContext(process.info.packageName, 0); + String text = mContext.getString(R.string.heavy_weight_notification, + context.getApplicationInfo().loadLabel(context.getPackageManager())); + Notification notification = new Notification(); + notification.icon = com.android.internal.R.drawable.stat_sys_adb; //context.getApplicationInfo().icon; + notification.when = 0; + notification.flags = Notification.FLAG_ONGOING_EVENT; + notification.tickerText = text; + notification.defaults = 0; // please be quiet + notification.sound = null; + notification.vibrate = null; + notification.setLatestEventInfo(context, text, + mContext.getText(R.string.heavy_weight_notification_detail), + PendingIntent.getActivity(mContext, 0, root.intent, + PendingIntent.FLAG_CANCEL_CURRENT)); + + try { + int[] outId = new int[1]; + inm.enqueueNotification("android", R.string.heavy_weight_notification, + notification, outId); + } catch (RuntimeException e) { + Slog.w(ActivityManagerService.TAG, + "Error showing notification for heavy-weight app", e); + } catch (RemoteException e) { + } + } catch (NameNotFoundException e) { + Log.w(TAG, "Unable to create context for heavy notification", e); + } + } break; + case CANCEL_HEAVY_NOTIFICATION_MSG: { + INotificationManager inm = NotificationManager.getService(); + if (inm == null) { + return; + } + try { + inm.cancelNotification("android", + R.string.heavy_weight_notification); + } catch (RuntimeException e) { + Slog.w(ActivityManagerService.TAG, + "Error canceling notification for service", e); + } catch (RemoteException e) { + } + } break; } } }; @@ -1299,11 +1237,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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); @@ -1335,6 +1269,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); + android.os.Process.setCanSelfBackground(false); ActivityManagerService m = new ActivityManagerService(); @@ -1592,7 +1527,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return mAppBindArgs; } - private final void setFocusedActivityLocked(HistoryRecord r) { + final void setFocusedActivityLocked(ActivityRecord r) { if (mFocusedActivity != r) { mFocusedActivity = r; mWindowManager.setFocusedApp(r, true); @@ -1677,65 +1612,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - 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(HistoryRecord r) { - final boolean hadit = mLRUActivities.remove(r); - mLRUActivities.add(r); - return hadit; - } - - private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) { - int i = mHistory.size()-1; - while (i >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (!r.finishing && r != notTop) { - return r; - } - i--; - } - return null; - } - - private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) { - int i = mHistory.size()-1; - while (i >= 0) { - HistoryRecord r = (HistoryRecord)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 HistoryRecord topRunningActivityLocked(IBinder token, int taskId) { - int i = mHistory.size()-1; - while (i >= 0) { - HistoryRecord r = (HistoryRecord)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 @@ -1749,8 +1632,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return proc; } - private void ensurePackageDexOpt(String packageName) { - IPackageManager pm = ActivityThread.getPackageManager(); + void ensurePackageDexOpt(String packageName) { + IPackageManager pm = AppGlobals.getPackageManager(); try { if (pm.performDexOpt(packageName)) { mDidDexOpt = true; @@ -1759,157 +1642,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - 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(HistoryRecord 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()); - } 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(HistoryRecord 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); @@ -2055,7 +1795,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen hostingNameStr != null ? hostingNameStr : ""); if (app.persistent) { - Watchdog.getInstance().processStarted(app, app.processName, pid); + Watchdog.getInstance().processStarted(app.processName, pid); } StringBuilder buf = mStringBuilder; @@ -2110,365 +1850,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - 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); - } - HistoryRecord 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() { - HistoryRecord 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(HistoryRecord 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(HistoryRecord top, - HistoryRecord 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--; - } - HistoryRecord r; - boolean behindFullscreen = false; - for (; i>=0; i--) { - r = (HistoryRecord)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 = (HistoryRecord)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(HistoryRecord starting, - int configChanges) { - HistoryRecord r = topRunningActivityLocked(null); - if (r != null) { - ensureActivitiesVisibleLocked(r, starting, null, configChanges); - } - } - - private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) { + void updateUsageStats(ActivityRecord resumedComponent, boolean resumed) { if (resumed) { mUsageStatsService.noteResumeComponent(resumedComponent.realActivity); } else { @@ -2476,7 +1858,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - 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 @@ -2503,7 +1885,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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); } } @@ -2515,7 +1897,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen /** * Starts the "new version setup screen" if appropriate. */ - private void startSetupActivityLocked() { + void startSetupActivityLocked() { // Only do this once per boot. if (mCheckedForSetup) { return; @@ -2559,14 +1941,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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(HistoryRecord r) { + void reportResumedActivityLocked(ActivityRecord r) { //Slog.i(TAG, "**** REPORT RESUME: " + r); final int identHash = System.identityHashCode(r); @@ -2585,1210 +1967,27 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } 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(HistoryRecord prev) { - // Find the first activity that is not finishing. - HistoryRecord 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); - - HistoryRecord 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. - HistoryRecord 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(HistoryRecord 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... - HistoryRecord next = null; - boolean startIt = true; - for (int i = NH-1; i >= 0; i--) { - HistoryRecord p = (HistoryRecord)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. - HistoryRecord 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 HistoryRecord performClearTaskLocked(int taskId, - HistoryRecord newR, int launchFlags, boolean doClear) { - int i = mHistory.size(); - - // First find the requested task. - while (i > 0) { - i--; - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (r.task.taskId == taskId) { - i++; - break; - } - } - - // Now clear it. - while (i > 0) { - i--; - HistoryRecord r = (HistoryRecord)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... - HistoryRecord ret = r; - if (doClear) { - while (i < (mHistory.size()-1)) { - i++; - r = (HistoryRecord)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(HistoryRecord r, int task) { - int i = mHistory.size(); - while (i > 0) { - i--; - HistoryRecord candidate = (HistoryRecord)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 HistoryRecord moveActivityToFrontLocked(int where) { - HistoryRecord newTop = (HistoryRecord)mHistory.remove(where); - int top = mHistory.size(); - HistoryRecord oldTop = (HistoryRecord)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(HistoryRecord 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, HistoryRecord 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); - - HistoryRecord sourceRecord = null; - HistoryRecord 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 = (HistoryRecord)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; - } - } - - HistoryRecord r = new HistoryRecord(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(HistoryRecord r, - HistoryRecord 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; - } - - HistoryRecord 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) { - HistoryRecord 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. - HistoryRecord 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. - HistoryRecord 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. - HistoryRecord 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. - HistoryRecord 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. - HistoryRecord 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) { - HistoryRecord 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(); - HistoryRecord prev = - N > 0 ? (HistoryRecord)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, HistoryRecord 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(HistoryRecord 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"); - } - - final 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 = - ActivityThread.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(); - - 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) { - HistoryRecord 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); } @@ -3799,7 +1998,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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; @@ -3810,7 +2009,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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); } @@ -3834,8 +2033,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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; } @@ -3853,11 +2052,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } synchronized (this) { - int index = indexOfTokenLocked(callingActivity); + int index = mMainStack.indexOfTokenLocked(callingActivity); if (index < 0) { return false; } - HistoryRecord r = (HistoryRecord)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; @@ -3871,7 +2070,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ActivityInfo aInfo = null; try { List<ResolveInfo> resolves = - ActivityThread.getPackageManager().queryIntentActivities( + AppGlobals.getPackageManager().queryIntentActivities( intent, r.resolvedType, PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS); @@ -3915,7 +2114,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen r.finishing = true; // Propagate reply information over to the new activity. - final HistoryRecord resultTo = r.resultTo; + final ActivityRecord resultTo = r.resultTo; final String resultWho = r.resultWho; final int requestCode = r.requestCode; r.resultTo = null; @@ -3926,7 +2125,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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); @@ -3960,7 +2159,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ActivityInfo aInfo; try { ResolveInfo rInfo = - ActivityThread.getPackageManager().resolveIntent( + AppGlobals.getPackageManager().resolveIntent( intent, resolvedType, PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS); aInfo = rInfo != null ? rInfo.activityInfo : null; @@ -3978,13 +2177,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } 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++) { @@ -4010,11 +2209,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public void setRequestedOrientation(IBinder token, int requestedOrientation) { synchronized (this) { - int index = indexOfTokenLocked(token); + int index = mMainStack.indexOfTokenLocked(token); if (index < 0) { return; } - HistoryRecord r = (HistoryRecord)mHistory.get(index); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); final long origId = Binder.clearCallingIdentity(); mWindowManager.setAppOrientation(r, requestedOrientation); Configuration config = mWindowManager.updateOrientationFromAppTokens( @@ -4023,7 +2222,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (config != null) { r.frozenBeforeDestroy = true; if (!updateConfigurationLocked(config, r)) { - resumeTopActivityLocked(null); + mMainStack.resumeTopActivityLocked(null); } } Binder.restoreCallingIdentity(origId); @@ -4032,250 +2231,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public int getRequestedOrientation(IBinder token) { synchronized (this) { - int index = indexOfTokenLocked(token); + int index = mMainStack.indexOfTokenLocked(token); if (index < 0) { return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } - HistoryRecord r = (HistoryRecord)mHistory.get(index); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); return mWindowManager.getAppOrientation(r); } } - private final void stopActivityLocked(HistoryRecord 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; - } - HistoryRecord r = (HistoryRecord)mHistory.get(index); - - // Is this the last activity left? - boolean lastActivity = true; - for (int i=mHistory.size()-1; i>=0; i--) { - HistoryRecord p = (HistoryRecord)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(HistoryRecord 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)) { - HistoryRecord next = (HistoryRecord)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 - HistoryRecord 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 - || ((HistoryRecord)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 HistoryRecord finishCurrentActivityLocked(HistoryRecord r, - int mode) { - final int index = indexOfTokenLocked(r); - if (index < 0) { - return null; - } - - return finishCurrentActivityLocked(r, index, mode); - } - - private final HistoryRecord finishCurrentActivityLocked(HistoryRecord 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(). * @@ -4294,7 +2258,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen synchronized(this) { if (mController != null) { // Find the first activity that is not finishing. - HistoryRecord next = topRunningActivityLocked(token, 0); + ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0); if (next != null) { // ask watcher if this is allowed boolean resumeOK = true; @@ -4310,57 +2274,119 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } final long origId = Binder.clearCallingIdentity(); - boolean res = requestFinishActivityLocked(token, resultCode, + boolean res = mMainStack.requestFinishActivityLocked(token, resultCode, resultData, "app-request"); Binder.restoreCallingIdentity(origId); return res; } } - void sendActivityResultLocked(int callingUid, HistoryRecord r, - String resultWho, int requestCode, int resultCode, Intent data) { - - if (callingUid > 0) { - grantUriPermissionFromIntentLocked(callingUid, r.packageName, - data, r); + public final void finishHeavyWeightApp() { + if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) + != PackageManager.PERMISSION_GRANTED) { + String msg = "Permission Denial: finishHeavyWeightApp() from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES; + Slog.w(TAG, msg); + throw new SecurityException(msg); } - - 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); + + synchronized(this) { + if (mHeavyWeightProcess == null) { return; - } catch (Exception e) { - Slog.w(TAG, "Exception thrown sending result to " + r, e); } + + ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>( + mHeavyWeightProcess.activities); + for (int i=0; i<activities.size(); i++) { + ActivityRecord r = activities.get(i); + if (!r.finishing) { + int index = mMainStack.indexOfTokenLocked(r); + if (index >= 0) { + mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED, + null, "finish-heavy"); + } + } + } + + mHeavyWeightProcess = null; + mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG); } - - r.addResultLocked(null, resultWho, requestCode, resultCode, data); } - + + public void crashApplication(int uid, int initialPid, String packageName, + String message) { + if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) + != PackageManager.PERMISSION_GRANTED) { + String msg = "Permission Denial: crashApplication() from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + + synchronized(this) { + ProcessRecord proc = null; + + // Figure out which process to kill. We don't trust that initialPid + // still has any relation to current pids, so must scan through the + // list. + synchronized (mPidsSelfLocked) { + for (int i=0; i<mPidsSelfLocked.size(); i++) { + ProcessRecord p = mPidsSelfLocked.valueAt(i); + if (p.info.uid != uid) { + continue; + } + if (p.pid == initialPid) { + proc = p; + break; + } + for (String str : p.pkgList) { + if (str.equals(packageName)) { + proc = p; + } + } + } + } + + if (proc == null) { + Log.w(TAG, "crashApplication: nothing for uid=" + uid + + " initialPid=" + initialPid + + " packageName=" + packageName); + return; + } + + if (proc.thread != null) { + long ident = Binder.clearCallingIdentity(); + try { + proc.thread.scheduleCrash(message); + } catch (RemoteException e) { + } + Binder.restoreCallingIdentity(ident); + } + } + } + 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; } - HistoryRecord self = (HistoryRecord)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--) { - HistoryRecord r = (HistoryRecord)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"); } } @@ -4373,8 +2399,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public boolean willActivityBeVisible(IBinder token) { synchronized(this) { int i; - for (i=mHistory.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); + for (i=mMainStack.mHistory.size()-1; i>=0; i--) { + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); if (r == token) { return true; } @@ -4389,11 +2415,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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; } - HistoryRecord self = (HistoryRecord)mHistory.get(index); + ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index); final long origId = Binder.clearCallingIdentity(); @@ -4408,188 +2434,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } /** - * Perform clean-up of service connections in an activity record. - */ - private final void cleanUpActivityServicesLocked(HistoryRecord 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(HistoryRecord 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(HistoryRecord 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(HistoryRecord 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 (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--; - HistoryRecord r = (HistoryRecord)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. @@ -4602,30 +2446,27 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } // 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--; - HistoryRecord r = (HistoryRecord)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) { @@ -4633,14 +2474,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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 @@ -4657,7 +2498,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - cleanUpActivityLocked(r, true); + r.stack.cleanUpActivityLocked(r, true); r.state = ActivityState.STOPPED; } atTop = false; @@ -4674,14 +2515,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } 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); } } } @@ -4700,7 +2541,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return -1; } - private final ProcessRecord getRecordForAppLocked( + final ProcessRecord getRecordForAppLocked( IApplicationThread thread) { if (thread == null) { return null; @@ -4710,7 +2551,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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]++; @@ -4752,8 +2593,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) { // The low memory report is overriding any current // state for a GC request. Make sure to do - // visible/foreground processes first. - if (rec.setAdj <= VISIBLE_APP_ADJ) { + // heavy/important/visible/foreground processes first. + if (rec.setAdj <= HEAVY_WEIGHT_APP_ADJ) { rec.lastRequestedGc = 0; } else { rec.lastRequestedGc = rec.lastLowMemory; @@ -4830,8 +2671,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return tracesFile; } - final void appNotResponding(ProcessRecord app, HistoryRecord activity, - HistoryRecord parent, final String annotation) { + final void appNotResponding(ProcessRecord app, ActivityRecord activity, + ActivityRecord parent, final String annotation) { ArrayList<Integer> pids = new ArrayList<Integer>(20); synchronized (this) { @@ -4950,8 +2791,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - private final void decPersistentCountLocked(ProcessRecord app) - { + final void decPersistentCountLocked(ProcessRecord app) { app.persistentActivities--; if (app.persistentActivities > 0) { // Still more of 'em... @@ -4979,11 +2819,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } synchronized(this) { - int index = indexOfTokenLocked(token); + int index = mMainStack.indexOfTokenLocked(token); if (index < 0) { return; } - HistoryRecord r = (HistoryRecord)mHistory.get(index); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); ProcessRecord app = r.app; if (localLOGV) Slog.v( @@ -5035,7 +2875,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int pid = Binder.getCallingPid(); long callingId = Binder.clearCallingIdentity(); try { - IPackageManager pm = ActivityThread.getPackageManager(); + IPackageManager pm = AppGlobals.getPackageManager(); int pkgUid = -1; synchronized(this) { try { @@ -5092,7 +2932,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen long callingId = Binder.clearCallingIdentity(); try { - IPackageManager pm = ActivityThread.getPackageManager(); + IPackageManager pm = AppGlobals.getPackageManager(); int pkgUid = -1; synchronized(this) { try { @@ -5124,7 +2964,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen long callingId = Binder.clearCallingIdentity(); try { - IPackageManager pm = ActivityThread.getPackageManager(); + IPackageManager pm = AppGlobals.getPackageManager(); int pkgUid = -1; synchronized(this) { try { @@ -5194,10 +3034,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mWindowManager.closeSystemDialogs(reason); - for (i=mHistory.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)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"); } } @@ -5298,7 +3138,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (uid < 0) { try { - uid = ActivityThread.getPackageManager().getPackageUid(name); + uid = AppGlobals.getPackageManager().getPackageUid(name); } catch (RemoteException e) { } } @@ -5318,8 +3158,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen boolean didSomething = killPackageProcessesLocked(name, uid, -100, callerWillRestart, doit); - for (i=mHistory.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)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; @@ -5330,7 +3170,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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"); } } @@ -5362,7 +3202,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ac.removePackage(name); } } - resumeTopActivityLocked(null); + mMainStack.resumeTopActivityLocked(null); } return didSomething; @@ -5376,6 +3216,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen + "/" + uid + ")"); mProcessNames.remove(name, uid); + if (mHeavyWeightProcess == app) { + mHeavyWeightProcess = null; + mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG); + } boolean needRestart = false; if (app.pid > 0 && app.pid != MY_PID) { int pid = app.pid; @@ -5417,6 +3261,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid, app.processName); mProcessNames.remove(app.processName, app.info.uid); + if (mHeavyWeightProcess == app) { + mHeavyWeightProcess = null; + mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG); + } // Take care of any launching providers waiting for this process. checkAppInLaunchingProvidersLocked(app, true); // Take care of any services that are waiting for the process. @@ -5583,12 +3431,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen boolean didSomething = false; // See if the top visible activity is waiting to run in this process... - HistoryRecord 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) { @@ -5597,7 +3445,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen badApp = true; } } else { - ensureActivitiesVisibleLocked(hr, null, processName, 0); + mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0); } } @@ -5681,195 +3529,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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<HistoryRecord> processStoppingActivitiesLocked( - boolean remove) { - int N = mStoppingActivities.size(); - if (N <= 0) return null; - - ArrayList<HistoryRecord> stops = null; - - final boolean nowVisible = mResumedActivity != null - && mResumedActivity.nowVisible - && !mResumedActivity.waitingVisible; - for (int i=0; i<N; i++) { - HistoryRecord 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<HistoryRecord>(); - } - 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<HistoryRecord> stops = null; - ArrayList<HistoryRecord> finishes = null; - ArrayList<HistoryRecord> 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) { - HistoryRecord r = (HistoryRecord)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<HistoryRecord>(mFinishingActivities); - mFinishingActivities.clear(); - } - if ((NT=mCancelledThumbnails.size()) > 0) { - thumbnails = new ArrayList<HistoryRecord>(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++) { - HistoryRecord r = (HistoryRecord)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++) { - HistoryRecord r = (HistoryRecord)finishes.get(i); - synchronized (this) { - destroyActivityLocked(r, true); - } - } - - // Report back to any thumbnail receivers. - for (i=0; i<NT; i++) { - HistoryRecord r = (HistoryRecord)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); @@ -5940,60 +3609,31 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } 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); - - HistoryRecord r = null; - - synchronized (this) { - int index = indexOfTokenLocked(token); - if (index >= 0) { - r = (HistoryRecord)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( TAG, "Activity stopped: token=" + token); - HistoryRecord r = null; + ActivityRecord r = null; final long origId = Binder.clearCallingIdentity(); synchronized (this) { - int index = indexOfTokenLocked(token); + int index = mMainStack.indexOfTokenLocked(token); if (index >= 0) { - r = (HistoryRecord)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); } } } @@ -6010,39 +3650,27 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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) { - HistoryRecord r = (HistoryRecord)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) { synchronized (this) { - HistoryRecord r = getCallingRecordLocked(token); + ActivityRecord r = getCallingRecordLocked(token); return r != null && r.app != null ? r.info.packageName : null; } } public ComponentName getCallingActivity(IBinder token) { synchronized (this) { - HistoryRecord r = getCallingRecordLocked(token); + ActivityRecord r = getCallingRecordLocked(token); return r != null ? r.intent.getComponent() : null; } } - private HistoryRecord getCallingRecordLocked(IBinder token) { - int index = indexOfTokenLocked(token); + private ActivityRecord getCallingRecordLocked(IBinder token) { + int index = mMainStack.indexOfTokenLocked(token); if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); if (r != null) { return r.resultTo; } @@ -6052,9 +3680,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public ComponentName getActivityClassForToken(IBinder token) { synchronized(this) { - int index = indexOfTokenLocked(token); + int index = mMainStack.indexOfTokenLocked(token); if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); return r.intent.getComponent(); } return null; @@ -6063,9 +3691,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public String getPackageForToken(IBinder token) { synchronized(this) { - int index = indexOfTokenLocked(token); + int index = mMainStack.indexOfTokenLocked(token); if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); return r.packageName; } return null; @@ -6092,7 +3720,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen try { if (callingUid != 0 && callingUid != Process.SYSTEM_UID && Process.supportsProcesses()) { - int uid = ActivityThread.getPackageManager() + int uid = AppGlobals.getPackageManager() .getPackageUid(packageName); if (uid != Binder.getCallingUid()) { String msg = "Permission Denial: getIntentSender() from pid=" @@ -6104,57 +3732,66 @@ public final class ActivityManagerService extends ActivityManagerNative implemen throw new SecurityException(msg); } } + + return getIntentSenderLocked(type, packageName, callingUid, + token, resultWho, requestCode, intent, resolvedType, flags); + } catch (RemoteException e) { throw new SecurityException(e); } - HistoryRecord activity = null; - if (type == INTENT_SENDER_ACTIVITY_RESULT) { - int index = indexOfTokenLocked(token); - if (index < 0) { - return null; - } - activity = (HistoryRecord)mHistory.get(index); - if (activity.finishing) { - return null; - } + } + } + + IIntentSender getIntentSenderLocked(int type, + String packageName, int callingUid, IBinder token, String resultWho, + int requestCode, Intent intent, String resolvedType, int flags) { + ActivityRecord activity = null; + if (type == INTENT_SENDER_ACTIVITY_RESULT) { + int index = mMainStack.indexOfTokenLocked(token); + if (index < 0) { + return null; } + activity = (ActivityRecord)mMainStack.mHistory.get(index); + if (activity.finishing) { + return null; + } + } - final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0; - final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0; - final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0; - flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT - |PendingIntent.FLAG_UPDATE_CURRENT); + final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0; + final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0; + final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0; + flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT + |PendingIntent.FLAG_UPDATE_CURRENT); - PendingIntentRecord.Key key = new PendingIntentRecord.Key( - type, packageName, activity, resultWho, - requestCode, intent, resolvedType, flags); - WeakReference<PendingIntentRecord> ref; - ref = mIntentSenderRecords.get(key); - PendingIntentRecord rec = ref != null ? ref.get() : null; - if (rec != null) { - if (!cancelCurrent) { - if (updateCurrent) { - rec.key.requestIntent.replaceExtras(intent); - } - return rec; + PendingIntentRecord.Key key = new PendingIntentRecord.Key( + type, packageName, activity, resultWho, + requestCode, intent, resolvedType, flags); + WeakReference<PendingIntentRecord> ref; + ref = mIntentSenderRecords.get(key); + PendingIntentRecord rec = ref != null ? ref.get() : null; + if (rec != null) { + if (!cancelCurrent) { + if (updateCurrent) { + rec.key.requestIntent.replaceExtras(intent); } - rec.canceled = true; - mIntentSenderRecords.remove(key); - } - if (noCreate) { return rec; } - rec = new PendingIntentRecord(this, key, callingUid); - mIntentSenderRecords.put(key, rec.ref); - if (type == INTENT_SENDER_ACTIVITY_RESULT) { - if (activity.pendingResults == null) { - activity.pendingResults - = new HashSet<WeakReference<PendingIntentRecord>>(); - } - activity.pendingResults.add(rec.ref); - } + rec.canceled = true; + mIntentSenderRecords.remove(key); + } + if (noCreate) { return rec; } + rec = new PendingIntentRecord(this, key, callingUid); + mIntentSenderRecords.put(key, rec.ref); + if (type == INTENT_SENDER_ACTIVITY_RESULT) { + if (activity.pendingResults == null) { + activity.pendingResults + = new HashSet<WeakReference<PendingIntentRecord>>(); + } + activity.pendingResults.add(rec.ref); + } + return rec; } public void cancelIntentSender(IIntentSender sender) { @@ -6164,7 +3801,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen synchronized(this) { PendingIntentRecord rec = (PendingIntentRecord)sender; try { - int uid = ActivityThread.getPackageManager() + int uid = AppGlobals.getPackageManager() .getPackageUid(rec.key.packageName); if (uid != Binder.getCallingUid()) { String msg = "Permission Denial: cancelIntentSender() from pid=" @@ -6323,7 +3960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return PackageManager.PERMISSION_GRANTED; } try { - return ActivityThread.getPackageManager() + return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); } catch (RemoteException e) { // Should never happen, but if it does... deny! @@ -6431,8 +4068,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - private void grantUriPermissionLocked(int callingUid, - String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) { + 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); if (modeFlags == 0) { @@ -6442,7 +4079,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Requested grant " + targetPkg + " permission to " + uri); - final IPackageManager pm = ActivityThread.getPackageManager(); + final IPackageManager pm = AppGlobals.getPackageManager(); // If this is not a content: uri, we can't do anything with it. if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { @@ -6453,8 +4090,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen String name = uri.getAuthority(); ProviderInfo pi = null; - ContentProviderRecord cpr - = (ContentProviderRecord)mProvidersByName.get(name); + ContentProviderRecord cpr = mProvidersByName.get(name); if (cpr != null) { pi = cpr.info; } else { @@ -6561,8 +4197,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - private void grantUriPermissionFromIntentLocked(int callingUid, - String targetPkg, Intent intent, HistoryRecord activity) { + void grantUriPermissionFromIntentLocked(int callingUid, + String targetPkg, Intent intent, ActivityRecord activity) { if (intent == null) { return; } @@ -6597,7 +4233,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - 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 @@ -6613,29 +4249,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - private void removeActivityUriPermissionsLocked(HistoryRecord 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 @@ -6647,12 +4260,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri); - final IPackageManager pm = ActivityThread.getPackageManager(); + final IPackageManager pm = AppGlobals.getPackageManager(); final String authority = uri.getAuthority(); ProviderInfo pi = null; - ContentProviderRecord cpr - = (ContentProviderRecord)mProvidersByName.get(authority); + ContentProviderRecord cpr = mProvidersByName.get(authority); if (cpr != null) { pi = cpr.info; } else { @@ -6742,12 +4354,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return; } - final IPackageManager pm = ActivityThread.getPackageManager(); + final IPackageManager pm = AppGlobals.getPackageManager(); final String authority = uri.getAuthority(); ProviderInfo pi = null; - ContentProviderRecord cpr - = (ContentProviderRecord)mProvidersByName.get(authority); + ContentProviderRecord cpr = mProvidersByName.get(authority); if (cpr != null) { pi = cpr.info; } else { @@ -6797,7 +4408,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen PendingThumbnailsRecord pending = null; IApplicationThread topThumbnail = null; - HistoryRecord topRecord = null; + ActivityRecord topRecord = null; synchronized(this) { if (localLOGV) Slog.v( @@ -6822,18 +4433,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen throw new SecurityException(msg); } - int pos = mHistory.size()-1; - HistoryRecord next = - pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null; - HistoryRecord top = null; + int pos = mMainStack.mHistory.size()-1; + ActivityRecord next = + pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null; + ActivityRecord top = null; CharSequence topDescription = null; TaskRecord curTask = null; int numActivities = 0; int numRunning = 0; while (pos >= 0 && maxNum > 0) { - final HistoryRecord r = next; + final ActivityRecord r = next; pos--; - next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null; + next = pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null; // Initialize state for next task if needed. if (top == null || @@ -6935,7 +4546,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen enforceCallingPermission(android.Manifest.permission.GET_TASKS, "getRecentTasks()"); - IPackageManager pm = ActivityThread.getPackageManager(); + IPackageManager pm = AppGlobals.getPackageManager(); final int N = mRecentTasks.size(); ArrayList<ActivityManager.RecentTaskInfo> res @@ -6982,12 +4593,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private final int findAffinityTaskTopLocked(int startIndex, String affinity) { int j; - TaskRecord startTask = ((HistoryRecord)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--) { - HistoryRecord r = (HistoryRecord)mHistory.get(j); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j); if (r.task != jt) { jt = r.task; if (affinity.equals(jt.affinity)) { @@ -6997,10 +4608,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } // Now look forwards - final int N = mHistory.size(); + final int N = mMainStack.mHistory.size(); jt = startTask; for (j=startIndex+1; j<N; j++) { - HistoryRecord r = (HistoryRecord)mHistory.get(j); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j); if (r.task != jt) { if (affinity.equals(jt.affinity)) { return j; @@ -7010,7 +4621,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } // Might it be at the top? - if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) { + if (affinity.equals(((ActivityRecord)mMainStack.mHistory.get(N-1)).task.affinity)) { return N-1; } @@ -7018,293 +4629,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } /** - * 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 HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop, - HistoryRecord 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. - HistoryRecord target = null; - int targetI = 0; - int taskTopI = -1; - int replyChainEnd = -1; - int lastReparentPos = -1; - for (int i=mHistory.size()-1; i>=-1; i--) { - HistoryRecord below = i >= 0 ? (HistoryRecord)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. - HistoryRecord p = (HistoryRecord)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 = (HistoryRecord)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() && - ((HistoryRecord)mHistory.get( - replyChainEnd)).task == task) { - replyChainEnd++; - } - replyChainEnd--; - } else if (replyChainEnd < 0) { - replyChainEnd = targetI; - } - HistoryRecord p = null; - for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) { - p = (HistoryRecord)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; - } - HistoryRecord p = null; - for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) { - p = (HistoryRecord)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--) { - HistoryRecord p = (HistoryRecord)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--) { - HistoryRecord p = (HistoryRecord)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) { @@ -7322,14 +4646,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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--) { - HistoryRecord hr = (HistoryRecord)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; } } @@ -7339,84 +4663,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) { - if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr); - - final int task = tr.taskId; - int top = mHistory.size()-1; - - if (top < 0 || ((HistoryRecord)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) { - HistoryRecord r = (HistoryRecord)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); - HistoryRecord 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); } } @@ -7435,93 +4695,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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, HistoryRecord 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) { - HistoryRecord 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) { - HistoryRecord r = (HistoryRecord)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); - HistoryRecord 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()"); @@ -7548,10 +4728,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } 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++) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); if (r == token) { if (!onlyRoot || lastTask != r.task) { return r.task.taskId; @@ -7564,89 +4744,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return -1; } - /** - * Returns the top activity in any existing task matching the given - * Intent. Returns null if no such task is found. - */ - private HistoryRecord 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--) { - HistoryRecord r = (HistoryRecord)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 HistoryRecord 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--) { - HistoryRecord r = (HistoryRecord)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++) { - HistoryRecord r = (HistoryRecord)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--; @@ -7671,7 +4779,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Binder.restoreCallingIdentity(origId); } - final void sendPendingThumbnail(HistoryRecord r, IBinder token, + final void sendPendingThumbnail(ActivityRecord r, IBinder token, Bitmap thumbnail, CharSequence description, boolean always) { TaskRecord task = null; ArrayList receivers = null; @@ -7680,11 +4788,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen synchronized(this) { if (r == null) { - int index = indexOfTokenLocked(token); + int index = mMainStack.indexOfTokenLocked(token); if (index < 0) { return; } - r = (HistoryRecord)mHistory.get(index); + r = (ActivityRecord)mMainStack.mHistory.get(index); } if (thumbnail == null) { thumbnail = r.thumbnail; @@ -7745,7 +4853,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private final List generateApplicationProvidersLocked(ProcessRecord app) { List providers = null; try { - providers = ActivityThread.getPackageManager(). + providers = AppGlobals.getPackageManager(). queryContentProviders(app.processName, app.info.uid, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); } catch (RemoteException ex) { @@ -7755,8 +4863,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen for (int i=0; i<N; i++) { ProviderInfo cpi = (ProviderInfo)providers.get(i); - ContentProviderRecord cpr = - (ContentProviderRecord)mProvidersByClass.get(cpi.name); + ContentProviderRecord cpr = mProvidersByClass.get(cpi.name); if (cpr == null) { cpr = new ContentProviderRecord(cpi, app.info); mProvidersByClass.put(cpi.name, cpr); @@ -7831,7 +4938,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } // First check if this content provider has been published... - cpr = (ContentProviderRecord)mProvidersByName.get(name); + cpr = mProvidersByName.get(name); if (cpr != null) { cpi = cpr.info; if (checkContentProviderPermissionLocked(cpi, r, -1) != null) { @@ -7869,8 +4976,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen r.conProviders.put(cpr, new Integer(cnt.intValue()+1)); } cpr.clients.add(r); - if (cpr.app != null && r.setAdj >= VISIBLE_APP_ADJ) { - // If this is a visible app accessing the provider, + if (cpr.app != null && r.setAdj <= PERCEPTIBLE_APP_ADJ) { + // If this is a perceptible app accessing the provider, // make sure to count it as being accessed and thus // back up on the LRU list. This is good because // content providers are often expensive to start. @@ -7888,7 +4995,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else { try { - cpi = ActivityThread.getPackageManager(). + cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); } catch (RemoteException ex) { @@ -7912,12 +5019,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "Attempt to launch content provider before system ready"); } - cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name); + cpr = mProvidersByClass.get(cpi.name); final boolean firstClass = cpr == null; if (firstClass) { try { ApplicationInfo ai = - ActivityThread.getPackageManager(). + AppGlobals.getPackageManager(). getApplicationInfo( cpi.applicationInfo.packageName, STOCK_PM_FLAGS); @@ -8046,7 +5153,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen */ public void removeContentProvider(IApplicationThread caller, String name) { synchronized (this) { - ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name); + ContentProviderRecord cpr = mProvidersByName.get(name); if(cpr == null) { // remove from mProvidersByClass if (DEBUG_PROVIDER) Slog.v(TAG, name + @@ -8060,8 +5167,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen " when removing content provider " + name); } //update content provider record entry info - ContentProviderRecord localCpr = (ContentProviderRecord) - mProvidersByClass.get(cpr.info.name); + ContentProviderRecord localCpr = mProvidersByClass.get(cpr.info.name); if (DEBUG_PROVIDER) Slog.v(TAG, "Removing provider requested by " + r.info.processName + " from process " + localCpr.appInfo.processName); @@ -8085,7 +5191,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private void removeContentProviderExternal(String name) { synchronized (this) { - ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name); + ContentProviderRecord cpr = mProvidersByName.get(name); if(cpr == null) { //remove from mProvidersByClass if(localLOGV) Slog.v(TAG, name+" content provider not found in providers list"); @@ -8093,7 +5199,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } //update content provider record entry info - ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name); + ContentProviderRecord localCpr = mProvidersByClass.get(cpr.info.name); localCpr.externals--; if (localCpr.externals < 0) { Slog.e(TAG, "Externals < 0 for content provider " + localCpr); @@ -8125,8 +5231,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (src == null || src.info == null || src.provider == null) { continue; } - ContentProviderRecord dst = - (ContentProviderRecord)r.pubProviders.get(src.info.name); + ContentProviderRecord dst = r.pubProviders.get(src.info.name); if (dst != null) { mProvidersByClass.put(dst.info.name, dst); String names[] = dst.info.authority.split(";"); @@ -8219,12 +5324,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "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((HistoryRecord)mHistory.get(count-1), + mMainStack.finishActivityLocked((ActivityRecord)mMainStack.mHistory.get(count-1), count-1, Activity.RESULT_CANCELED, null, "unhandled-back"); Binder.restoreCallingIdentity(origId); } @@ -8267,8 +5372,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mSleeping = true; mWindowManager.setEventDispatching(false); - if (mResumedActivity != null) { - pauseIfSleepingLocked(); + if (mMainStack.mResumedActivity != null) { + mMainStack.pauseIfSleepingLocked(); } else { Slog.w(TAG, "goingToSleep with no resumed activity!"); } @@ -8288,10 +5393,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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"); @@ -8312,35 +5418,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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); } } @@ -8468,13 +5553,42 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + public void setImmersive(IBinder token, boolean immersive) { + synchronized(this) { + int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1; + if (index < 0) { + throw new IllegalArgumentException(); + } + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); + r.immersive = immersive; + } + } + + public boolean isImmersive(IBinder token) { + synchronized (this) { + int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1; + if (index < 0) { + throw new IllegalArgumentException(); + } + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); + return r.immersive; + } + } + + public boolean isTopActivityImmersive() { + synchronized (this) { + ActivityRecord r = mMainStack.topRunningActivityLocked(null); + return (r != null) ? r.immersive : false; + } + } + public final void enterSafeMode() { synchronized(this) { // It only makes sense to do this before the system is ready // and started launching other packages. if (!mSystemReady) { try { - ActivityThread.getPackageManager().enterSafeMode(); + AppGlobals.getPackageManager().enterSafeMode(); } catch (RemoteException e) { } @@ -8560,123 +5674,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return killed; } - public void reportPss(IApplicationThread caller, int pss) { - Watchdog.PssRequestor req; - String name; - ProcessRecord callerApp; - synchronized (this) { - if (caller == null) { - return; - } - callerApp = getRecordForAppLocked(caller); - if (callerApp == null) { - return; - } - callerApp.lastPss = pss; - req = callerApp; - name = callerApp.processName; - } - Watchdog.getInstance().reportPss(req, name, pss); - if (!callerApp.persistent) { - removeRequestedPss(callerApp); - } - } - - public void requestPss(Runnable completeCallback) { - ArrayList<ProcessRecord> procs; - synchronized (this) { - mRequestPssCallback = completeCallback; - mRequestPssList.clear(); - for (int i=mLruProcesses.size()-1; i>=0; i--) { - ProcessRecord proc = mLruProcesses.get(i); - if (!proc.persistent) { - mRequestPssList.add(proc); - } - } - procs = new ArrayList<ProcessRecord>(mRequestPssList); - } - - int oldPri = Process.getThreadPriority(Process.myTid()); - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - for (int i=procs.size()-1; i>=0; i--) { - ProcessRecord proc = procs.get(i); - proc.lastPss = 0; - proc.requestPss(); - } - Process.setThreadPriority(oldPri); - } - - void removeRequestedPss(ProcessRecord proc) { - Runnable callback = null; - synchronized (this) { - if (mRequestPssList.remove(proc)) { - if (mRequestPssList.size() == 0) { - callback = mRequestPssCallback; - mRequestPssCallback = null; - } - } - } - - if (callback != null) { - callback.run(); - } - } - - public void collectPss(Watchdog.PssStats stats) { - stats.mEmptyPss = 0; - stats.mEmptyCount = 0; - stats.mBackgroundPss = 0; - stats.mBackgroundCount = 0; - stats.mServicePss = 0; - stats.mServiceCount = 0; - stats.mVisiblePss = 0; - stats.mVisibleCount = 0; - stats.mForegroundPss = 0; - stats.mForegroundCount = 0; - stats.mNoPssCount = 0; - synchronized (this) { - int i; - int NPD = mProcDeaths.length < stats.mProcDeaths.length - ? mProcDeaths.length : stats.mProcDeaths.length; - int aggr = 0; - for (i=0; i<NPD; i++) { - aggr += mProcDeaths[i]; - stats.mProcDeaths[i] = aggr; - } - while (i<stats.mProcDeaths.length) { - stats.mProcDeaths[i] = 0; - i++; - } - - for (i=mLruProcesses.size()-1; i>=0; i--) { - ProcessRecord proc = mLruProcesses.get(i); - if (proc.persistent) { - continue; - } - //Slog.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss); - if (proc.lastPss == 0) { - stats.mNoPssCount++; - continue; - } - if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) { - if (proc.empty) { - stats.mEmptyPss += proc.lastPss; - stats.mEmptyCount++; - } else { - stats.mBackgroundPss += proc.lastPss; - stats.mBackgroundCount++; - } - } else if (proc.setAdj >= VISIBLE_APP_ADJ) { - stats.mVisiblePss += proc.lastPss; - stats.mVisibleCount++; - } else { - stats.mForegroundPss += proc.lastPss; - stats.mForegroundCount++; - } - } - } - } - public final void startRunning(String pkg, String cls, String action, String data) { synchronized(this) { @@ -8747,7 +5744,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); List<ResolveInfo> ris = null; try { - ris = ActivityThread.getPackageManager().queryIntentReceivers( + ris = AppGlobals.getPackageManager().queryIntentReceivers( intent, null, 0); } catch (RemoteException e) { } @@ -8866,7 +5863,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen synchronized (this) { if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try { - List apps = ActivityThread.getPackageManager(). + List apps = AppGlobals.getPackageManager(). getPersistentApplications(STOCK_PM_FLAGS); if (apps != null) { int N = apps.size(); @@ -8889,7 +5886,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mBooting = true; try { - if (ActivityThread.getPackageManager().hasSystemUidErrors()) { + if (AppGlobals.getPackageManager().hasSystemUidErrors()) { Message msg = Message.obtain(); msg.what = SHOW_UID_ERROR_MSG; mHandler.sendMessage(msg); @@ -8897,7 +5894,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } catch (RemoteException e) { } - resumeTopActivityLocked(null); + mMainStack.resumeTopActivityLocked(null); } } @@ -8985,12 +5982,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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--) { - HistoryRecord r = (HistoryRecord)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) { @@ -9008,28 +6005,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return false; } } else { - HistoryRecord 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 = (HistoryRecord)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"); } } @@ -9041,9 +6038,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (app.services.size() != 0) { // Any services running in the application need to be placed // back in the pending list. - Iterator it = app.services.iterator(); + Iterator<ServiceRecord> it = app.services.iterator(); while (it.hasNext()) { - ServiceRecord sr = (ServiceRecord)it.next(); + ServiceRecord sr = it.next(); sr.crashCount++; } } @@ -9127,6 +6124,161 @@ public final class ActivityManagerService extends ActivityManagerNative implemen crashApplication(r, crashInfo); } + public void handleApplicationStrictModeViolation( + IBinder app, + int violationMask, + StrictMode.ViolationInfo info) { + ProcessRecord r = findAppProcess(app); + + if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) { + Integer stackFingerprint = info.crashInfo.stackTrace.hashCode(); + boolean logIt = true; + synchronized (mAlreadyLoggedViolatedStacks) { + if (mAlreadyLoggedViolatedStacks.contains(stackFingerprint)) { + logIt = false; + // TODO: sub-sample into EventLog for these, with + // the info.durationMillis? Then we'd get + // the relative pain numbers, without logging all + // the stack traces repeatedly. We'd want to do + // likewise in the client code, which also does + // dup suppression, before the Binder call. + } else { + if (mAlreadyLoggedViolatedStacks.size() >= MAX_DUP_SUPPRESSED_STACKS) { + mAlreadyLoggedViolatedStacks.clear(); + } + mAlreadyLoggedViolatedStacks.add(stackFingerprint); + } + } + if (logIt) { + logStrictModeViolationToDropBox(r, info); + } + } + + if ((violationMask & StrictMode.PENALTY_DIALOG) != 0) { + AppErrorResult result = new AppErrorResult(); + synchronized (this) { + final long origId = Binder.clearCallingIdentity(); + + Message msg = Message.obtain(); + msg.what = SHOW_STRICT_MODE_VIOLATION_MSG; + HashMap<String, Object> data = new HashMap<String, Object>(); + data.put("result", result); + data.put("app", r); + data.put("violationMask", violationMask); + data.put("info", info); + msg.obj = data; + mHandler.sendMessage(msg); + + Binder.restoreCallingIdentity(origId); + } + int res = result.get(); + Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res); + } + } + + // Depending on the policy in effect, there could be a bunch of + // these in quick succession so we try to batch these together to + // minimize disk writes, number of dropbox entries, and maximize + // compression, by having more fewer, larger records. + private void logStrictModeViolationToDropBox( + ProcessRecord process, + StrictMode.ViolationInfo info) { + if (info == null) { + return; + } + final boolean isSystemApp = process == null || + (process.info.flags & (ApplicationInfo.FLAG_SYSTEM | + ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0; + final String dropboxTag = isSystemApp ? "system_app_strictmode" : "data_app_strictmode"; + final DropBoxManager dbox = (DropBoxManager) + mContext.getSystemService(Context.DROPBOX_SERVICE); + + // Exit early if the dropbox isn't configured to accept this report type. + if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return; + + boolean bufferWasEmpty; + boolean needsFlush; + final StringBuilder sb = isSystemApp ? mStrictModeBuffer : new StringBuilder(1024); + synchronized (sb) { + bufferWasEmpty = sb.length() == 0; + appendDropBoxProcessHeaders(process, sb); + sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); + sb.append("System-App: ").append(isSystemApp).append("\n"); + sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n"); + if (info.violationNumThisLoop != 0) { + sb.append("Loop-Violation-Number: ").append(info.violationNumThisLoop).append("\n"); + } + if (info != null && info.durationMillis != -1) { + sb.append("Duration-Millis: ").append(info.durationMillis).append("\n"); + } + sb.append("\n"); + if (info.crashInfo != null && info.crashInfo.stackTrace != null) { + sb.append(info.crashInfo.stackTrace); + } + sb.append("\n"); + + // Only buffer up to ~64k. Various logging bits truncate + // things at 128k. + needsFlush = (sb.length() > 64 * 1024); + } + + // Flush immediately if the buffer's grown too large, or this + // is a non-system app. Non-system apps are isolated with a + // different tag & policy and not batched. + // + // Batching is useful during internal testing with + // StrictMode settings turned up high. Without batching, + // thousands of separate files could be created on boot. + if (!isSystemApp || needsFlush) { + new Thread("Error dump: " + dropboxTag) { + @Override + public void run() { + String report; + synchronized (sb) { + report = sb.toString(); + sb.delete(0, sb.length()); + sb.trimToSize(); + } + if (report.length() != 0) { + dbox.addText(dropboxTag, report); + } + } + }.start(); + return; + } + + // System app batching: + if (!bufferWasEmpty) { + // An existing dropbox-writing thread is outstanding, so + // we don't need to start it up. The existing thread will + // catch the buffer appends we just did. + return; + } + + // Worker thread to both batch writes and to avoid blocking the caller on I/O. + // (After this point, we shouldn't access AMS internal data structures.) + new Thread("Error dump: " + dropboxTag) { + @Override + public void run() { + // 5 second sleep to let stacks arrive and be batched together + try { + Thread.sleep(5000); // 5 seconds + } catch (InterruptedException e) {} + + String errorReport; + synchronized (mStrictModeBuffer) { + errorReport = mStrictModeBuffer.toString(); + if (errorReport.length() == 0) { + return; + } + mStrictModeBuffer.delete(0, mStrictModeBuffer.length()); + mStrictModeBuffer.trimToSize(); + } + dbox.addText(dropboxTag, errorReport); + } + }.start(); + } + /** * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors. * @param app object of the crashing app, null for the system server @@ -9180,40 +6332,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } /** - * Write a description of an error (crash, WTF, ANR) to the drop box. - * @param eventType to include in the drop box tag ("crash", "wtf", etc.) - * @param process which caused the error, null means the system server - * @param activity which triggered the error, null if unknown - * @param parent activity related to the error, null if unknown - * @param subject line related to the error, null if absent - * @param report in long form describing the error, null if absent - * @param logFile to include in the report, null if none - * @param crashInfo giving an application stack trace, null if absent + * Utility function for addErrorToDropBox and handleStrictModeViolation's logging + * to append various headers to the dropbox log text. */ - public void addErrorToDropBox(String eventType, - ProcessRecord process, HistoryRecord activity, HistoryRecord parent, String subject, - final String report, final File logFile, - final ApplicationErrorReport.CrashInfo crashInfo) { - // NOTE -- this must never acquire the ActivityManagerService lock, - // otherwise the watchdog may be prevented from resetting the system. - - String prefix; - if (process == null || process.pid == MY_PID) { - prefix = "system_server_"; - } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - prefix = "system_app_"; - } else { - prefix = "data_app_"; - } - - final String dropboxTag = prefix + eventType; - final DropBoxManager dbox = (DropBoxManager) - mContext.getSystemService(Context.DROPBOX_SERVICE); - - // Exit early if the dropbox isn't configured to accept this report type. - if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return; - - final StringBuilder sb = new StringBuilder(1024); + private static void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) { if (process == null || process.pid == MY_PID) { sb.append("Process: system_server\n"); } else { @@ -9221,7 +6343,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } if (process != null) { int flags = process.info.flags; - IPackageManager pm = ActivityThread.getPackageManager(); + IPackageManager pm = AppGlobals.getPackageManager(); sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n"); for (String pkg : process.pkgList) { sb.append("Package: ").append(pkg); @@ -9239,6 +6361,45 @@ public final class ActivityManagerService extends ActivityManagerNative implemen sb.append("\n"); } } + } + + private static String processClass(ProcessRecord process) { + if (process == null || process.pid == MY_PID) { + return "system_server"; + } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + return "system_app"; + } else { + return "data_app"; + } + } + + /** + * Write a description of an error (crash, WTF, ANR) to the drop box. + * @param eventType to include in the drop box tag ("crash", "wtf", etc.) + * @param process which caused the error, null means the system server + * @param activity which triggered the error, null if unknown + * @param parent activity related to the error, null if unknown + * @param subject line related to the error, null if absent + * @param report in long form describing the error, null if absent + * @param logFile to include in the report, null if none + * @param crashInfo giving an application stack trace, null if absent + */ + public void addErrorToDropBox(String eventType, + ProcessRecord process, ActivityRecord activity, ActivityRecord parent, String subject, + final String report, final File logFile, + final ApplicationErrorReport.CrashInfo crashInfo) { + // NOTE -- this must never acquire the ActivityManagerService lock, + // otherwise the watchdog may be prevented from resetting the system. + + final String dropboxTag = processClass(process) + "_" + eventType; + final DropBoxManager dbox = (DropBoxManager) + mContext.getSystemService(Context.DROPBOX_SERVICE); + + // Exit early if the dropbox isn't configured to accept this report type. + if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return; + + final StringBuilder sb = new StringBuilder(1024); + appendDropBoxProcessHeaders(process, sb); if (activity != null) { sb.append("Activity: ").append(activity.shortComponentName).append("\n"); } @@ -9496,6 +6657,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen new ActivityManager.RunningAppProcessInfo(app.processName, app.pid, app.getPackageList()); currApp.uid = app.info.uid; + if (mHeavyWeightProcess == app) { + currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HEAVY_WEIGHT; + } int adj = app.curAdj; if (adj >= EMPTY_APP_ADJ) { currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY; @@ -9507,6 +6671,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen currApp.lru = 0; } else if (adj >= SECONDARY_SERVER_ADJ) { currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; + } else if (adj >= HEAVY_WEIGHT_APP_ADJ) { + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_HEAVY_WEIGHT; + } else if (adj >= PERCEPTIBLE_APP_ADJ) { + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE; } else if (adj >= VISIBLE_APP_ADJ) { currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; } else { @@ -9515,8 +6683,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen currApp.importanceReasonCode = app.adjTypeCode; if (app.adjSource instanceof ProcessRecord) { currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid; - } else if (app.adjSource instanceof HistoryRecord) { - HistoryRecord r = (HistoryRecord)app.adjSource; + } else if (app.adjSource instanceof ActivityRecord) { + ActivityRecord r = (ActivityRecord)app.adjSource; if (r.app != null) currApp.importanceReasonPid = r.app.pid; } if (app.adjTarget instanceof ComponentName) { @@ -9546,7 +6714,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } } - IPackageManager pm = ActivityThread.getPackageManager(); + IPackageManager pm = AppGlobals.getPackageManager(); for (String pkg : extList) { try { ApplicationInfo info = pm.getApplicationInfo(pkg, 0); @@ -9630,7 +6798,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } return; } else if ("service".equals(cmd)) { - dumpService(fd, pw, args, opti, true); + dumpService(fd, pw, args, opti, dumpAll); return; } else if ("services".equals(cmd) || "s".equals(cmd)) { synchronized (this) { @@ -9695,31 +6863,31 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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(" "); @@ -9770,7 +6938,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen needSep = true; pw.println(" Running processes (most recent first):"); dumpProcessList(pw, this, mLruProcesses, " ", - "App ", "PERS", true); + "Proc", "PERS", true); needSep = true; } @@ -9884,8 +7052,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen pw.println(" "); pw.println(" mHomeProcess: " + mHomeProcess); + if (mHeavyWeightProcess != null) { + 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) { @@ -9904,8 +7075,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen + " 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); } @@ -9933,20 +7104,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen componentNameString = args[opti]; opti++; ComponentName componentName = ComponentName.unflattenFromString(componentNameString); - r = componentName != null ? mServices.get(componentName) : null; + synchronized (this) { + r = componentName != null ? mServices.get(componentName) : null; + } newArgs = new String[args.length - opti]; if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); } if (r != null) { - dumpService(fd, pw, r, newArgs); + dumpService(fd, pw, r, newArgs, dumpAll); } else { - for (ServiceRecord r1 : mServices.values()) { - if (componentNameString == null - || r1.name.flattenToString().contains(componentNameString)) { - dumpService(fd, pw, r1, newArgs); + ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); + synchronized (this) { + for (ServiceRecord r1 : mServices.values()) { + if (componentNameString == null + || r1.name.flattenToString().contains(componentNameString)) { + services.add(r1); + } } } + for (int i=0; i<services.size(); i++) { + dumpService(fd, pw, services.get(i), newArgs, dumpAll); + } } } @@ -9954,8 +7133,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * Invokes IApplicationThread.dumpService() on the thread of the specified service if * there is a thread associated with the service. */ - private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) { + private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args, + boolean dumpAll) { pw.println(" Service " + r.name.flattenToString()); + if (dumpAll) { + synchronized (this) { + pw.print(" * "); pw.println(r); + r.dump(pw, " "); + } + pw.println(""); + } if (r.app != null && r.app.thread != null) { try { // flush anything that is already in the PrintWriter since the thread is going @@ -9963,6 +7150,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen pw.flush(); r.app.thread.dumpService(fd, r, args); pw.print("\n"); + pw.flush(); } catch (RemoteException e) { pw.println("got a RemoteException while dumping the service"); } @@ -10145,10 +7333,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (mProvidersByClass.size() > 0) { if (needSep) pw.println(" "); pw.println(" Published content providers (by class):"); - Iterator it = mProvidersByClass.entrySet().iterator(); + Iterator<Map.Entry<String, ContentProviderRecord>> it + = mProvidersByClass.entrySet().iterator(); while (it.hasNext()) { - Map.Entry e = (Map.Entry)it.next(); - ContentProviderRecord r = (ContentProviderRecord)e.getValue(); + Map.Entry<String, ContentProviderRecord> e = it.next(); + ContentProviderRecord r = e.getValue(); pw.print(" * "); pw.println(r); r.dump(pw, " "); } @@ -10158,10 +7347,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (mProvidersByName.size() > 0) { pw.println(" "); pw.println(" Authority to provider mappings:"); - Iterator it = mProvidersByName.entrySet().iterator(); + Iterator<Map.Entry<String, ContentProviderRecord>> it + = mProvidersByName.entrySet().iterator(); while (it.hasNext()) { - Map.Entry e = (Map.Entry)it.next(); - ContentProviderRecord r = (ContentProviderRecord)e.getValue(); + Map.Entry<String, ContentProviderRecord> e = it.next(); + ContentProviderRecord r = e.getValue(); pw.print(" "); pw.print(e.getKey()); pw.print(": "); pw.println(r); } @@ -10228,7 +7418,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen String prefix, String label, boolean complete) { TaskRecord lastTask = null; for (int i=list.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)list.get(i); + ActivityRecord r = (ActivityRecord)list.get(i); final boolean full = complete || !r.inHistory; if (lastTask != r.task) { lastTask = r.task; @@ -10261,7 +7451,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen String prefix, String normalLabel, String persistentLabel, boolean inclOomAdj) { int numPers = 0; - for (int i=list.size()-1; i>=0; i--) { + final int N = list.size()-1; + for (int i=N; i>=0; i--) { ProcessRecord r = (ProcessRecord)list.get(i); if (false) { pw.println(prefix + (r.persistent ? persistentLabel : normalLabel) @@ -10279,6 +7470,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ); } else if (r.setAdj >= BACKUP_APP_ADJ) { oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ); + } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) { + oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ); + } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) { + oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ); } else if (r.setAdj >= VISIBLE_APP_ADJ) { oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ); } else if (r.setAdj >= FOREGROUND_APP_ADJ) { @@ -10304,10 +7499,27 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)", prefix, (r.persistent ? persistentLabel : normalLabel), - i, oomAdj, schedGroup, r.toShortString(), r.adjType)); + N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); if (r.adjSource != null || r.adjTarget != null) { - pw.println(prefix + " " + r.adjTarget - + "<=" + r.adjSource); + pw.print(prefix); + pw.print(" "); + if (r.adjTarget instanceof ComponentName) { + pw.print(((ComponentName)r.adjTarget).flattenToShortString()); + } else if (r.adjTarget != null) { + pw.print(r.adjTarget.toString()); + } else { + pw.print("{null}"); + } + pw.print("<="); + if (r.adjSource instanceof ProcessRecord) { + pw.print("Proc{"); + pw.print(((ProcessRecord)r.adjSource).toShortString()); + pw.println("}"); + } else if (r.adjSource != null) { + pw.println(r.adjSource.toString()); + } else { + pw.println("{null}"); + } } } else { pw.println(String.format("%s%s #%2d: %s", @@ -10371,22 +7583,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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. @@ -10394,9 +7590,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // XXX we are letting the client link to the service for // death notifications. if (app.services.size() > 0) { - Iterator it = app.services.iterator(); + Iterator<ServiceRecord> it = app.services.iterator(); while (it.hasNext()) { - ServiceRecord r = (ServiceRecord)it.next(); + ServiceRecord r = it.next(); if (r.connections.size() > 0) { Iterator<ConnectionRecord> jt = r.connections.values().iterator(); @@ -10431,9 +7627,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (app.services.size() != 0) { // Any services running in the application need to be placed // back in the pending list. - Iterator it = app.services.iterator(); + Iterator<ServiceRecord> it = app.services.iterator(); while (it.hasNext()) { - ServiceRecord sr = (ServiceRecord)it.next(); + ServiceRecord sr = it.next(); synchronized (sr.stats.getBatteryStats()) { sr.stats.stopLaunchedLocked(); } @@ -10572,9 +7768,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Remove published content providers. if (!app.pubProviders.isEmpty()) { - Iterator it = app.pubProviders.values().iterator(); + Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator(); while (it.hasNext()) { - ContentProviderRecord cpr = (ContentProviderRecord)it.next(); + ContentProviderRecord cpr = it.next(); cpr.provider = null; cpr.app = null; @@ -10666,6 +7862,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (DEBUG_PROCESSES) Slog.v(TAG, "Removing non-persistent process during cleanup: " + app); mProcessNames.remove(app.processName, app.info.uid); + if (mHeavyWeightProcess == app) { + mHeavyWeightProcess = null; + mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG); + } } else if (!app.removed) { // This app is persistent, so we need to keep its record around. // If it is not already on the pending app list, add it there @@ -10707,8 +7907,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int NL = mLaunchingProviders.size(); boolean restart = false; for (int i=0; i<NL; i++) { - ContentProviderRecord cpr = (ContentProviderRecord) - mLaunchingProviders.get(i); + ContentProviderRecord cpr = mLaunchingProviders.get(i); if (cpr.launchingApp == app) { if (!alwaysBad && !app.bad) { restart = true; @@ -10831,7 +8030,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (r == null) { try { ResolveInfo rInfo = - ActivityThread.getPackageManager().resolveService( + AppGlobals.getPackageManager().resolveService( service, resolvedType, 0); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; @@ -10888,7 +8087,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (r == null) { try { ResolveInfo rInfo = - ActivityThread.getPackageManager().resolveService( + AppGlobals.getPackageManager().resolveService( service, resolvedType, STOCK_PM_FLAGS); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; @@ -11625,7 +8824,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) { boolean anyForeground = false; - for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) { + for (ServiceRecord sr : proc.services) { if (sr.isForeground) { anyForeground = true; break; @@ -11659,14 +8858,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen + ") when binding service " + service); } - HistoryRecord activity = null; + 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 = (HistoryRecord)mHistory.get(aindex); + activity = (ActivityRecord)mMainStack.mHistory.get(aindex); } int clientLabel = 0; @@ -11770,8 +8969,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return 1; } - private void removeConnectionLocked( - ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) { + void removeConnectionLocked( + ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) { IBinder binder = c.conn.asBinder(); AppBindRecord b = c.binding; ServiceRecord s = b.service; @@ -12452,7 +9651,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Always okay. } else if (callerApp == null || !callerApp.persistent) { try { - if (ActivityThread.getPackageManager().isProtectedBroadcast( + if (AppGlobals.getPackageManager().isProtectedBroadcast( intent.getAction())) { String msg = "Permission Denial: not allowed to send broadcast " + intent.getAction() + " from pid=" @@ -12511,7 +9710,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen try { if (intent.getComponent() != null) { // Broadcast is going to one specific receiver class... - ActivityInfo ai = ActivityThread.getPackageManager(). + ActivityInfo ai = AppGlobals.getPackageManager(). getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS); if (ai != null) { receivers = new ArrayList(); @@ -12524,7 +9723,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = - ActivityThread.getPackageManager().queryIntentReceivers( + AppGlobals.getPackageManager().queryIntentReceivers( intent, resolvedType, STOCK_PM_FLAGS); } registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); @@ -13276,7 +10475,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (r.callingUid != Process.SYSTEM_UID && r.requiredPermission != null) { try { - perm = ActivityThread.getPackageManager(). + perm = AppGlobals.getPackageManager(). checkPermission(r.requiredPermission, info.activityInfo.applicationInfo.packageName); } catch (RemoteException e) { @@ -13533,7 +10732,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * configuration. */ public boolean updateConfigurationLocked(Configuration values, - HistoryRecord starting) { + ActivityRecord starting) { int changes = 0; boolean kept = true; @@ -13602,18 +10801,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // 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); } } @@ -13623,160 +10822,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return kept; } - - private final boolean relaunchActivityLocked(HistoryRecord 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(HistoryRecord 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. @@ -13868,15 +10913,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen app.adjType = "exec-service"; } else if (app.foregroundServices) { // The user is aware of this app, so make it visible. - adj = VISIBLE_APP_ADJ; + adj = PERCEPTIBLE_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "foreground-service"; } else if (app.forcingToForeground != null) { // The user is aware of this app, so make it visible. - adj = VISIBLE_APP_ADJ; + adj = PERCEPTIBLE_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "force-foreground"; app.adjSource = app.forcingToForeground; + } else if (app == mHeavyWeightProcess) { + // We don't want to kill the current heavy-weight process. + adj = HEAVY_WEIGHT_APP_ADJ; + schedGroup = Process.THREAD_GROUP_DEFAULT; + app.adjType = "heavy"; } else if (app == mHomeProcess) { // This process is hosting what we currently consider to be the // home app, so we don't want to let it go into the background. @@ -13891,7 +10941,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen app.adjType = "bg-activities"; N = app.activities.size(); for (int j=0; j<N; j++) { - if (((HistoryRecord)app.activities.get(j)).visible) { + if (app.activities.get(j).visible) { // This app has a visible activity! app.hidden = false; adj = VISIBLE_APP_ADJ; @@ -13934,9 +10984,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen final long now = SystemClock.uptimeMillis(); // This process is more important if the top activity is // bound to the service. - Iterator jt = app.services.iterator(); + Iterator<ServiceRecord> jt = app.services.iterator(); while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) { - ServiceRecord s = (ServiceRecord)jt.next(); + ServiceRecord s = jt.next(); if (s.startRequested) { if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) { // This service has seen some activity within @@ -13971,7 +11021,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ProcessRecord client = cr.binding.client; int myHiddenAdj = hiddenAdj; if (myHiddenAdj > client.hiddenAdj) { - if (client.hiddenAdj > VISIBLE_APP_ADJ) { + if (client.hiddenAdj >= VISIBLE_APP_ADJ) { myHiddenAdj = client.hiddenAdj; } else { myHiddenAdj = VISIBLE_APP_ADJ; @@ -13980,7 +11030,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int clientAdj = computeOomAdjLocked( client, myHiddenAdj, TOP_APP, true); if (adj > clientAdj) { - adj = clientAdj > VISIBLE_APP_ADJ + adj = clientAdj >= VISIBLE_APP_ADJ ? clientAdj : VISIBLE_APP_ADJ; if (!client.hidden) { app.hidden = false; @@ -13989,7 +11039,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; app.adjSource = cr.binding.client; - app.adjTarget = s.serviceInfo.name; + app.adjTarget = s.name; } if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) { @@ -13997,7 +11047,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } } - HistoryRecord a = cr.activity; + ActivityRecord a = cr.activity; //if (a != null) { // Slog.i(TAG, "Connection to " + a ": state=" + a.state); //} @@ -14011,7 +11061,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; app.adjSource = a; - app.adjTarget = s.serviceInfo.name; + app.adjTarget = s.name; } } } @@ -14031,10 +11081,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { - Iterator jt = app.pubProviders.values().iterator(); + Iterator<ContentProviderRecord> jt = app.pubProviders.values().iterator(); while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { - ContentProviderRecord cpr = (ContentProviderRecord)jt.next(); + ContentProviderRecord cpr = jt.next(); if (cpr.clients.size() != 0) { Iterator<ProcessRecord> kt = cpr.clients.iterator(); while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) { @@ -14063,7 +11113,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; app.adjSource = client; - app.adjTarget = cpr.info.name; + app.adjTarget = cpr.name; } if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) { schedGroup = Process.THREAD_GROUP_DEFAULT; @@ -14079,7 +11129,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen schedGroup = Process.THREAD_GROUP_DEFAULT; app.hidden = false; app.adjType = "provider"; - app.adjTarget = cpr.info.name; + app.adjTarget = cpr.name; } } } @@ -14091,7 +11141,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj); if (adj > app.maxAdj) { adj = app.maxAdj; - if (app.maxAdj <= VISIBLE_APP_ADJ) { + if (app.maxAdj <= PERCEPTIBLE_APP_ADJ) { schedGroup = Process.THREAD_GROUP_DEFAULT; } } @@ -14127,8 +11177,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private final boolean canGcNowLocked() { return mParallelBroadcasts.size() == 0 && mOrderedBroadcasts.size() == 0 - && (mSleeping || (mResumedActivity != null && - mResumedActivity.idle)); + && (mSleeping || (mMainStack.mResumedActivity != null && + mMainStack.mResumedActivity.idle)); } /** @@ -14143,7 +11193,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (canGcNowLocked()) { while (mProcessesToGc.size() > 0) { ProcessRecord proc = mProcessesToGc.remove(0); - if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) { + if (proc.curRawAdj > PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) { if ((proc.lastRequestedGc+GC_MIN_INTERVAL) <= SystemClock.uptimeMillis()) { // To avoid spamming the system, we will GC processes one @@ -14298,19 +11348,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return true; } - private final HistoryRecord resumedAppLocked() { - HistoryRecord resumedActivity = mResumedActivity; + private final ActivityRecord resumedAppLocked() { + 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; } private final boolean updateOomAdjLocked(ProcessRecord app) { - final HistoryRecord TOP_ACT = resumedAppLocked(); + final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; int curAdj = app.curAdj; final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ @@ -14331,9 +11381,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return res; } - private final boolean updateOomAdjLocked() { + final boolean updateOomAdjLocked() { boolean didOomAdj = true; - final HistoryRecord TOP_ACT = resumedAppLocked(); + final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; if (false) { @@ -14395,7 +11445,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj; } - private final void trimApplications() { + final void trimApplications() { synchronized (this) { int i; @@ -14515,7 +11565,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (Config.LOGV) Slog.v( TAG, "Looking to quit " + app.processName); for (j=0; j<NUMA && canQuit; j++) { - HistoryRecord r = (HistoryRecord)app.activities.get(j); + ActivityRecord r = app.activities.get(j); if (Config.LOGV) Slog.v( TAG, " " + r.intent.getComponent().flattenToShortString() + ": frozen=" + r.haveState + ", visible=" + r.visible); @@ -14525,9 +11575,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (canQuit) { // Finish all of the activities, and then the app itself. for (j=0; j<NUMA; j++) { - HistoryRecord r = (HistoryRecord)app.activities.get(j); + ActivityRecord r = app.activities.get(j); if (!r.finishing) { - destroyActivityLocked(r, false); + r.stack.destroyActivityLocked(r, false); } r.resultTo = null; } @@ -14564,25 +11614,25 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // 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 HistoryRecord r - = (HistoryRecord)mLRUActivities.get(i); + final ActivityRecord r + = (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--; } } |