diff options
Diffstat (limited to 'com/android/server/am')
23 files changed, 2035 insertions, 1570 deletions
diff --git a/com/android/server/am/ActivityDisplay.java b/com/android/server/am/ActivityDisplay.java index 8bcbfbef..6ed05552 100644 --- a/com/android/server/am/ActivityDisplay.java +++ b/com/android/server/am/ActivityDisplay.java @@ -16,9 +16,7 @@ package com.android.server.am; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.getStackIdForWindowingMode; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; @@ -48,13 +46,14 @@ import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.ConfigurationContainer; +import java.io.PrintWriter; import java.util.ArrayList; /** * Exactly one of these classes per Display in the system. Capable of holding zero or more * attached {@link ActivityStack}s. */ -class ActivityDisplay extends ConfigurationContainer { +class ActivityDisplay extends ConfigurationContainer<ActivityStack> { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM; private static final String TAG_STACK = TAG + POSTFIX_STACK; @@ -68,7 +67,7 @@ class ActivityDisplay extends ConfigurationContainer { /** All of the stacks on this display. Order matters, topmost stack is in front of all other * stacks, bottommost behind. Accessed directly by ActivityManager package classes */ - final ArrayList<ActivityStack> mStacks = new ArrayList<>(); + private final ArrayList<ActivityStack> mStacks = new ArrayList<>(); /** Array of all UIDs that are present on the display. */ private IntArray mDisplayAccessUIDs = new IntArray(); @@ -80,6 +79,13 @@ class ActivityDisplay extends ConfigurationContainer { private boolean mSleeping; + // Cached reference to some special stacks we tend to get a lot so we don't need to loop + // through the list to find them. + private ActivityStack mHomeStack = null; + private ActivityStack mRecentsStack = null; + private ActivityStack mPinnedStack = null; + private ActivityStack mSplitScreenPrimaryStack = null; + ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) { mSupervisor = supervisor; mDisplayId = displayId; @@ -98,6 +104,7 @@ class ActivityDisplay extends ConfigurationContainer { } if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack + " to displayId=" + mDisplayId + " position=" + position); + addStackReferenceIfNeeded(stack); positionChildAt(stack, position); mSupervisor.mService.updateSleepIfNeededLocked(); } @@ -106,6 +113,7 @@ class ActivityDisplay extends ConfigurationContainer { if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack + " from displayId=" + mDisplayId); mStacks.remove(stack); + removeStackReferenceIfNeeded(stack); mSupervisor.mService.updateSleepIfNeededLocked(); } @@ -150,6 +158,16 @@ class ActivityDisplay extends ConfigurationContainer { * @see ConfigurationContainer#isCompatible(int, int) */ <T extends ActivityStack> T getStack(int windowingMode, int activityType) { + if (activityType == ACTIVITY_TYPE_HOME) { + return (T) mHomeStack; + } else if (activityType == ACTIVITY_TYPE_RECENTS) { + return (T) mRecentsStack; + } + if (windowingMode == WINDOWING_MODE_PINNED) { + return (T) mPinnedStack; + } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + return (T) mSplitScreenPrimaryStack; + } for (int i = mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = mStacks.get(i); // TODO: Should undefined windowing and activity type be compatible with standard type? @@ -213,10 +231,14 @@ class ActivityDisplay extends ConfigurationContainer { if (windowingMode == WINDOWING_MODE_UNDEFINED) { // TODO: Should be okay to have stacks with with undefined windowing mode long term, but // have to set them to something for now due to logic that depending on them. - windowingMode = WINDOWING_MODE_FULLSCREEN; + windowingMode = getWindowingMode(); // Put in current display's windowing mode + if (windowingMode == WINDOWING_MODE_UNDEFINED) { + // Else fullscreen for now... + windowingMode = WINDOWING_MODE_FULLSCREEN; + } } - final boolean inSplitScreenMode = hasSplitScreenStack(); + final boolean inSplitScreenMode = hasSplitScreenPrimaryStack(); if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { // Switch to fullscreen windowing mode if we are not in split-screen mode and we are @@ -228,24 +250,7 @@ class ActivityDisplay extends ConfigurationContainer { windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; } - int stackId = INVALID_STACK_ID; - if (mDisplayId == DEFAULT_DISPLAY && (activityType == ACTIVITY_TYPE_STANDARD - || activityType == ACTIVITY_TYPE_UNDEFINED)) { - // TODO: Will be removed once we are no longer using static stack ids. - stackId = getStackIdForWindowingMode(windowingMode); - if (stackId == INVALID_STACK_ID) { - // Whatever...put in fullscreen stack for now. - stackId = FULLSCREEN_WORKSPACE_STACK_ID; - } - final T stack = getStack(stackId); - if (stack != null) { - return stack; - } - } - - if (stackId == INVALID_STACK_ID) { - stackId = mSupervisor.getNextStackId(); - } + final int stackId = mSupervisor.getNextStackId(); final T stack = createStackUnchecked(windowingMode, activityType, stackId, onTop); @@ -291,7 +296,7 @@ class ActivityDisplay extends ConfigurationContainer { if (stack.getWindowingMode() != windowingMode) { continue; } - mSupervisor.removeStackLocked(stack.mStackId); + mSupervisor.removeStack(stack); } } } @@ -306,12 +311,63 @@ class ActivityDisplay extends ConfigurationContainer { for (int i = mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = mStacks.get(i); if (stack.getActivityType() == activityType) { - mSupervisor.removeStackLocked(stack.mStackId); + mSupervisor.removeStack(stack); } } } } + void onStackWindowingModeChanged(ActivityStack stack) { + removeStackReferenceIfNeeded(stack); + addStackReferenceIfNeeded(stack); + } + + private void addStackReferenceIfNeeded(ActivityStack stack) { + final int activityType = stack.getActivityType(); + final int windowingMode = stack.getWindowingMode(); + + if (activityType == ACTIVITY_TYPE_HOME) { + if (mHomeStack != null && mHomeStack != stack) { + throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" + + mHomeStack + " already exist on display=" + this + " stack=" + stack); + } + mHomeStack = stack; + } else if (activityType == ACTIVITY_TYPE_RECENTS) { + if (mRecentsStack != null && mRecentsStack != stack) { + throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack=" + + mRecentsStack + " already exist on display=" + this + " stack=" + stack); + } + mRecentsStack = stack; + } + if (windowingMode == WINDOWING_MODE_PINNED) { + if (mPinnedStack != null && mPinnedStack != stack) { + throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack=" + + mPinnedStack + " already exist on display=" + this + + " stack=" + stack); + } + mPinnedStack = stack; + } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) { + throw new IllegalArgumentException("addStackReferenceIfNeeded:" + + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack + + " already exist on display=" + this + " stack=" + stack); + } + mSplitScreenPrimaryStack = stack; + } + } + + private void removeStackReferenceIfNeeded(ActivityStack stack) { + if (stack == mHomeStack) { + mHomeStack = null; + } else if (stack == mRecentsStack) { + mRecentsStack = null; + } else if (stack == mPinnedStack) { + mPinnedStack = null; + } else if (stack == mSplitScreenPrimaryStack) { + mSplitScreenPrimaryStack = null; + } + } + /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */ int getTopVisibleStackActivityType(int excludeWindowingMode) { for (int i = mStacks.size() - 1; i >= 0; --i) { @@ -326,20 +382,42 @@ class ActivityDisplay extends ConfigurationContainer { return ACTIVITY_TYPE_UNDEFINED; } - ActivityStack getSplitScreenStack() { - return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); + /** + * Get the topmost stack on the display. It may be different from focused stack, because + * focus may be on another display. + */ + ActivityStack getTopStack() { + return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1); } - boolean hasSplitScreenStack() { - return getSplitScreenStack() != null; + boolean isTopStack(ActivityStack stack) { + return stack == getTopStack(); + } + + int getIndexOf(ActivityStack stack) { + return mStacks.indexOf(stack); + } + + void onLockTaskPackagesUpdated() { + for (int i = mStacks.size() - 1; i >= 0; --i) { + mStacks.get(i).onLockTaskPackagesUpdated(); + } + } + + ActivityStack getSplitScreenPrimaryStack() { + return mSplitScreenPrimaryStack; + } + + boolean hasSplitScreenPrimaryStack() { + return mSplitScreenPrimaryStack != null; } PinnedActivityStack getPinnedStack() { - return getStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); + return (PinnedActivityStack) mPinnedStack; } boolean hasPinnedStack() { - return getPinnedStack() != null; + return mPinnedStack != null; } @Override @@ -353,7 +431,7 @@ class ActivityDisplay extends ConfigurationContainer { } @Override - protected ConfigurationContainer getChildAt(int index) { + protected ActivityStack getChildAt(int index) { return mStacks.get(index); } @@ -401,6 +479,10 @@ class ActivityDisplay extends ConfigurationContainer { mSleeping = asleep; } + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "displayId=" + mDisplayId + " mStacks=" + mStacks); + } + public void writeToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); super.writeToProto(proto, CONFIGURATION_CONTAINER); diff --git a/com/android/server/am/ActivityManagerDebugConfig.java b/com/android/server/am/ActivityManagerDebugConfig.java index 3a9bf125..ceb2ad62 100644 --- a/com/android/server/am/ActivityManagerDebugConfig.java +++ b/com/android/server/am/ActivityManagerDebugConfig.java @@ -59,7 +59,6 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_FOCUS = false; static final boolean DEBUG_IDLE = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false; - static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false; static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false; static final boolean DEBUG_LRU = DEBUG_ALL || false; static final boolean DEBUG_MU = DEBUG_ALL || false; @@ -74,10 +73,10 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_PROVIDER = DEBUG_ALL || false; static final boolean DEBUG_PSS = DEBUG_ALL || false; static final boolean DEBUG_RECENTS = DEBUG_ALL || false; + static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false; static final boolean DEBUG_RELEASE = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_RESULTS = DEBUG_ALL || false; static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false; - static final boolean DEBUG_SCREENSHOTS = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_SERVICE = DEBUG_ALL || false; static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false; static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false; @@ -85,7 +84,6 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_SWITCH = DEBUG_ALL || false; static final boolean DEBUG_TASKS = DEBUG_ALL || false; - static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false; static final boolean DEBUG_TRANSITION = DEBUG_ALL || false; static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false; static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false; @@ -105,7 +103,6 @@ class ActivityManagerDebugConfig { static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : ""; static final String POSTFIX_IDLE = (APPEND_CATEGORY_NAME) ? "_Idle" : ""; static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : ""; - static final String POSTFIX_LOCKSCREEN = (APPEND_CATEGORY_NAME) ? "_LockScreen" : ""; static final String POSTFIX_LOCKTASK = (APPEND_CATEGORY_NAME) ? "_LockTask" : ""; static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : ""; static final String POSTFIX_MU = "_MU"; @@ -122,7 +119,6 @@ class ActivityManagerDebugConfig { static final String POSTFIX_RELEASE = (APPEND_CATEGORY_NAME) ? "_Release" : ""; static final String POSTFIX_RESULTS = (APPEND_CATEGORY_NAME) ? "_Results" : ""; static final String POSTFIX_SAVED_STATE = (APPEND_CATEGORY_NAME) ? "_SavedState" : ""; - static final String POSTFIX_SCREENSHOTS = (APPEND_CATEGORY_NAME) ? "_Screenshots" : ""; static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : ""; static final String POSTFIX_SERVICE_EXECUTING = (APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : ""; @@ -130,13 +126,11 @@ class ActivityManagerDebugConfig { static final String POSTFIX_STATES = (APPEND_CATEGORY_NAME) ? "_States" : ""; static final String POSTFIX_SWITCH = (APPEND_CATEGORY_NAME) ? "_Switch" : ""; static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : ""; - static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : ""; static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : ""; static final String POSTFIX_UID_OBSERVERS = (APPEND_CATEGORY_NAME) ? "_UidObservers" : ""; static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : ""; static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : ""; static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : ""; - static final String POSTFIX_VISIBLE_BEHIND = (APPEND_CATEGORY_NAME) ? "_VisibleBehind" : ""; } diff --git a/com/android/server/am/ActivityManagerService.java b/com/android/server/am/ActivityManagerService.java index e6fe6204..f17c9ac3 100644 --- a/com/android/server/am/ActivityManagerService.java +++ b/com/android/server/am/ActivityManagerService.java @@ -27,18 +27,10 @@ import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.ActivityManager.StackId.getWindowingModeForStackId; -import static android.app.ActivityManager.StackId.isStaticStack; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; @@ -57,6 +49,9 @@ import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground; import static android.os.Build.VERSION_CODES.N; +import static android.os.IServiceManager.DUMP_PRIORITY_CRITICAL; +import static android.os.IServiceManager.DUMP_PRIORITY_HIGH; +import static android.os.IServiceManager.DUMP_PRIORITY_NORMAL; import static android.os.Process.BLUETOOTH_UID; import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.FIRST_ISOLATED_UID; @@ -137,7 +132,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH; @@ -182,7 +176,6 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; -import static com.android.server.am.proto.ActivityManagerServiceProto.ACTIVITIES; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; import static com.android.server.wm.AppTransition.TRANSIT_NONE; import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE; @@ -199,7 +192,6 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; -import android.app.ActivityManager.StackId; import android.app.ActivityManager.StackInfo; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManagerInternal; @@ -216,7 +208,6 @@ import android.app.ContentProviderHolder; import android.app.Dialog; import android.app.IActivityController; import android.app.IActivityManager; -import android.app.IAppTask; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; import android.app.INotificationManager; @@ -404,6 +395,9 @@ import com.android.server.SystemServiceManager; import com.android.server.ThreadPriorityBooster; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.proto.ActivityManagerServiceProto; +import com.android.server.am.proto.BroadcastProto; +import com.android.server.am.proto.StickyBroadcastProto; import com.android.server.firewall.IntentFirewall; import com.android.server.job.JobSchedulerInternal; import com.android.server.pm.Installer; @@ -739,9 +733,6 @@ public class ActivityManagerService extends IActivityManager.Stub doDump(fd, pw, new String[] {"associations"}); } doDump(fd, pw, new String[] {"processes"}); - doDump(fd, pw, new String[] {"-v", "all"}); - doDump(fd, pw, new String[] {"service", "all"}); - doDump(fd, pw, new String[] {"provider", "all"}); } @Override @@ -753,6 +744,8 @@ public class ActivityManagerService extends IActivityManager.Stub public boolean canShowErrorDialogs() { return mShowDialogs && !mSleeping && !mShuttingDown && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY) + && !mUserController.hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, + mUserController.getCurrentUserId()) && !(UserManager.isDeviceInDemoMode(mContext) && mUserController.getCurrentUser().isDemo()); } @@ -1717,7 +1710,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; - static final int TOP_APP_KILLED_BY_LMK_MSG = 73; static final int NOTIFY_VR_KEYGUARD_MSG = 74; static final int FIRST_ACTIVITY_STACK_MSG = 100; @@ -1738,9 +1730,6 @@ public class ActivityManagerService extends IActivityManager.Stub */ private boolean mUserIsMonkey; - /** Flag whether the device has a Recents UI */ - boolean mHasRecents; - /** The dimensions of the thumbnails in the Recents UI. */ int mThumbnailWidth; int mThumbnailHeight; @@ -1946,17 +1935,6 @@ public class ActivityManagerService extends IActivityManager.Stub dispatchProcessDied(pid, uid); break; } - case TOP_APP_KILLED_BY_LMK_MSG: { - final String appName = (String) msg.obj; - final AlertDialog d = new BaseErrorDialog(mUiContext); - d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); - d.setTitle(mUiContext.getText(R.string.top_app_killed_title)); - d.setMessage(mUiContext.getString(R.string.top_app_killed_message, appName)); - d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.close), - obtainMessage(DISMISS_DIALOG_UI_MSG, d)); - d.show(); - break; - } case DISPATCH_UIDS_CHANGED_UI_MSG: { dispatchUidsChanged(); } break; @@ -2111,7 +2089,8 @@ public class ActivityManagerService extends IActivityManager.Stub String text = mContext.getString(R.string.heavy_weight_notification, context.getApplicationInfo().loadLabel(context.getPackageManager())); Notification notification = - new Notification.Builder(context, SystemNotificationChannels.DEVELOPER) + new Notification.Builder(context, + SystemNotificationChannels.HEAVY_WEIGHT_APP) .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) .setWhen(0) .setOngoing(true) @@ -2145,7 +2124,7 @@ public class ActivityManagerService extends IActivityManager.Stub } try { inm.cancelNotificationWithTag("android", null, - SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, msg.arg1); + SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, msg.arg1); } catch (RuntimeException e) { Slog.w(ActivityManagerService.TAG, "Error canceling notification for service", e); @@ -2503,13 +2482,16 @@ public class ActivityManagerService extends IActivityManager.Stub public void setSystemProcess() { try { - ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true); + ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true, + DUMP_PRIORITY_CRITICAL | DUMP_PRIORITY_NORMAL); ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); - ServiceManager.addService("meminfo", new MemBinder(this)); + ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false, + DUMP_PRIORITY_HIGH | DUMP_PRIORITY_NORMAL); ServiceManager.addService("gfxinfo", new GraphicsBinder(this)); ServiceManager.addService("dbinfo", new DbBinder(this)); if (MONITOR_CPU_USAGE) { - ServiceManager.addService("cpuinfo", new CpuBinder(this)); + ServiceManager.addService("cpuinfo", new CpuBinder(this), + /* allowIsolated= */ false, DUMP_PRIORITY_CRITICAL); } ServiceManager.addService("permission", new PermissionController(this)); ServiceManager.addService("processinfo", new ProcessInfoService(this)); @@ -2540,7 +2522,6 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { mWindowManager = wm; mStackSupervisor.setWindowManager(wm); - mActivityStarter.setWindowManager(wm); mLockTaskController.setWindowManager(wm); } } @@ -2782,8 +2763,9 @@ public class ActivityManagerService extends IActivityManager.Stub mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); mTaskChangeNotificationController = new TaskChangeNotificationController(this, mStackSupervisor, mHandler); - mActivityStarter = new ActivityStarter(this, mStackSupervisor); + mActivityStarter = new ActivityStarter(this); mRecentTasks = new RecentTasks(this, mStackSupervisor); + mStackSupervisor.setRecentTasks(mRecentTasks); mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler); mProcessCpuThread = new Thread("CpuTracker") { @@ -3241,11 +3223,12 @@ public class ActivityManagerService extends IActivityManager.Stub // stack implementation changes in the future, keep in mind that the use of the fullscreen // stack is a means to move the activity to the main display and a moveActivityToDisplay() // option would be a better choice here. - if (r.requestedVrComponent != null && r.getStackId() >= FIRST_DYNAMIC_STACK_ID) { + if (r.requestedVrComponent != null && r.getDisplayId() != DEFAULT_DISPLAY) { Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId() + " to main stack for VR"); - setTaskWindowingMode(r.getTask().taskId, - WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */); + final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, r.getActivityType(), true /* toTop */); + moveTaskToStack(r.getTask().taskId, stack.mStackId, true /* toTop */); } mHandler.sendMessage( mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); @@ -5095,11 +5078,12 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - if (mHeavyWeightProcess == null) { + final ProcessRecord proc = mHeavyWeightProcess; + if (proc == null) { return; } - ArrayList<ActivityRecord> activities = new ArrayList<>(mHeavyWeightProcess.activities); + ArrayList<ActivityRecord> activities = new ArrayList<>(proc.activities); for (int i = 0; i < activities.size(); i++) { ActivityRecord r = activities.get(i); if (!r.finishing && r.isInStackLocked()) { @@ -5109,7 +5093,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG, - mHeavyWeightProcess.userId, 0)); + proc.userId, 0)); mHeavyWeightProcess = null; } } @@ -5428,7 +5412,6 @@ public class ActivityManagerService extends IActivityManager.Stub boolean doLowMem = app.instr == null; boolean doOomAdj = doLowMem; if (!app.killedByAm) { - maybeNotifyTopAppKilled(app); Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: " + ProcessList.makeOomAdjString(app.setAdj) + ProcessList.makeProcStateString(app.setProcState)); @@ -5462,23 +5445,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - /** Show system error dialog when a top app is killed by LMK */ - void maybeNotifyTopAppKilled(ProcessRecord app) { - if (!shouldNotifyTopAppKilled(app)) { - return; - } - - Message msg = mHandler.obtainMessage(TOP_APP_KILLED_BY_LMK_MSG); - msg.obj = mContext.getPackageManager().getApplicationLabel(app.info); - mUiHandler.sendMessage(msg); - } - - /** Only show notification when the top app is killed on low ram devices */ - private boolean shouldNotifyTopAppKilled(ProcessRecord app) { - return app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP && - ActivityManager.isLowRamDeviceStatic(); - } - /** * If a stack trace dump file is configured, dump process stack traces. * @param clearTraces causes the dump file to be erased prior to the new @@ -5963,16 +5929,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (appInfo != null) { forceStopPackageLocked(packageName, appInfo.uid, "clear data"); - // Remove all tasks match the cleared application package and user - for (int i = mRecentTasks.size() - 1; i >= 0; i--) { - final TaskRecord tr = mRecentTasks.get(i); - final String taskPackageName = - tr.getBaseIntent().getComponent().getPackageName(); - if (tr.userId != resolvedUserId) continue; - if (!taskPackageName.equals(packageName)) continue; - mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, - REMOVE_FROM_RECENTS); - } + mRecentTasks.removeTasksByPackageName(packageName, resolvedUserId); } } @@ -6553,7 +6510,7 @@ public class ActivityManagerService extends IActivityManager.Stub } // Clean-up disabled tasks - cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId); + mRecentTasks.cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId); // Clean-up disabled services. mServices.bringDownDisabledPackageServicesLocked( @@ -8084,8 +8041,8 @@ public class ActivityManagerService extends IActivityManager.Stub } private boolean isInPictureInPictureMode(ActivityRecord r) { - if (r == null || r.getStack() == null || !r.getStack().isPinnedStack() || - r.getStack().isInStackLocked(r) == null) { + if (r == null || r.getStack() == null || !r.inPinnedWindowingMode() + || r.getStack().isInStackLocked(r) == null) { return false; } @@ -8179,7 +8136,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Only update the saved args from the args that are set r.pictureInPictureArgs.copyOnlySet(params); - if (r.getStack().getStackId() == PINNED_STACK_ID) { + if (r.inPinnedWindowingMode()) { // If the activity is already in picture-in-picture, update the pinned stack now // if it is not already expanding to fullscreen. Otherwise, the arguments will // be used the next time the activity enters PiP @@ -9800,35 +9757,12 @@ public class ActivityManagerService extends IActivityManager.Stub public List<IBinder> getAppTasks(String callingPackage) { int callingUid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); - - synchronized(this) { - ArrayList<IBinder> list = new ArrayList<IBinder>(); - try { - if (DEBUG_ALL) Slog.v(TAG, "getAppTasks"); - - final int N = mRecentTasks.size(); - for (int i = 0; i < N; i++) { - TaskRecord tr = mRecentTasks.get(i); - // Skip tasks that do not match the caller. We don't need to verify - // callingPackage, because we are also limiting to callingUid and know - // that will limit to the correct security sandbox. - if (tr.effectiveUid != callingUid) { - continue; - } - Intent intent = tr.getBaseIntent(); - if (intent == null || - !callingPackage.equals(intent.getComponent().getPackageName())) { - continue; - } - ActivityManager.RecentTaskInfo taskInfo = - createRecentTaskInfoFromTaskRecord(tr); - AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid); - list.add(taskImpl.asBinder()); - } - } finally { - Binder.restoreCallingIdentity(ident); + try { + synchronized(this) { + return mRecentTasks.getAppTasksList(callingUid, callingPackage); } - return list; + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -9851,58 +9785,6 @@ public class ActivityManagerService extends IActivityManager.Stub return list; } - /** - * Creates a new RecentTaskInfo from a TaskRecord. - */ - private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) { - // Update the task description to reflect any changes in the task stack - tr.updateTaskDescription(); - - // Compose the recent task info - ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); - rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId; - rti.persistentId = tr.taskId; - rti.baseIntent = new Intent(tr.getBaseIntent()); - rti.origActivity = tr.origActivity; - rti.realActivity = tr.realActivity; - rti.description = tr.lastDescription; - rti.stackId = tr.getStackId(); - rti.userId = tr.userId; - rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription); - rti.firstActiveTime = tr.firstActiveTime; - rti.lastActiveTime = tr.lastActiveTime; - rti.affiliatedTaskId = tr.mAffiliatedTaskId; - rti.affiliatedTaskColor = tr.mAffiliatedTaskColor; - rti.numActivities = 0; - if (tr.mBounds != null) { - rti.bounds = new Rect(tr.mBounds); - } - rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode(); - rti.resizeMode = tr.mResizeMode; - rti.configuration.setTo(tr.getConfiguration()); - - ActivityRecord base = null; - ActivityRecord top = null; - ActivityRecord tmp; - - for (int i = tr.mActivities.size() - 1; i >= 0; --i) { - tmp = tr.mActivities.get(i); - if (tmp.finishing) { - continue; - } - base = tmp; - if (top == null || (top.state == ActivityState.INITIALIZING)) { - top = base; - } - rti.numActivities++; - } - - rti.baseActivity = (base != null) ? base.intent.getComponent() : null; - rti.topActivity = (top != null) ? top.intent.getComponent() : null; - - return rti; - } - private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) { boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS, callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; @@ -9936,118 +9818,15 @@ public class ActivityManagerService extends IActivityManager.Stub final int callingUid = Binder.getCallingUid(); userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, false, ALLOW_FULL_ONLY, "getRecentTasks", null); + final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(), + callingUid); + final boolean detailed = checkCallingPermission( + android.Manifest.permission.GET_DETAILED_TASKS) + == PackageManager.PERMISSION_GRANTED; - final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0; - final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0; synchronized (this) { - final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(), + return mRecentTasks.getRecentTasks(maxNum, flags, allowed, detailed, userId, callingUid); - final boolean detailed = checkCallingPermission( - android.Manifest.permission.GET_DETAILED_TASKS) - == PackageManager.PERMISSION_GRANTED; - - if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) { - Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents"); - return ParceledListSlice.emptyList(); - } - mRecentTasks.loadUserRecentsLocked(userId); - - final int recentsCount = mRecentTasks.size(); - ArrayList<ActivityManager.RecentTaskInfo> res = - new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount); - - final Set<Integer> includedUsers; - if (includeProfiles) { - includedUsers = mUserController.getProfileIds(userId); - } else { - includedUsers = new HashSet<>(); - } - includedUsers.add(Integer.valueOf(userId)); - - for (int i = 0; i < recentsCount && maxNum > 0; i++) { - TaskRecord tr = mRecentTasks.get(i); - // Only add calling user or related users recent tasks - if (!includedUsers.contains(Integer.valueOf(tr.userId))) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr); - continue; - } - - if (tr.realActivitySuspended) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr); - continue; - } - - // Return the entry if desired by the caller. We always return - // the first entry, because callers always expect this to be the - // foreground app. We may filter others if the caller has - // not supplied RECENT_WITH_EXCLUDED and there is some reason - // we should exclude the entry. - - if (i == 0 - || withExcluded - || (tr.intent == null) - || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - == 0)) { - if (!allowed) { - // If the caller doesn't have the GET_TASKS permission, then only - // allow them to see a small subset of tasks -- their own and home. - if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr); - continue; - } - } - final ActivityStack stack = tr.getStack(); - if ((flags & ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS) != 0) { - if (stack != null && stack.isHomeOrRecentsStack()) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, home or recents stack task: " + tr); - continue; - } - } - if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) { - if (stack != null && stack.isDockedStack() && stack.topTask() == tr) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, top task in docked stack: " + tr); - continue; - } - } - if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) { - if (stack != null && stack.isPinnedStack()) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, pinned stack task: " + tr); - continue; - } - } - if (tr.autoRemoveRecents && tr.getTopActivity() == null) { - // Don't include auto remove tasks that are finished or finishing. - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, auto-remove without activity: " + tr); - continue; - } - if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0 - && !tr.isAvailable) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, unavail real act: " + tr); - continue; - } - - if (!tr.mUserSetupComplete) { - // Don't include task launched while user is not done setting-up. - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, user setup not complete: " + tr); - continue; - } - - ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr); - if (!detailed) { - rti.baseIntent.replaceExtras((Bundle)null); - } - - res.add(rti); - maxNum--; - } - } - return new ParceledListSlice<>(res); } } @@ -10119,23 +9898,10 @@ public class ActivityManagerService extends IActivityManager.Stub TaskRecord task = new TaskRecord(this, mStackSupervisor.getNextTaskIdForUserLocked(r.userId), ainfo, intent, description); - - int trimIdx = mRecentTasks.trimForTaskLocked(task, false); - if (trimIdx >= 0) { - // If this would have caused a trim, then we'll abort because that - // means it would be added at the end of the list but then just removed. + if (!mRecentTasks.addToBottom(task)) { return INVALID_TASK_ID; } - - final int N = mRecentTasks.size(); - if (N >= (ActivityManager.getMaxRecentTasksStatic()-1)) { - final TaskRecord tr = mRecentTasks.remove(N - 1); - tr.removedFromRecents(); - } - - task.inRecents = true; - mRecentTasks.add(task); - r.getStack().addTask(task, false, "addAppTask"); + r.getStack().addTask(task, !ON_TOP, "addAppTask"); // TODO: Send the thumbnail to WM to store it. @@ -10351,38 +10117,6 @@ public class ActivityManagerService extends IActivityManager.Stub mWindowManager.executeAppTransition(); } - private void removeTasksByPackageNameLocked(String packageName, int userId) { - // Remove all tasks with activities in the specified package from the list of recent tasks - for (int i = mRecentTasks.size() - 1; i >= 0; i--) { - TaskRecord tr = mRecentTasks.get(i); - if (tr.userId != userId) continue; - - ComponentName cn = tr.intent.getComponent(); - if (cn != null && cn.getPackageName().equals(packageName)) { - // If the package name matches, remove the task. - mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS); - } - } - } - - private void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses, - int userId) { - - for (int i = mRecentTasks.size() - 1; i >= 0; i--) { - TaskRecord tr = mRecentTasks.get(i); - if (userId != UserHandle.USER_ALL && tr.userId != userId) { - continue; - } - - ComponentName cn = tr.intent.getComponent(); - final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName) - && (filterByClasses == null || filterByClasses.contains(cn.getClassName())); - if (sameComponent) { - mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS); - } - } - } - @Override public void removeStack(int stackId) { enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()"); @@ -10390,11 +10124,14 @@ public class ActivityManagerService extends IActivityManager.Stub final long ident = Binder.clearCallingIdentity(); try { final ActivityStack stack = mStackSupervisor.getStack(stackId); - if (stack != null && !stack.isActivityTypeStandardOrUndefined()) { + if (stack == null) { + return; + } + if (!stack.isActivityTypeStandardOrUndefined()) { throw new IllegalArgumentException( "Removing non-standard stack is not allowed."); } - mStackSupervisor.removeStackLocked(stackId); + mStackSupervisor.removeStack(stack); } finally { Binder.restoreCallingIdentity(ident); } @@ -10609,7 +10346,7 @@ public class ActivityManagerService extends IActivityManager.Stub } final ActivityStack stack = r.getStack(); - if (stack == null || stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) { + if (stack == null || !stack.inFreeformWindowingMode()) { throw new IllegalStateException( "exitFreeformMode: You can only go fullscreen from freeform."); } @@ -10677,27 +10414,20 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId + " to stackId=" + stackId + " toTop=" + toTop); - if (stackId == DOCKED_STACK_ID) { - mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, - null /* initialBounds */); - } - ActivityStack stack = mStackSupervisor.getStack(stackId); + final ActivityStack stack = mStackSupervisor.getStack(stackId); if (stack == null) { - if (!isStaticStack(stackId)) { - throw new IllegalStateException( - "moveTaskToStack: No stack for stackId=" + stackId); - } - final ActivityDisplay display = task.getStack().getDisplay(); - final int windowingMode = - getWindowingModeForStackId(stackId, display.hasSplitScreenStack()); - stack = display.getOrCreateStack(windowingMode, - task.getStack().getActivityType(), toTop); + throw new IllegalStateException( + "moveTaskToStack: No stack for stackId=" + stackId); } if (!stack.isActivityTypeStandardOrUndefined()) { throw new IllegalArgumentException("moveTaskToStack: Attempt to move task " + taskId + " to stack " + stackId); } + if (stack.inSplitScreenPrimaryWindowingMode()) { + mWindowManager.setDockedStackCreateState( + DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */); + } task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "moveTaskToStack"); } finally { @@ -10767,9 +10497,9 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized (this) { final ActivityStack stack = - mStackSupervisor.getDefaultDisplay().getSplitScreenStack(); + mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); if (toTop) { - mStackSupervisor.resizeStackLocked(stack.mStackId, null /* destBounds */, + mStackSupervisor.resizeStackLocked(stack, null /* destBounds */, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, true /* preserveWindows */, true /* allowResizeInDockedMode */, !DEFER_RESUME); @@ -10862,7 +10592,12 @@ public class ActivityManagerService extends IActivityManager.Stub stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, animationDuration, false /* fromFullscreen */); } else { - mStackSupervisor.resizeStackLocked(stackId, destBounds, null /* tempTaskBounds */, + final ActivityStack stack = mStackSupervisor.getStack(stackId); + if (stack == null) { + Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); + return; + } + mStackSupervisor.resizeStackLocked(stack, destBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, preserveWindows, allowResizeInDockedMode, !DEFER_RESUME); } @@ -12938,6 +12673,10 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("Provided bugreport type is not correct, value: " + bugreportType); } + // Always log caller, even if it does not have permission to dump. + String type = extraOptions == null ? "bugreport" : extraOptions; + Slog.i(TAG, type + " requested by UID " + Binder.getCallingUid()); + enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport"); if (extraOptions != null) { SystemProperties.set("dumpstate.options", extraOptions); @@ -14145,7 +13884,6 @@ public class ActivityManagerService extends IActivityManager.Stub // Load resources only after the current configuration has been set. final Resources res = mContext.getResources(); - mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents); mThumbnailWidth = res.getDimensionPixelSize( com.android.internal.R.dimen.thumbnail_width); mThumbnailHeight = res.getDimensionPixelSize( @@ -15104,10 +14842,31 @@ public class ActivityManagerService extends IActivityManager.Stub long origId = Binder.clearCallingIdentity(); if (useProto) { - //TODO: Options when dumping proto final ProtoOutputStream proto = new ProtoOutputStream(fd); - synchronized (this) { - writeActivitiesToProtoLocked(proto); + String cmd = opti < args.length ? args[opti] : ""; + opti++; + + if ("activities".equals(cmd) || "a".equals(cmd)) { + // output proto is ActivityStackSupervisorProto + synchronized (this) { + writeActivitiesToProtoLocked(proto); + } + } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { + // output proto is BroadcastProto + synchronized (this) { + writeBroadcastsToProtoLocked(proto); + } + } else { + // default option, dump everything, output is ActivityManagerServiceProto + synchronized (this) { + long activityToken = proto.start(ActivityManagerServiceProto.ACTIVITIES); + writeActivitiesToProtoLocked(proto); + proto.end(activityToken); + + long broadcastToken = proto.start(ActivityManagerServiceProto.BROADCASTS); + writeBroadcastsToProtoLocked(proto); + proto.end(broadcastToken); + } } proto.flush(); Binder.restoreCallingIdentity(origId); @@ -15133,7 +14892,9 @@ public class ActivityManagerService extends IActivityManager.Stub } } else if ("recents".equals(cmd) || "r".equals(cmd)) { synchronized (this) { - dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage); + if (mRecentTasks != null) { + mRecentTasks.dump(pw, true /* dumpAll */, dumpPackage); + } } } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { String[] newArgs; @@ -15354,7 +15115,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage); + if (mRecentTasks != null) { + mRecentTasks.dump(pw, dumpAll, dumpPackage); + } pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -15424,7 +15187,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage); + if (mRecentTasks != null) { + mRecentTasks.dump(pw, dumpAll, dumpPackage); + } pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -15458,7 +15223,8 @@ public class ActivityManagerService extends IActivityManager.Stub } private void writeActivitiesToProtoLocked(ProtoOutputStream proto) { - mStackSupervisor.writeToProto(proto, ACTIVITIES); + // The output proto of "activity --proto activities" is ActivityStackSupervisorProto + mStackSupervisor.writeToProto(proto); } private void dumpLastANRLocked(PrintWriter pw) { @@ -15510,42 +15276,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - void dumpRecentsLocked(FileDescriptor fd, PrintWriter pw, String[] args, - int opti, boolean dumpAll, String dumpPackage) { - pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)"); - - boolean printedAnything = false; - - if (mRecentTasks != null && mRecentTasks.size() > 0) { - boolean printedHeader = false; - - final int N = mRecentTasks.size(); - for (int i=0; i<N; i++) { - TaskRecord tr = mRecentTasks.get(i); - if (dumpPackage != null) { - if (tr.realActivity == null || - !dumpPackage.equals(tr.realActivity.getPackageName())) { - continue; - } - } - if (!printedHeader) { - pw.println(" Recent tasks:"); - printedHeader = true; - printedAnything = true; - } - pw.print(" * Recent #"); pw.print(i); pw.print(": "); - pw.println(tr); - if (dumpAll) { - mRecentTasks.get(i).dump(pw, " "); - } - } - } - - if (!printedAnything) { - pw.println(" (nothing)"); - } - } - void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) { pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)"); @@ -16372,6 +16102,40 @@ public class ActivityManagerService extends IActivityManager.Stub } } + void writeBroadcastsToProtoLocked(ProtoOutputStream proto) { + if (mRegisteredReceivers.size() > 0) { + Iterator it = mRegisteredReceivers.values().iterator(); + while (it.hasNext()) { + ReceiverList r = (ReceiverList)it.next(); + r.writeToProto(proto, BroadcastProto.RECEIVER_LIST); + } + } + mReceiverResolver.writeToProto(proto, BroadcastProto.RECEIVER_RESOLVER); + for (BroadcastQueue q : mBroadcastQueues) { + q.writeToProto(proto, BroadcastProto.BROADCAST_QUEUE); + } + for (int user=0; user<mStickyBroadcasts.size(); user++) { + long token = proto.start(BroadcastProto.STICKY_BROADCASTS); + proto.write(StickyBroadcastProto.USER, mStickyBroadcasts.keyAt(user)); + for (Map.Entry<String, ArrayList<Intent>> ent + : mStickyBroadcasts.valueAt(user).entrySet()) { + long actionToken = proto.start(StickyBroadcastProto.ACTIONS); + proto.write(StickyBroadcastProto.StickyAction.NAME, ent.getKey()); + for (Intent intent : ent.getValue()) { + intent.writeToProto(proto, StickyBroadcastProto.StickyAction.INTENTS, + false, true, true, false); + } + proto.end(actionToken); + } + proto.end(token); + } + + long handlerToken = proto.start(BroadcastProto.HANDLER); + proto.write(BroadcastProto.MainHandler.HANDLER, mHandler.toString()); + mHandler.getLooper().writeToProto(proto, BroadcastProto.MainHandler.LOOPER); + proto.end(handlerToken); + } + void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { boolean needSep = false; @@ -19360,7 +19124,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Remove all permissions granted from/to this package removeUriPermissionsForPackageLocked(ssp, userId, true); - removeTasksByPackageNameLocked(ssp, userId); + mRecentTasks.removeTasksByPackageName(ssp, userId); mServices.forceStopPackageLocked(ssp, userId); @@ -20697,9 +20461,10 @@ public class ActivityManagerService extends IActivityManager.Stub /** Helper method that requests bounds from WM and applies them to stack. */ private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) { final Rect newStackBounds = new Rect(); - mStackSupervisor.getStack(stackId).getBoundsForNewConfiguration(newStackBounds); + final ActivityStack stack = mStackSupervisor.getStack(stackId); + stack.getBoundsForNewConfiguration(newStackBounds); mStackSupervisor.resizeStackLocked( - stackId, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */, + stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume); } @@ -24367,125 +24132,6 @@ public class ActivityManagerService extends IActivityManager.Stub } /** - * An implementation of IAppTask, that allows an app to manage its own tasks via - * {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that - * only the process that calls getAppTasks() can call the AppTask methods. - */ - class AppTaskImpl extends IAppTask.Stub { - private int mTaskId; - private int mCallingUid; - - public AppTaskImpl(int taskId, int callingUid) { - mTaskId = taskId; - mCallingUid = callingUid; - } - - private void checkCaller() { - if (mCallingUid != Binder.getCallingUid()) { - throw new SecurityException("Caller " + mCallingUid - + " does not match caller of getAppTasks(): " + Binder.getCallingUid()); - } - } - - @Override - public void finishAndRemoveTask() { - checkCaller(); - - synchronized (ActivityManagerService.this) { - long origId = Binder.clearCallingIdentity(); - try { - // We remove the task from recents to preserve backwards - if (!mStackSupervisor.removeTaskByIdLocked(mTaskId, false, - REMOVE_FROM_RECENTS)) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - - @Override - public ActivityManager.RecentTaskInfo getTaskInfo() { - checkCaller(); - - synchronized (ActivityManagerService.this) { - long origId = Binder.clearCallingIdentity(); - try { - TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); - if (tr == null) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - return createRecentTaskInfoFromTaskRecord(tr); - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - - @Override - public void moveToFront() { - checkCaller(); - // Will bring task to front if it already has a root activity. - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (this) { - mStackSupervisor.startActivityFromRecentsInner(mTaskId, null); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - - @Override - public int startActivity(IBinder whoThread, String callingPackage, - Intent intent, String resolvedType, Bundle bOptions) { - checkCaller(); - - int callingUser = UserHandle.getCallingUserId(); - TaskRecord tr; - IApplicationThread appThread; - synchronized (ActivityManagerService.this) { - tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); - if (tr == null) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - appThread = IApplicationThread.Stub.asInterface(whoThread); - if (appThread == null) { - throw new IllegalArgumentException("Bad app thread " + appThread); - } - } - return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent, - resolvedType, null, null, null, null, 0, 0, null, null, - null, bOptions, false, callingUser, tr, "AppTaskImpl"); - } - - @Override - public void setExcludeFromRecents(boolean exclude) { - checkCaller(); - - synchronized (ActivityManagerService.this) { - long origId = Binder.clearCallingIdentity(); - try { - TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); - if (tr == null) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - Intent intent = tr.getBaseIntent(); - if (exclude) { - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - } else { - intent.setFlags(intent.getFlags() - & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - } - - /** * Kill processes for the user with id userId and that depend on the package named packageName */ @Override diff --git a/com/android/server/am/ActivityManagerShellCommand.java b/com/android/server/am/ActivityManagerShellCommand.java index 4c934232..f03d2d53 100644 --- a/com/android/server/am/ActivityManagerShellCommand.java +++ b/com/android/server/am/ActivityManagerShellCommand.java @@ -73,10 +73,8 @@ import java.util.List; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.RESIZE_MODE_USER; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; @@ -86,15 +84,6 @@ final class ActivityManagerShellCommand extends ShellCommand { public static final String NO_CLASS_ERROR_CODE = "Error type 3"; private static final String SHELL_PACKAGE_NAME = "com.android.shell"; - // Is the object moving in a positive direction? - private static final boolean MOVING_FORWARD = true; - // Is the object moving in the horizontal plan? - private static final boolean MOVING_HORIZONTALLY = true; - // Is the object current point great then its target point? - private static final boolean GREATER_THAN_TARGET = true; - // Amount we reduce the stack size by when testing a task re-size. - private static final int STACK_BOUNDS_INSET = 10; - // IPC interface to activity manager -- don't need to do additional security checks. final IActivityManager mInterface; @@ -1944,8 +1933,6 @@ final class ActivityManagerShellCommand extends ShellCommand { return runStackInfo(pw); case "move-top-activity-to-pinned-stack": return runMoveTopActivityToPinnedStack(pw); - case "size-docked-stack-test": - return runStackSizeDockedStackTest(pw); case "remove": return runStackRemove(pw); default: @@ -2143,89 +2130,6 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - int runStackSizeDockedStackTest(PrintWriter pw) throws RemoteException { - final PrintWriter err = getErrPrintWriter(); - final int stepSize = Integer.parseInt(getNextArgRequired()); - final String side = getNextArgRequired(); - final String delayStr = getNextArg(); - final int delayMs = (delayStr != null) ? Integer.parseInt(delayStr) : 0; - - ActivityManager.StackInfo info = mInterface.getStackInfo( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); - if (info == null) { - err.println("Docked stack doesn't exist"); - return -1; - } - if (info.bounds == null) { - err.println("Docked stack doesn't have a bounds"); - return -1; - } - Rect bounds = info.bounds; - - final boolean horizontalGrowth = "l".equals(side) || "r".equals(side); - final int changeSize = (horizontalGrowth ? bounds.width() : bounds.height()) / 2; - int currentPoint; - switch (side) { - case "l": - currentPoint = bounds.left; - break; - case "r": - currentPoint = bounds.right; - break; - case "t": - currentPoint = bounds.top; - break; - case "b": - currentPoint = bounds.bottom; - break; - default: - err.println("Unknown growth side: " + side); - return -1; - } - - final int startPoint = currentPoint; - final int minPoint = currentPoint - changeSize; - final int maxPoint = currentPoint + changeSize; - - int maxChange; - pw.println("Shrinking docked stack side=" + side); - pw.flush(); - while (currentPoint > minPoint) { - maxChange = Math.min(stepSize, currentPoint - minPoint); - currentPoint -= maxChange; - setBoundsSide(bounds, side, currentPoint); - int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs); - if (res < 0) { - return res; - } - } - - pw.println("Growing docked stack side=" + side); - pw.flush(); - while (currentPoint < maxPoint) { - maxChange = Math.min(stepSize, maxPoint - currentPoint); - currentPoint += maxChange; - setBoundsSide(bounds, side, currentPoint); - int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs); - if (res < 0) { - return res; - } - } - - pw.println("Back to Original size side=" + side); - pw.flush(); - while (currentPoint > startPoint) { - maxChange = Math.min(stepSize, currentPoint - startPoint); - currentPoint -= maxChange; - setBoundsSide(bounds, side, currentPoint); - int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs); - if (res < 0) { - return res; - } - } - return 0; - } - void setBoundsSide(Rect bounds, String side, int value) { switch (side) { case "l": @@ -2687,10 +2591,6 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Change docked stack to <LEFT,TOP,RIGHT,BOTTOM>"); pw.println(" and supplying temporary different task bounds indicated by"); pw.println(" <TASK_LEFT,TOP,RIGHT,BOTTOM>"); - pw.println(" size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]"); - pw.println(" Test command for sizing docked stack by"); - pw.println(" <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom"); - pw.println(" applying the optional [DELAY_MS] between each step."); pw.println(" move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>"); pw.println(" Moves the top activity from"); pw.println(" <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the"); diff --git a/com/android/server/am/ActivityMetricsLogger.java b/com/android/server/am/ActivityMetricsLogger.java index fdcb8c69..93c0f772 100644 --- a/com/android/server/am/ActivityMetricsLogger.java +++ b/com/android/server/am/ActivityMetricsLogger.java @@ -5,6 +5,7 @@ import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; @@ -127,7 +128,7 @@ class ActivityMetricsLogger { case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: mWindowState = WINDOW_STATE_SIDE_BY_SIDE; break; - case WINDOW_STATE_FREEFORM: + case WINDOWING_MODE_FREEFORM: mWindowState = WINDOW_STATE_FREEFORM; break; default: diff --git a/com/android/server/am/ActivityRecord.java b/com/android/server/am/ActivityRecord.java index 7b0b942a..2c72a4db 100644 --- a/com/android/server/am/ActivityRecord.java +++ b/com/android/server/am/ActivityRecord.java @@ -17,9 +17,7 @@ package com.android.server.am; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX; import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; import static android.app.ActivityOptions.ANIM_CUSTOM; @@ -60,6 +58,10 @@ import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS; import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; @@ -284,6 +286,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo int configChangeFlags; // which config values have changed private boolean keysPaused; // has key dispatching been paused for it? int launchMode; // the launch mode activity attribute. + int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override boolean visible; // does this activity's window need to be shown? boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard // might hide this activity? @@ -420,9 +423,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (iconFilename != null || taskDescription.getLabel() != null || taskDescription.getPrimaryColor() != 0) { pw.print(prefix); pw.print("taskDescription:"); - pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); pw.print(" label=\""); pw.print(taskDescription.getLabel()); pw.print("\""); + pw.print(" icon="); pw.print(taskDescription.getInMemoryIcon() != null + ? taskDescription.getInMemoryIcon().getByteCount() + " bytes" + : "null"); + pw.print(" iconResource="); pw.print(taskDescription.getIconResource()); + pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); pw.print(" primaryColor="); pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); pw.print(prefix + " backgroundColor="); @@ -432,9 +439,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo pw.print(prefix + " navigationBarColor="); pw.println(Integer.toHexString(taskDescription.getNavigationBarColor())); } - if (iconFilename == null && taskDescription.getIcon() != null) { - pw.print(prefix); pw.println("taskDescription contains Bitmap"); - } } if (results != null) { pw.print(prefix); pw.print("results="); pw.println(results); @@ -661,8 +665,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return; } - final boolean inPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID) && - (targetStackBounds != null); + final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null; if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) { // Picture-in-picture mode changes also trigger a multi-window mode change as well, so // update that here in order @@ -684,10 +687,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } - boolean isFreeform() { - return task != null && task.getStackId() == FREEFORM_WORKSPACE_STACK_ID; - } - @Override protected int getChildCount() { // {@link ActivityRecord} is a leaf node and has no children. @@ -831,23 +830,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo hasBeenLaunched = false; mStackSupervisor = supervisor; - mRotationAnimationHint = aInfo.rotationAnimation; - - if (options != null) { - pendingOptions = options; - mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind(); - - final int rotationAnimation = pendingOptions.getRotationAnimationHint(); - // Only override manifest supplied option if set. - if (rotationAnimation >= 0) { - mRotationAnimationHint = rotationAnimation; - } - PendingIntent usageReport = pendingOptions.getUsageTimeReport(); - if (usageReport != null) { - appTimeTracker = new AppTimeTracker(usageReport); - } - } - // This starts out true, since the initial state of an activity is that we have everything, // and we shouldn't never consider it lacking in state to be removed if it dies. haveState = true; @@ -914,6 +896,32 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0; mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0; + + mRotationAnimationHint = aInfo.rotationAnimation; + lockTaskLaunchMode = aInfo.lockTaskLaunchMode; + if (appInfo.isPrivilegedApp() && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS + || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { + lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; + } + + if (options != null) { + pendingOptions = options; + mLaunchTaskBehind = options.getLaunchTaskBehind(); + + final int rotationAnimation = pendingOptions.getRotationAnimationHint(); + // Only override manifest supplied option if set. + if (rotationAnimation >= 0) { + mRotationAnimationHint = rotationAnimation; + } + final PendingIntent usageReport = pendingOptions.getUsageTimeReport(); + if (usageReport != null) { + appTimeTracker = new AppTimeTracker(usageReport); + } + final boolean useLockTask = pendingOptions.getLockTaskMode(); + if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) { + lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; + } + } } AppWindowContainerController getWindowContainerController() { @@ -948,7 +956,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // update the initial multi-window modes so that the callbacks are scheduled correctly when // the user leaves that mode. mLastReportedMultiWindowMode = !task.mFullscreen; - mLastReportedPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID); + mLastReportedPictureInPictureMode = inPinnedWindowingMode(); } void removeWindowContainer() { @@ -1551,7 +1559,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // On devices that support leanback only (Android TV), Recents activity can only be // visible if the home stack is the focused stack or we are in split-screen mode. final ActivityDisplay display = getDisplay(); - boolean hasSplitScreenStack = display != null && display.hasSplitScreenStack(); + boolean hasSplitScreenStack = display != null && display.hasSplitScreenPrimaryStack(); isVisible = hasSplitScreenStack || mStackSupervisor.isFocusedStack(getStack()); } @@ -2739,6 +2747,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo void setShowWhenLocked(boolean showWhenLocked) { mShowWhenLocked = showWhenLocked; + mStackSupervisor.ensureActivitiesVisibleLocked(null, 0 /* configChanges */, + false /* preserveWindows */); } /** diff --git a/com/android/server/am/ActivityStack.java b/com/android/server/am/ActivityStack.java index 1940ca2b..f0811dda 100644 --- a/com/android/server/am/ActivityStack.java +++ b/com/android/server/am/ActivityStack.java @@ -16,27 +16,25 @@ package com.android.server.am; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.app.WindowConfiguration.activityTypeToString; +import static android.app.WindowConfiguration.windowingModeToString; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; - import static android.view.Display.INVALID_DISPLAY; + import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM; import static com.android.server.am.ActivityDisplay.POSITION_TOP; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE; @@ -100,7 +98,6 @@ import static java.lang.Integer.MAX_VALUE; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; -import android.app.ActivityManager.StackId; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IActivityController; @@ -110,6 +107,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; +import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -192,10 +190,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // finished destroying itself. private static final int DESTROY_TIMEOUT = 10 * 1000; - // How long until we reset a task when the user returns to it. Currently - // disabled. - private static final long ACTIVITY_INACTIVE_RESET_TIME = 0; - // Set to false to disable the preview that is shown while a new activity // is being started. private static final boolean SHOW_APP_STARTING_PREVIEW = true; @@ -352,12 +346,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private final SparseArray<Rect> mTmpBounds = new SparseArray<>(); private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>(); private final Rect mTmpRect2 = new Rect(); + private final Point mTmpSize = new Point(); /** Run all ActivityStacks through this */ protected final ActivityStackSupervisor mStackSupervisor; - private final LaunchingTaskPositioner mTaskPositioner; - private boolean mTopActivityOccludesKeyguard; private ActivityRecord mTopDismissingKeyguardActivity; @@ -460,8 +453,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mWindowManager = mService.mWindowManager; mStackId = stackId; mCurrentUser = mService.mUserController.getCurrentUserId(); - mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID - ? new LaunchingTaskPositioner() : null; mTmpRect2.setEmpty(); setWindowingMode(windowingMode); setActivityType(activityType); @@ -479,6 +470,16 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return mWindowContainerController; } + @Override + public void onConfigurationChanged(Configuration newParentConfig) { + final int prevWindowingMode = getWindowingMode(); + super.onConfigurationChanged(newParentConfig); + final ActivityDisplay display = getDisplay(); + if (display != null && prevWindowingMode != getWindowingMode()) { + display.onStackWindowingModeChanged(this); + } + } + /** Adds the stack to specified display and calls WindowManager to do the same. */ void reparent(ActivityDisplay activityDisplay, boolean onTop) { removeFromDisplay(); @@ -502,14 +503,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mDisplayId = activityDisplay.mDisplayId; mBounds = bounds != null ? new Rect(bounds) : null; mFullscreen = mBounds == null; - if (mTaskPositioner != null) { - mTaskPositioner.setDisplay(activityDisplay.mDisplay); - mTaskPositioner.configure(mBounds); - } + onParentChanged(); activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM); - if (mStackId == DOCKED_STACK_ID) { + if (inSplitScreenPrimaryWindowingMode()) { // If we created a docked stack we want to resize it so it resizes all other stacks // in the system. mStackSupervisor.resizeDockedStackLocked( @@ -533,9 +531,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai display.removeChild(this); } mDisplayId = INVALID_DISPLAY; - if (mTaskPositioner != null) { - mTaskPositioner.reset(); - } } /** Removes the stack completely. Also calls WindowManager to do the same on its side. */ @@ -639,9 +634,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai void setBounds(Rect bounds) { mBounds = mFullscreen ? null : new Rect(bounds); - if (mTaskPositioner != null) { - mTaskPositioner.configure(bounds); - } } ActivityRecord topRunningActivityLocked() { @@ -818,14 +810,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return isActivityTypeHome() || isActivityTypeRecents(); } - final boolean isDockedStack() { - return mStackId == DOCKED_STACK_ID; - } - - final boolean isPinnedStack() { - return mStackId == PINNED_STACK_ID; - } - final boolean isOnHomeDisplay() { return mDisplayId == DEFAULT_DISPLAY; } @@ -1505,9 +1489,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * needed. A stack is considered translucent if it don't contain a visible or * starting (about to be visible) activity that is fullscreen (opaque). * @param starting The currently starting activity or null if there is none. - * @param stackBehindId The id of the stack directly behind this one. + * @param stackBehind The stack directly behind this one. */ - private boolean isStackTranslucent(ActivityRecord starting, int stackBehindId) { + private boolean isStackTranslucent(ActivityRecord starting, ActivityStack stackBehind) { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); final ArrayList<ActivityRecord> activities = task.mActivities; @@ -1532,7 +1516,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - final ActivityStack stackBehind = mStackSupervisor.getStack(stackBehindId); final boolean stackBehindHomeOrRecent = stackBehind != null && stackBehind.isHomeOrRecentsStack(); if (!isHomeOrRecentsStack() && r.frontOfTask && task.isOverHomeStack() @@ -1553,6 +1536,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai && !mForceHidden; } + boolean isTopStackOnDisplay() { + return getDisplay().isTopStack(this); + } + /** * Returns true if the stack should be visible. * @@ -1563,23 +1550,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - if (mStackSupervisor.isFrontStackOnDisplay(this) || mStackSupervisor.isFocusedStack(this)) { + final ActivityDisplay display = getDisplay(); + if (isTopStackOnDisplay() || mStackSupervisor.isFocusedStack(this)) { return true; } - final ActivityDisplay display = getDisplay(); - final ArrayList<ActivityStack> displayStacks = display.mStacks; - final int stackIndex = displayStacks.indexOf(this); - - if (stackIndex == displayStacks.size() - 1) { - Slog.wtf(TAG, - "Stack=" + this + " isn't front stack but is at the top of the stack list"); - return false; - } + final int stackIndex = display.getIndexOf(this); // Check position and visibility of this stack relative to the front stack on its display. - final ActivityStack topStack = getTopStackOnDisplay(); - final int topStackId = topStack.mStackId; + final ActivityStack topStack = getDisplay().getTopStack(); final int windowingMode = getWindowingMode(); final int activityType = getActivityType(); @@ -1587,7 +1566,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // If the assistant stack is focused and translucent, then the docked stack is always // visible if (topStack.isActivityTypeAssistant()) { - return topStack.isStackTranslucent(starting, DOCKED_STACK_ID); + return topStack.isStackTranslucent(starting, this); } return true; } @@ -1596,34 +1575,31 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // A case would be if recents stack exists but has no tasks and is below the docked stack // and home stack is below recents if (activityType == ACTIVITY_TYPE_HOME) { - final ActivityStack splitScreenStack = display.getStack( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); - int dockedStackIndex = displayStacks.indexOf(splitScreenStack); + final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack(); + int dockedStackIndex = display.getIndexOf(splitScreenStack); if (dockedStackIndex > stackIndex && stackIndex != dockedStackIndex - 1) { return false; } } // Find the first stack behind front stack that actually got something visible. - int stackBehindTopIndex = displayStacks.indexOf(topStack) - 1; + int stackBehindTopIndex = display.getIndexOf(topStack) - 1; while (stackBehindTopIndex >= 0 && - displayStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) { + display.getChildAt(stackBehindTopIndex).topRunningActivityLocked() == null) { stackBehindTopIndex--; } final ActivityStack stackBehindTop = (stackBehindTopIndex >= 0) - ? displayStacks.get(stackBehindTopIndex) : null; - int stackBehindTopId = INVALID_STACK_ID; + ? display.getChildAt(stackBehindTopIndex) : null; int stackBehindTopWindowingMode = WINDOWING_MODE_UNDEFINED; int stackBehindTopActivityType = ACTIVITY_TYPE_UNDEFINED; if (stackBehindTop != null) { - stackBehindTopId = stackBehindTop.mStackId; stackBehindTopWindowingMode = stackBehindTop.getWindowingMode(); stackBehindTopActivityType = stackBehindTop.getActivityType(); } final boolean alwaysOnTop = topStack.getWindowConfiguration().isAlwaysOnTop(); if (topStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || alwaysOnTop) { - if (stackIndex == stackBehindTopIndex) { + if (this == stackBehindTop) { // Stacks directly behind the docked or pinned stack are always visible. return true; } else if (alwaysOnTop && stackIndex == stackBehindTopIndex - 1) { @@ -1632,14 +1608,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { return true; } else if (stackBehindTopActivityType == ACTIVITY_TYPE_ASSISTANT) { - return displayStacks.get(stackBehindTopIndex).isStackTranslucent( - starting, mStackId); + return stackBehindTop.isStackTranslucent(starting, this); } } } if (topStack.isBackdropToTranslucentActivity() - && topStack.isStackTranslucent(starting, stackBehindTopId)) { + && topStack.isStackTranslucent(starting, stackBehindTop)) { // Stacks behind the fullscreen or assistant stack with a translucent activity are // always visible so they can act as a backdrop to the translucent activity. // For example, dialog activities @@ -1657,14 +1632,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } - if (StackId.isStaticStack(mStackId) - || isHomeOrRecentsStack() || isActivityTypeAssistant()) { - // Visibility of any static stack should have been determined by the conditions above. + if (isOnHomeDisplay()) { + // Visibility of any stack on default display should have been determined by the + // conditions above. return false; } - for (int i = stackIndex + 1; i < displayStacks.size(); i++) { - final ActivityStack stack = displayStacks.get(i); + final int stackCount = display.getChildCount(); + for (int i = stackIndex + 1; i < stackCount; i++) { + final ActivityStack stack = display.getChildAt(i); if (!stack.mFullscreen && !stack.hasFullscreenTask()) { continue; @@ -1675,7 +1651,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - if (!stack.isStackTranslucent(starting, INVALID_STACK_ID)) { + if (!stack.isStackTranslucent(starting, null /* stackBehind */)) { return false; } } @@ -1801,7 +1777,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai makeInvisible(r); } } - if (mStackId == FREEFORM_WORKSPACE_STACK_ID) { + final int windowingMode = getWindowingMode(); + if (windowingMode == WINDOWING_MODE_FREEFORM) { // The visibility of tasks and the activities they contain in freeform stack are // determined individually unlike other stacks where the visibility or fullscreen // status of an activity in a previous task affects other. @@ -1816,7 +1793,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // show activities in the next application stack behind them vs. another // task in the home stack like recents. behindFullscreenActivity = true; - } else if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID) { + } else if (windowingMode == WINDOWING_MODE_FULLSCREEN + || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping after task=" + task + " returning to non-application type=" + task.getTaskToReturnTo()); // Once we reach a fullscreen stack task that has a running activity and should @@ -1852,6 +1830,32 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } /** + * Returns true if this stack should be resized to match the bounds specified by + * {@link ActivityOptions#setLaunchBounds} when launching an activity into the stack. + */ + boolean resizeStackWithLaunchBounds() { + return inPinnedWindowingMode(); + } + + /** + * Returns true if we try to maintain focus in the current stack when the top activity finishes. + */ + private boolean keepFocusInStackIfPossible() { + final int windowingMode = getWindowingMode(); + return windowingMode == WINDOWING_MODE_FREEFORM + || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + || windowingMode == WINDOWING_MODE_PINNED; + } + + /** + * Returns true if the top task in the task is allowed to return home when finished and + * there are other tasks in the stack. + */ + boolean allowTopTaskToReturnHome() { + return !inPinnedWindowingMode(); + } + + /** * @return the top most visible activity that wants to dismiss Keyguard */ ActivityRecord getTopDismissingKeyguardActivity() { @@ -1867,7 +1871,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai */ boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) { - final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID; + final boolean isInPinnedStack = r.inPinnedWindowingMode(); final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing( mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY); final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked(); @@ -2165,7 +2169,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mResumedActivity = r; r.state = ActivityState.RESUMED; mService.setResumedActivityUncheckLocked(r, reason); - mStackSupervisor.addRecentActivity(r); + mStackSupervisor.mRecentTasks.add(r.getTask()); } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { @@ -2572,8 +2576,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; - } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null && - mStackSupervisor.isFrontStackOnDisplay(lastStack)) { + } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null + && lastStack.isTopStackOnDisplay()) { next.showStartingWindow(null /* prev */, false /* newTask */, false /* taskSwitch */); } @@ -2617,7 +2621,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev, ActivityOptions options, String reason) { - if ((!mFullscreen || !isOnHomeDisplay()) && adjustFocusToNextFocusableStackLocked(reason)) { + if (adjustFocusToNextFocusableStackLocked(reason)) { // Try to move focus to the next visible stack with a running activity if this // stack is not covering the entire screen or is on a secondary display (with no home // stack). @@ -2746,9 +2750,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // make underlying task focused when this one will be finished. int returnToType = isLastTaskOverHome ? task.getTaskToReturnTo() : ACTIVITY_TYPE_STANDARD; - if (fromHomeOrRecents && StackId.allowTopTaskToReturnHome(mStackId)) { - returnToType = topTask == null - ? ACTIVITY_TYPE_HOME : topTask.getActivityType(); + if (fromHomeOrRecents && allowTopTaskToReturnHome()) { + returnToType = topTask == null ? ACTIVITY_TYPE_HOME : topTask.getActivityType(); } task.setTaskToReturnTo(returnToType); } @@ -2901,7 +2904,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Ensure the caller has requested not to trigger auto-enter PiP return false; } - if (pipCandidate == null || pipCandidate.getStackId() == PINNED_STACK_ID) { + if (pipCandidate == null || pipCandidate.inPinnedWindowingMode()) { // Ensure that we do not trigger entering PiP an activity on the pinned stack return false; } @@ -3186,15 +3189,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop, ActivityRecord newActivity) { - boolean forceReset = + final boolean forceReset = (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; - if (ACTIVITY_INACTIVE_RESET_TIME > 0 - && taskTop.getTask().getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) { - if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) { - forceReset = true; - } - } - final TaskRecord task = taskTop.getTask(); /** False until we evaluate the TaskRecord associated with taskTop. Switches to true @@ -3291,7 +3287,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final String myReason = reason + " adjustFocus"; if (next != r) { - if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) { + if (next != null && keepFocusInStackIfPossible() && isFocusable()) { // For freeform, docked, and pinned stacks we always keep the focus within the // stack as long as there is a running activity. return; @@ -3757,7 +3753,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (mode == FINISH_IMMEDIATELY || (prevState == ActivityState.PAUSED - && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID)) + && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode())) || finishingActivityInNonFocusedStack || prevState == STOPPING || prevState == STOPPED @@ -4436,7 +4432,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai AppTimeTracker timeTracker, String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); - final ActivityStack topStack = getTopStackOnDisplay(); + final ActivityStack topStack = getDisplay().getTopStack(); final ActivityRecord topActivity = topStack != null ? topStack.topActivity() : null; final int numTasks = mTaskHistory.size(); final int index = mTaskHistory.indexOf(tr); @@ -4464,7 +4460,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Don't refocus if invisible to current user final ActivityRecord top = tr.getTopActivity(); if (top == null || !top.okToShowLocked()) { - mStackSupervisor.addRecentActivity(top); + if (top != null) { + mStackSupervisor.mRecentTasks.add(top.getTask()); + } ActivityOptions.abort(options); return; } @@ -4524,7 +4522,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // 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 (mStackSupervisor.isFrontStackOnDisplay(this) && mService.mController != null) { + if (isTopStackOnDisplay() && mService.mController != null) { ActivityRecord next = topRunningActivityLocked(null, taskId); if (next == null) { next = topRunningActivityLocked(null, 0); @@ -4571,8 +4569,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mWindowContainerController.positionChildAtBottom(tr.getWindowContainerController()); } - if (mStackId == PINNED_STACK_ID) { - mStackSupervisor.removeStackLocked(PINNED_STACK_ID); + if (inPinnedWindowingMode()) { + mStackSupervisor.removeStack(this); return true; } @@ -4604,15 +4602,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return true; } - /** - * Get the topmost stack on the current display. It may be different from focused stack, because - * focus may be on another display. - */ - private ActivityStack getTopStackOnDisplay() { - final ArrayList<ActivityStack> stacks = getDisplay().mStacks; - return stacks.isEmpty() ? null : stacks.get(stacks.size() - 1); - } - static void logStartActivity(int tag, ActivityRecord r, TaskRecord task) { final Uri data = r.intent.getData(); final String strData = data != null ? data.toSafeString() : null; @@ -4687,7 +4676,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai for (int i = mTaskHistory.size() - 1; i >= 0; i--) { final TaskRecord task = mTaskHistory.get(i); if (task.isResizeable()) { - if (mStackId == FREEFORM_WORKSPACE_STACK_ID) { + if (inFreeformWindowingMode()) { // For freeform stack we don't adjust the size of the tasks to match that // of the stack, but we do try to make sure the tasks are still contained // with the bounds of the stack. @@ -4889,7 +4878,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (focusedStack && topTask) { // Give the latest time to ensure foreground task can be sorted // at the first, because lastActiveTime of creating task is 0. - ci.lastActiveTime = System.currentTimeMillis(); + ci.lastActiveTime = SystemClock.elapsedRealtime(); topTask = false; } @@ -5069,7 +5058,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (task.autoRemoveFromRecents() || isVoiceSession) { // Task creator asked to remove this when done, or this task was a voice // interaction, so it should not remain on the recent tasks list. - mStackSupervisor.removeTaskFromRecents(task); + mStackSupervisor.mRecentTasks.remove(task); } task.removeWindowContainer(); @@ -5097,7 +5086,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai task.setStack(null); // Notify if a task from the pinned stack is being removed (or moved depending on the mode) - if (mStackId == PINNED_STACK_ID) { + if (inPinnedWindowingMode()) { mService.mTaskChangeNotificationController.notifyActivityUnpinned(); } } @@ -5120,10 +5109,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) { - if (mTaskPositioner == null) { + if (!task.inFreeformWindowingMode()) { return false; } - mTaskPositioner.updateDefaultBounds(task, mTaskHistory, windowLayout); + mStackSupervisor.getLaunchingTaskPositioner() + .updateDefaultBounds(task, mTaskHistory, windowLayout); + return true; } @@ -5248,10 +5239,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai @Override public String toString() { return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this)) - + " stackId=" + mStackId + ", " + mTaskHistory.size() + " tasks}"; + + " stackId=" + mStackId + " type=" + activityTypeToString(getActivityType()) + + " mode=" + windowingModeToString(getWindowingMode()) + ", " + + mTaskHistory.size() + " tasks}"; } - void onLockTaskPackagesUpdatedLocked() { + void onLockTaskPackagesUpdated() { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { mTaskHistory.get(taskNdx).setLockTaskAuth(); } diff --git a/com/android/server/am/ActivityStackSupervisor.java b/com/android/server/am/ActivityStackSupervisor.java index da2827a6..5c91e3cc 100644 --- a/com/android/server/am/ActivityStackSupervisor.java +++ b/com/android/server/am/ActivityStackSupervisor.java @@ -21,11 +21,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.START_ANY_ACTIVITY; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.START_TASK_TO_FRONT; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; @@ -35,10 +31,13 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.app.WindowConfiguration.activityTypeToString; +import static android.app.WindowConfiguration.windowingModeToString; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; @@ -47,6 +46,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; + import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; @@ -86,12 +86,13 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; +import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS; import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID; import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY; -import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; + import static java.lang.Integer.MAX_VALUE; import android.Manifest; @@ -102,7 +103,6 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; -import android.app.ActivityManager.StackId; import android.app.ActivityManager.StackInfo; import android.app.ActivityManagerInternal.SleepToken; import android.app.ActivityOptions; @@ -176,7 +176,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener { +public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener, + RecentTasks.Callbacks { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM; private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; private static final String TAG_IDLE = TAG + POSTFIX_IDLE; @@ -286,7 +287,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityManagerService mService; - private RecentTasks mRecentTasks; + RecentTasks mRecentTasks; final ActivityStackSupervisorHandler mHandler; @@ -294,8 +295,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D WindowManagerService mWindowManager; DisplayManager mDisplayManager; + LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner(); + /** Counter for next free stack ID to use for dynamic activity stacks. */ - private int mNextFreeStackId = FIRST_DYNAMIC_STACK_ID; + private int mNextFreeStackId = 0; /** * Maps the task identifier that activities are currently being started in to the userId of the @@ -576,6 +579,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void setRecentTasks(RecentTasks recentTasks) { mRecentTasks = recentTasks; + mRecentTasks.registerCallback(this); } /** @@ -627,15 +631,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return stack != null && stack == mFocusedStack; } - /** The top most stack on its display. */ - boolean isFrontStackOnDisplay(ActivityStack stack) { - return isFrontOfStackList(stack, stack.getDisplay().mStacks); - } - - private boolean isFrontOfStackList(ActivityStack stack, List<ActivityStack> stackList) { - return stack == stackList.get((stackList.size() - 1)); - } - /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */ void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) { if (!focusCandidate.isFocusable()) { @@ -731,9 +726,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); final TaskRecord task = stack.taskForIdLocked(id); if (task != null) { return task; @@ -749,7 +744,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Otherwise, check the recent tasks and return if we find it there and we are not restoring // the task from recents if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents"); - final TaskRecord task = mRecentTasks.taskForIdLocked(id); + final TaskRecord task = mRecentTasks.getTask(id); if (task == null) { if (DEBUG_RECENTS) { @@ -776,9 +771,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityRecord isInAnyStackLocked(IBinder token) { int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityRecord r = stack.isInStackLocked(token); if (r != null) { return r; } @@ -816,18 +812,21 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void lockAllProfileTasks(@UserIdInt int userId) { mWindowManager.deferSurfaceLayout(); try { - final List<ActivityStack> stacks = getStacks(); - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; stackNdx--) { - final List<TaskRecord> tasks = stacks.get(stackNdx).getAllTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) { - final TaskRecord task = tasks.get(taskNdx); - - // Check the task for a top activity belonging to userId, or returning a result - // to an activity belonging to userId. Example case: a document picker for - // personal files, opened by a work app, should still get locked. - if (taskTopActivityIsUser(task, userId)) { - mService.mTaskChangeNotificationController.notifyTaskProfileLocked( - task.taskId, userId); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final List<TaskRecord> tasks = stack.getAllTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) { + final TaskRecord task = tasks.get(taskNdx); + + // Check the task for a top activity belonging to userId, or returning a + // result to an activity belonging to userId. Example case: a document + // picker for personal files, opened by a work app, should still get locked. + if (taskTopActivityIsUser(task, userId)) { + mService.mTaskChangeNotificationController.notifyTaskProfileLocked( + task.taskId, userId); + } } } } @@ -858,7 +857,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on. int candidateTaskId = nextTaskIdForUser(currentTaskId, userId); - while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId) + while (mRecentTasks.containsTaskId(candidateTaskId, userId) || anyTaskForIdLocked( candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) { candidateTaskId = nextTaskIdForUser(candidateTaskId, userId); @@ -893,9 +892,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final String processName = app.processName; boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (!isFocusedStack(stack)) { continue; } @@ -928,9 +927,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean allResumedActivitiesIdle() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (!isFocusedStack(stack) || stack.numActivities() == 0) { continue; } @@ -949,9 +948,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean allResumedActivitiesComplete() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (isFocusedStack(stack)) { final ActivityRecord r = stack.mResumedActivity; if (r != null && r.state != RESUMED) { @@ -968,12 +967,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - boolean allResumedActivitiesVisible() { + private boolean allResumedActivitiesVisible() { boolean foundResumed = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); final ActivityRecord r = stack.mResumedActivity; if (r != null) { if (!r.nowVisible || mActivitiesWaitingForVisibleActivity.contains(r)) { @@ -997,9 +996,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) { boolean someActivityPaused = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (!isFocusedStack(stack) && stack.mResumedActivity != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack + " mResumedActivity=" + stack.mResumedActivity); @@ -1014,9 +1013,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean allPausedActivitiesComplete() { boolean pausing = true; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); final ActivityRecord r = stack.mPausingActivity; if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) { if (DEBUG_STATES) { @@ -1034,9 +1033,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void cancelInitializingActivities() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - stacks.get(stackNdx).cancelInitializingActivities(); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.cancelInitializingActivities(); } } } @@ -1134,13 +1134,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) { final int displayId = mTmpOrderedDisplayIds.get(i); - final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks; - if (stacks == null) { - continue; - } - for (int j = stacks.size() - 1; j >= 0; --j) { - final ActivityStack stack = stacks.get(j); - if (stack != focusedStack && isFrontStackOnDisplay(stack) && stack.isFocusable()) { + final ActivityDisplay display = mActivityDisplays.get(displayId); + for (int j = display.getChildCount() - 1; j >= 0; --j) { + final ActivityStack stack = display.getChildAt(j); + if (stack != focusedStack && stack.isTopStackOnDisplay() && stack.isFocusable()) { r = stack.topRunningActivityLocked(); if (r != null) { return r; @@ -1156,9 +1153,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = new ArrayList<>(); final int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<>(); runningTaskLists.add(stackTaskList); stack.getTasksLocked(stackTaskList, callingUid, allowed); @@ -1607,6 +1604,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D Slog.w(TAG, msg); throw new SecurityException(msg); } + // Check if someone tries to launch an unwhitelisted activity into LockTask mode. + final boolean lockTaskMode = options.getLockTaskMode(); + if (lockTaskMode && !mService.mLockTaskController.isPackageWhitelisted( + UserHandle.getUserId(callingUid), aInfo.packageName)) { + final String msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with lockTaskMode=true"; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } } return true; @@ -1928,9 +1935,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean handleAppDiedLocked(ProcessRecord app) { boolean hasVisibleActivities = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + hasVisibleActivities |= stack.handleAppDiedLocked(app); } } return hasVisibleActivities; @@ -1938,9 +1946,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void closeSystemDialogsLocked() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - stacks.get(stackNdx).closeSystemDialogsLocked(); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.closeSystemDialogsLocked(); } } } @@ -1966,9 +1975,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (stack.finishDisabledPackageActivitiesLocked( packageName, filterByClasses, doit, evenPersistent, userId)) { didSomething = true; @@ -1988,9 +1997,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // hosted by the process that is actually still the foreground. ProcessRecord fgApp = null; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (isFocusedStack(stack)) { if (stack.mResumedActivity != null) { fgApp = stack.mResumedActivity.app; @@ -2040,9 +2049,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - stacks.get(stackNdx).updateActivityApplicationInfoLocked(aInfo); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.updateActivityApplicationInfoLocked(aInfo); } } } @@ -2051,10 +2061,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D TaskRecord finishedTask = null; ActivityStack focusedStack = getFocusedStack(); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - final int numStacks = stacks.size(); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + final int numStacks = display.getChildCount(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityStack stack = display.getChildAt(stackNdx); TaskRecord t = stack.finishTopRunningActivityLocked(app, reason); if (stack == focusedStack || finishedTask == null) { finishedTask = t; @@ -2066,10 +2076,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void finishVoiceTask(IVoiceInteractionSession session) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - final int numStacks = stacks.size(); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + final int numStacks = display.getChildCount(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityStack stack = display.getChildAt(stackNdx); stack.finishVoiceTask(session); } } @@ -2105,8 +2115,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // moveTaskToStackUncheckedLocked() should already placed the task on top, // still need moveTaskToFrontLocked() below for any transition settings. } - if (StackId.resizeStackWithLaunchBounds(stack.mStackId)) { - resizeStackLocked(stack.mStackId, bounds, null /* tempTaskBounds */, + if (stack.resizeStackWithLaunchBounds()) { + resizeStackLocked(stack, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); } else { @@ -2125,7 +2135,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D "findTaskToMoveToFront: moved to front of stack=" + currentStack); handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, - currentStack.mStackId, forceNonResizeable); + currentStack, forceNonResizeable); } boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) { @@ -2139,6 +2149,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D || mService.mSupportsFreeformWindowManagement; } + LaunchingTaskPositioner getLaunchingTaskPositioner() { + return mTaskPositioner; + } + protected <T extends ActivityStack> T getStack(int stackId) { for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { final T stack = mActivityDisplays.valueAt(i).getStack(stackId); @@ -2316,8 +2330,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); if (display != null) { - for (int i = display.mStacks.size() - 1; i >= 0; --i) { - stack = (T) display.mStacks.get(i); + for (int i = display.getChildCount() - 1; i >= 0; --i) { + stack = (T) display.getChildAt(i); if (stack.isCompatible(windowingMode, activityType)) { return stack; } @@ -2385,8 +2399,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Return the topmost valid stack on the display. - for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) { - final ActivityStack stack = activityDisplay.mStacks.get(i); + for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) { + final ActivityStack stack = activityDisplay.getChildAt(i); if (isValidLaunchStack(stack, displayId, r)) { return stack; } @@ -2417,25 +2431,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return r.supportsSplitScreenWindowingMode(); } - if (StackId.isDynamicStack(stack.mStackId)) { + if (!stack.isOnHomeDisplay()) { return r.canBeLaunchedOnDisplay(displayId); } Slog.e(TAG, "isValidLaunchStack: Unexpected stack=" + stack); return false; } - ArrayList<ActivityStack> getStacks() { - ArrayList<ActivityStack> allStacks = new ArrayList<>(); - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - allStacks.addAll(mActivityDisplays.valueAt(displayNdx).mStacks); - } - return allStacks; - } - - ArrayList<ActivityStack> getStacksOnDefaultDisplay() { - return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks; - } - /** * Get next focusable stack in the system. This will search across displays and stacks * in last-focused order for a focusable and visible stack, different from the target stack. @@ -2450,10 +2452,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) { final int displayId = mTmpOrderedDisplayIds.get(i); // If a display is registered in WM, it must also be available in AM. - @SuppressWarnings("ConstantConditions") - final List<ActivityStack> stacks = getActivityDisplayOrCreateLocked(displayId).mStacks; - for (int j = stacks.size() - 1; j >= 0; --j) { - final ActivityStack stack = stacks.get(j); + final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); + for (int j = display.getChildCount() - 1; j >= 0; --j) { + final ActivityStack stack = display.getChildAt(j); if (stack != currentFocus && stack.isFocusable() && stack.shouldBeVisible(null)) { return stack; @@ -2511,20 +2512,17 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return null; } - void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds, - boolean preserveWindows, boolean allowResizeInDockedMode, boolean deferResume) { - if (stackId == DOCKED_STACK_ID) { + void resizeStackLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds, + Rect tempTaskInsetBounds, boolean preserveWindows, boolean allowResizeInDockedMode, + boolean deferResume) { + + if (stack.inSplitScreenPrimaryWindowingMode()) { resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null, preserveWindows, deferResume); return; } - final ActivityStack stack = getStack(stackId); - if (stack == null) { - Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); - return; - } - final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenStack(); + final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenPrimaryStack(); if (!allowResizeInDockedMode && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) { // If the docked stack exists, don't resize non-floating stacks independently of the @@ -2532,7 +2530,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId); + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stack.mStackId); mWindowManager.deferSurfaceLayout(); try { if (stack.supportsSplitScreenWindowingMode()) { @@ -2584,8 +2582,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** * TODO: This should just change the windowing mode and resize vs. actually moving task around. - * Can do that once we are no longer using static stack ids. Specially when - * {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} is removed. + * Can do that once we are no longer using static stack ids. */ private void moveTasksToFullscreenStackInSurfaceTransaction(ActivityStack fromStack, int toDisplayId, boolean onTop) { @@ -2600,13 +2597,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // We are moving all tasks from the docked stack to the fullscreen stack, // which is dismissing the docked stack, so resize all other stacks to // fullscreen here already so we don't end up with resize trashing. - final ArrayList<ActivityStack> displayStacks = toDisplay.mStacks; - for (int i = displayStacks.size() - 1; i >= 0; --i) { - final ActivityStack otherStack = displayStacks.get(i); + for (int i = toDisplay.getChildCount() - 1; i >= 0; --i) { + final ActivityStack otherStack = toDisplay.getChildAt(i); if (!otherStack.inSplitScreenSecondaryWindowingMode()) { continue; } - resizeStackLocked(otherStack.mStackId, null, null, null, PRESERVE_WINDOWS, + resizeStackLocked(otherStack, null, null, null, PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, DEFER_RESUME); } @@ -2697,8 +2693,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - final ActivityStack stack = getDefaultDisplay().getStack( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); + final ActivityStack stack = getDefaultDisplay().getSplitScreenPrimaryStack(); if (stack == null) { Slog.w(TAG, "resizeDockedStackLocked: docked stack not found"); return; @@ -2727,10 +2722,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // static stacks need to be adjusted so they don't overlap with the docked stack. // We get the bounds to use from window manager which has been adjusted for any // screen controls and is also the same for all stacks. - final ArrayList<ActivityStack> stacks = getStacksOnDefaultDisplay(); + final ActivityDisplay display = getDefaultDisplay(); final Rect otherTaskRect = new Rect(); - for (int i = stacks.size() - 1; i >= 0; --i) { - final ActivityStack current = stacks.get(i); + for (int i = display.getChildCount() - 1; i >= 0; --i) { + final ActivityStack current = display.getChildAt(i); if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { continue; } @@ -2744,7 +2739,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D tempRect /* outStackBounds */, otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */); - resizeStackLocked(current.mStackId, !tempRect.isEmpty() ? tempRect : null, + resizeStackLocked(current, !tempRect.isEmpty() ? tempRect : null, !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows, true /* allowResizeInDockedMode */, deferResume); @@ -2762,8 +2757,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) { // TODO(multi-display): Pinned stack display should be passed in. - final PinnedActivityStack stack = getDefaultDisplay().getStack( - WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); + final PinnedActivityStack stack = getDefaultDisplay().getPinnedStack(); if (stack == null) { Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found"); return; @@ -2801,12 +2795,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - private void removeStackInSurfaceTransaction(int stackId) { - final ActivityStack stack = getStack(stackId); - if (stack == null) { - return; - } - + private void removeStackInSurfaceTransaction(ActivityStack stack) { final ArrayList<TaskRecord> tasks = stack.getAllTasks(); if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) { /** @@ -2836,12 +2825,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Removes the stack associated with the given {@param stackId}. If the {@param stackId} is the + * Removes the stack associated with the given {@param stack}. If the {@param stack} is the * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but * instead moved back onto the fullscreen stack. */ - void removeStackLocked(int stackId) { - mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stackId)); + void removeStack(ActivityStack stack) { + mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stack)); } /** @@ -2892,23 +2881,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } - void addRecentActivity(ActivityRecord r) { - if (r == null) { - return; - } - final TaskRecord task = r.getTask(); - mRecentTasks.addLocked(task); - task.touchActiveTime(); - } - - void removeTaskFromRecents(TaskRecord task) { - mRecentTasks.remove(task); - task.removedFromRecents(); - } - void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) { if (removeFromRecents) { - removeTaskFromRecents(tr); + mRecentTasks.remove(tr); } ComponentName component = tr.getBaseIntent().getComponent(); if (component == null) { @@ -2979,8 +2954,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D int getNextStackId() { while (true) { - if (mNextFreeStackId >= FIRST_DYNAMIC_STACK_ID - && getStack(mNextFreeStackId) == null) { + if (getStack(mNextFreeStackId) == null) { break; } mNextFreeStackId++; @@ -2989,7 +2963,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Restores a recent task to a stack + * Called to restore the state of the task into the stack that it's supposed to go into. + * * @param task The recent task to be restored. * @param aOptions The activity options to use for restoration. * @return true if the task has been restored successfully. @@ -3020,6 +2995,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } + @Override + public void onRecentTaskAdded(TaskRecord task) { + task.touchActiveTime(); + } + + @Override + public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed) { + if (wasTrimmed) { + // Task was trimmed from the recent tasks list -- remove the active task record as well + // since the user won't really be able to go back to it + removeTaskByIdLocked(task.taskId, false /* killProcess */, + false /* removeFromRecents */); + } + task.removedFromRecents(); + } + /** * Move stack with all its existing content to specified display. * @param stackId Id of stack to move. @@ -3160,7 +3151,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Resize the pinned stack to match the current size of the task the activity we are // going to be moving is currently contained in. We do this to have the right starting // animation bounds for the pinned stack to the desired bounds the caller wants. - resizeStackLocked(PINNED_STACK_ID, task.mBounds, null /* tempTaskBounds */, + resizeStackLocked(stack, task.mBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); @@ -3257,9 +3248,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityRecord affinityMatch = null; if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (!r.hasCompatibleActivityType(stack)) { if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack); @@ -3292,12 +3283,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } ActivityRecord findActivityLocked(Intent intent, ActivityInfo info, - boolean compareIntentFilters) { + boolean compareIntentFilters) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord ar = stacks.get(stackNdx) - .findActivityLocked(intent, info, compareIntentFilters); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityRecord ar = stack.findActivityLocked( + intent, info, compareIntentFilters); if (ar != null) { return ar; } @@ -3391,9 +3383,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Set the sleeping state of the stacks on the display. - final ArrayList<ActivityStack> stacks = display.mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (displayShouldSleep) { stack.goToSleepIfPossible(false /* shuttingDown */); } else { @@ -3455,12 +3446,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private boolean putStacksToSleepLocked(boolean allowDelay, boolean shuttingDown) { boolean allSleep = true; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (allowDelay) { - allSleep &= stacks.get(stackNdx).goToSleepIfPossible(shuttingDown); + allSleep &= stack.goToSleepIfPossible(shuttingDown); } else { - stacks.get(stackNdx).goToSleep(); + stack.goToSleep(); } } } @@ -3485,11 +3477,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void handleAppCrashLocked(ProcessRecord app) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - int stackNdx = stacks.size() - 1; - while (stackNdx >= 0) { - stacks.get(stackNdx).handleAppCrashLocked(app); - stackNdx--; + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.handleAppCrashLocked(app); } } } @@ -3500,7 +3491,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityStack stack = task.getStack(); r.mLaunchTaskBehind = false; - mRecentTasks.addLocked(task); + mRecentTasks.add(task); mService.mTaskChangeNotificationController.notifyTaskStackChanged(); r.setVisibility(false); @@ -3522,10 +3513,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D try { // First the front stacks. In case any are not fullscreen and are in front of home. for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - final int topStackNdx = stacks.size() - 1; - for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows); } } @@ -3536,10 +3526,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void addStartingWindowsForVisibleActivities(boolean taskSwitch) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - final int topStackNdx = stacks.size() - 1; - for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); stack.addStartingWindowsForVisibleActivities(taskSwitch); } } @@ -3555,20 +3544,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } mTaskLayersChanged = false; for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); int baseLayer = 0; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - baseLayer += stacks.get(stackNdx).rankTaskLayers(baseLayer); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + baseLayer += stack.rankTaskLayers(baseLayer); } } } void clearOtherAppTimeTrackers(AppTimeTracker except) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - final int topStackNdx = stacks.size() - 1; - for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); stack.clearOtherAppTimeTrackers(except); } } @@ -3576,10 +3565,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void scheduleDestroyAllActivities(ProcessRecord app, String reason) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - final int numStacks = stacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); stack.scheduleDestroyActivities(app, reason); } } @@ -3631,10 +3619,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // let's iterate through the tasks and release the oldest one. final int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + final int stackCount = display.getChildCount(); // Step through all stacks starting from behind, to hit the oldest things first. - for (int stackNdx = 0; stackNdx < stacks.size(); stackNdx++) { - final ActivityStack stack = stacks.get(stackNdx); + for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) { + final ActivityStack stack = display.getChildAt(stackNdx); // Try to release activities in this stack; if we manage to, we are done. if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) { return; @@ -3646,14 +3635,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean switchUserLocked(int userId, UserState uss) { final int focusStackId = mFocusedStack.getStackId(); // We dismiss the docked stack whenever we switch users. - final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenStack(); + final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenPrimaryStack(); if (dockedStack != null) { moveTasksToFullscreenStackLocked(dockedStack, mFocusedStack == dockedStack); } // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will // also cause all tasks to be moved to the fullscreen stack at a position that is // appropriate. - removeStackLocked(PINNED_STACK_ID); + removeStacksInWindowingModes(WINDOWING_MODE_PINNED); mUserStackInFront.put(mCurrentUser, focusStackId); final int restoreStackId = mUserStackInFront.get(userId, mHomeStack.mStackId); @@ -3661,9 +3650,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mStartingUsers.add(uss); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); stack.switchUserLocked(userId); TaskRecord task = stack.topTask(); if (task != null) { @@ -3761,9 +3750,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void validateTopActivitiesLocked() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); final ActivityRecord r = stack.topRunningActivityLocked(); final ActivityState state = r == null ? DESTROYED : r.state; if (isFocusedStack(stack)) { @@ -3798,7 +3787,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { final ActivityDisplay display = mActivityDisplays.valueAt(i); - pw.println(prefix + "displayId=" + display.mDisplayId + " mStacks=" + display.mStacks); + display.dump(pw, prefix); } if (!mWaitingForActivityVisible.isEmpty()) { pw.print(prefix); pw.println("mWaitingForActivityVisible="); @@ -3811,8 +3800,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mService.mLockTaskController.dump(pw, prefix); } - public void writeToProto(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); + public void writeToProto(ProtoOutputStream proto) { super.writeToProto(proto, CONFIGURATION_CONTAINER); for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx); @@ -3828,7 +3816,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } else { proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); } - proto.end(token); } /** @@ -3857,9 +3844,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ArrayList<ActivityRecord> activities = new ArrayList<>(); int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { activities.addAll(stack.getDumpActivitiesLocked(name)); } @@ -3892,11 +3879,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx); pw.print("Display #"); pw.print(activityDisplay.mDisplayId); pw.println(" (activities from top to bottom):"); - ArrayList<ActivityStack> stacks = activityDisplay.mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); pw.println(); - pw.println(" Stack #" + stack.mStackId + ":"); + pw.println(" Stack #" + stack.mStackId + + ": type=" + activityTypeToString(stack.getActivityType()) + + " mode=" + windowingModeToString(stack.getWindowingMode())); pw.println(" mFullscreen=" + stack.mFullscreen); pw.println(" isSleeping=" + stack.shouldSleepActivities()); pw.println(" mBounds=" + stack.mBounds); @@ -4140,30 +4129,29 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } synchronized (mService) { - ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); - if (activityDisplay != null) { - final boolean destroyContentOnRemoval - = activityDisplay.shouldDestroyContentOnRemove(); - final ArrayList<ActivityStack> stacks = activityDisplay.mStacks; - while (!stacks.isEmpty()) { - final ActivityStack stack = stacks.get(0); - if (destroyContentOnRemoval) { - moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, - false /* onTop */); - stack.finishAllActivitiesLocked(true /* immediately */); - } else { - // Moving all tasks to fullscreen stack, because it's guaranteed to be - // a valid launch stack for all activities. This way the task history from - // external display will be preserved on primary after move. - moveTasksToFullscreenStackLocked(stack, true /* onTop */); - } + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay == null) { + return; + } + final boolean destroyContentOnRemoval + = activityDisplay.shouldDestroyContentOnRemove(); + while (activityDisplay.getChildCount() > 0) { + final ActivityStack stack = activityDisplay.getChildAt(0); + if (destroyContentOnRemoval) { + moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, false /* onTop */); + stack.finishAllActivitiesLocked(true /* immediately */); + } else { + // Moving all tasks to fullscreen stack, because it's guaranteed to be + // a valid launch stack for all activities. This way the task history from + // external display will be preserved on primary after move. + moveTasksToFullscreenStackLocked(stack, true /* onTop */); } + } - releaseSleepTokens(activityDisplay); + releaseSleepTokens(activityDisplay); - mActivityDisplays.remove(displayId); - mWindowManager.onDisplayRemoved(displayId); - } + mActivityDisplays.remove(displayId); + mWindowManager.onDisplayRemoved(displayId); } } @@ -4235,7 +4223,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D info.userId = stack.mCurrentUser; info.visible = stack.shouldBeVisible(null); // A stack might be not attached to a display. - info.position = display != null ? display.mStacks.indexOf(stack) : 0; + info.position = display != null ? display.getIndexOf(stack) : 0; info.configuration.setTo(stack.getConfiguration()); ArrayList<TaskRecord> tasks = stack.getAllTasks(); @@ -4281,25 +4269,25 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ArrayList<StackInfo> getAllStackInfosLocked() { ArrayList<StackInfo> list = new ArrayList<>(); for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { - ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; - for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) { - list.add(getStackInfo(stacks.get(ndx))); + final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + list.add(getStackInfo(stack)); } } return list; } void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode, - int preferredDisplayId, int actualStackId) { + int preferredDisplayId, ActivityStack actualStack) { handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId, - actualStackId, false /* forceNonResizable */); + actualStack, false /* forceNonResizable */); } void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode, - int preferredDisplayId, int actualStackId, boolean forceNonResizable) { + int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) { final boolean isSecondaryDisplayPreferred = (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY); - final ActivityStack actualStack = getStack(actualStackId); final boolean inSplitScreenMode = actualStack != null && actualStack.inSplitScreenWindowingMode(); if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) @@ -4315,8 +4303,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // The task landed on an inappropriate display somehow, move it to the default // display. // TODO(multi-display): Find proper stack for the task on the default display. - mService.moveTaskToStack(task.taskId, FULLSCREEN_WORKSPACE_STACK_ID, - true /* toTop */); + mService.setTaskWindowingMode(task.taskId, + WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */); launchOnSecondaryDisplayFailed = true; } else { // The task might have landed on a display different from requested. @@ -4346,10 +4334,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Dismiss docked stack. If task appeared to be in docked stack but is not resizable - // we need to move it to top of fullscreen stack, otherwise it will be covered. - final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenStack(); + final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenPrimaryStack(); if (dockedStack != null) { - moveTasksToFullscreenStackLocked(dockedStack, - actualStackId == dockedStack.getStackId()); + moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack); } } else if (topActivity != null && topActivity.isNonResizableOrForcedResizable() && !topActivity.noDisplay) { @@ -4402,7 +4389,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, ActivityStack prevStack) { final ActivityStack stack = task.getStack(); if (prevStack == null || prevStack == stack - || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) { + || (!prevStack.inPinnedWindowingMode() && !stack.inPinnedWindowingMode())) { return; } @@ -4561,14 +4548,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (display == null) { return null; } - final ArrayList<ActivityStack> stacks = display.mStacks; - for (int i = stacks.size() - 1; i >= 0; i--) { - if (stacks.get(i) == stack && i > 0) { - return stacks.get(i - 1); + for (int i = display.getChildCount() - 1; i >= 0; i--) { + if (display.getChildAt(i) == stack && i > 0) { + return display.getChildAt(i - 1); } } throw new IllegalStateException("Failed to find a stack behind stack=" + stack - + " in=" + stacks); + + " in=" + display); } /** @@ -4681,8 +4667,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D for (int i = mActivityDisplays.size() - 1; i >= 0; i--) { final ActivityDisplay display = mActivityDisplays.valueAt(i); // Traverse all stacks on a display. - for (int j = display.mStacks.size() - 1; j >= 0; j--) { - final ActivityStack stack = display.mStacks.get(j); + for (int j = display.getChildCount() - 1; j >= 0; --j) { + final ActivityStack stack = display.getChildAt(j); // Get top activity from a visible stack and add it to the list. if (stack.shouldBeVisible(null /* starting */)) { final ActivityRecord top = stack.topActivity(); diff --git a/com/android/server/am/ActivityStarter.java b/com/android/server/am/ActivityStarter.java index d444c663..6f74d851 100644 --- a/com/android/server/am/ActivityStarter.java +++ b/com/android/server/am/ActivityStarter.java @@ -26,15 +26,9 @@ import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER; import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; -import static android.app.ActivityManager.StackId; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.ActivityManager.StackId.isDynamicStack; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; @@ -121,7 +115,6 @@ import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; import com.android.server.pm.InstantAppResolver; -import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; import java.text.DateFormat; @@ -140,11 +133,11 @@ class ActivityStarter { private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; + private static final int INVALID_LAUNCH_MODE = -1; private final ActivityManagerService mService; private final ActivityStackSupervisor mSupervisor; private final ActivityStartInterceptor mInterceptor; - private WindowManagerService mWindowManager; final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>(); @@ -154,9 +147,7 @@ class ActivityStarter { private int mCallingUid; private ActivityOptions mOptions; - private boolean mLaunchSingleTop; - private boolean mLaunchSingleInstance; - private boolean mLaunchSingleTask; + private int mLaunchMode; private boolean mLaunchTaskBehind; private int mLaunchFlags; @@ -166,6 +157,7 @@ class ActivityStarter { private boolean mDoResume; private int mStartFlags; private ActivityRecord mSourceRecord; + // The display to launch the activity onto, barring any strong reason to do otherwise. private int mPreferredDisplayId; @@ -195,8 +187,6 @@ class ActivityStarter { private IVoiceInteractionSession mVoiceSession; private IVoiceInteractor mVoiceInteractor; - private boolean mUsingVr2dDisplay; - // Last home activity record we attempted to start private final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1]; // The result of the last home activity we attempted to start. @@ -216,11 +206,9 @@ class ActivityStarter { mCallingUid = -1; mOptions = null; - mLaunchSingleTop = false; - mLaunchSingleInstance = false; - mLaunchSingleTask = false; mLaunchTaskBehind = false; mLaunchFlags = 0; + mLaunchMode = INVALID_LAUNCH_MODE; mLaunchBounds = null; @@ -248,16 +236,13 @@ class ActivityStarter { mVoiceSession = null; mVoiceInteractor = null; - mUsingVr2dDisplay = false; - mIntentDelivered = false; } - ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) { + ActivityStarter(ActivityManagerService service) { mService = service; - mSupervisor = supervisor; + mSupervisor = mService.mStackSupervisor; mInterceptor = new ActivityStartInterceptor(mService, mSupervisor); - mUsingVr2dDisplay = false; } int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent, @@ -610,38 +595,41 @@ class ActivityStarter { mSupervisor.reportTaskToFrontNoLaunch(mStartActivity); } - int startedActivityStackId = INVALID_STACK_ID; + ActivityStack startedActivityStack = null; final ActivityStack currentStack = r.getStack(); if (currentStack != null) { - startedActivityStackId = currentStack.mStackId; + startedActivityStack = currentStack; } else if (mTargetStack != null) { - startedActivityStackId = targetStack.mStackId; + startedActivityStack = targetStack; } - if (startedActivityStackId == DOCKED_STACK_ID) { - final ActivityStack homeStack = mSupervisor.getDefaultDisplay().getStack( - WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME); + if (startedActivityStack == null) { + return; + } + + if (startedActivityStack.inSplitScreenPrimaryWindowingMode()) { + final ActivityStack homeStack = mSupervisor.mHomeStack; final boolean homeStackVisible = homeStack != null && homeStack.isVisible(); if (homeStackVisible) { // We launch an activity while being in home stack, which means either launcher or // recents into docked stack. We don't want the launched activity to be alone in a // docked stack, so we want to immediately launch recents too. if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch."); - mWindowManager.showRecentApps(true /* fromHome */); + mService.mWindowManager.showRecentApps(true /* fromHome */); } return; } boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK) && (mReuseTask != null); - if (startedActivityStackId == PINNED_STACK_ID && (result == START_TASK_TO_FRONT - || result == START_DELIVERED_TO_TOP || clearedTask)) { + if (startedActivityStack.inPinnedWindowingMode() + && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP + || clearedTask)) { // The activity was already running in the pinned stack so it wasn't started, but either // brought to the front or the new intent was delivered to it since it was already in // front. Notify anyone interested in this piece of information. mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt( clearedTask); - return; } } @@ -1062,7 +1050,7 @@ class ActivityStarter { // operations. if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 || isDocumentLaunchesIntoExisting(mLaunchFlags) - || mLaunchSingleInstance || mLaunchSingleTask) { + || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { final TaskRecord task = reusedActivity.getTask(); // In this situation we want to remove all activities from the task up to the one @@ -1145,7 +1133,7 @@ class ActivityStarter { && top.userId == mStartActivity.userId && top.app != null && top.app.thread != null && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 - || mLaunchSingleTop || mLaunchSingleTask); + || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)); if (dontStart) { // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; @@ -1164,7 +1152,7 @@ class ActivityStarter { // Don't use mStartActivity.task to show the toast. We're not starting a new activity // but reusing 'top'. Fields in mStartActivity may not be fully initialized. mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode, - preferredLaunchDisplayId, topStack.mStackId); + preferredLaunchDisplayId, topStack); return START_DELIVERED_TO_TOP; } @@ -1227,7 +1215,7 @@ class ActivityStarter { mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); // Go ahead and tell window manager to execute app transition for this activity // since the app transition will not be triggered through the resume channel. - mWindowManager.executeAppTransition(); + mService.mWindowManager.executeAppTransition(); } else { // If the target stack was not previously focusable (previous top running activity // on that stack was not visible) then any prior calls to move the stack to the @@ -1240,13 +1228,13 @@ class ActivityStarter { mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); } - } else { - mSupervisor.addRecentActivity(mStartActivity); + } else if (mStartActivity != null) { + mSupervisor.mRecentTasks.add(mStartActivity.getTask()); } mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack); mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode, - preferredLaunchDisplayId, mTargetStack.mStackId); + preferredLaunchDisplayId, mTargetStack); return START_SUCCESS; } @@ -1268,13 +1256,13 @@ class ActivityStarter { mLaunchBounds = getOverrideBounds(r, options, inTask); - mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP; - mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE; - mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK; + mLaunchMode = r.launchMode; + mLaunchFlags = adjustLaunchFlagsToDocumentMode( - r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags()); + r, LAUNCH_SINGLE_INSTANCE == mLaunchMode, + LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags()); mLaunchTaskBehind = r.mLaunchTaskBehind - && !mLaunchSingleTask && !mLaunchSingleInstance + && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE) && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0; sendNewTaskResultRequestIfNeeded(); @@ -1384,7 +1372,7 @@ class ActivityStarter { // If this task is empty, then we are adding the first activity -- it // determines the root, and must be launching as a NEW_TASK. - if (mLaunchSingleInstance || mLaunchSingleTask) { + if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) { ActivityOptions.abort(mOptions); throw new IllegalArgumentException("Trying to launch singleInstance/Task " @@ -1427,7 +1415,7 @@ class ActivityStarter { // in any task/stack, however it could launch other activities like ResolverActivity, // and we want those to stay in the original task. if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null - && mSourceRecord.isFreeform()) { + && mSourceRecord.inFreeformWindowingMode()) { mAddingToTask = true; } } @@ -1446,7 +1434,7 @@ class ActivityStarter { // instance... this new activity it is starting must go on its // own task. mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; - } else if (mLaunchSingleInstance || mLaunchSingleTask) { + } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { // The activity being started is a single instance... it always // gets launched into its own task. mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; @@ -1497,7 +1485,7 @@ class ActivityStarter { // launch this as a new task behind the current one. boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 && (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0) - || mLaunchSingleInstance || mLaunchSingleTask; + || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK); // If bring to front is requested, and no result is requested and we have not been given // an explicit task to launch in to, and we can find a task that was started with this // same component, then instead of launching bring that one to the front. @@ -1507,7 +1495,7 @@ class ActivityStarter { final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId()); intentActivity = task != null ? task.getTopActivity() : null; } else if (putIntoExistingTask) { - if (mLaunchSingleInstance) { + if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) { // There can be one and only one instance of single instance activity in the // history, and it is always in its own unique task, so we do a special search. intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, @@ -1516,7 +1504,7 @@ class ActivityStarter { // For the launch adjacent case we only want to put the activity in an existing // task if the activity already exists in the history. intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, - !mLaunchSingleTask); + !(LAUNCH_SINGLE_TASK == mLaunchMode)); } else { // Otherwise find the best task to put the activity in. intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId); @@ -1545,7 +1533,6 @@ class ActivityStarter { if (DEBUG_STACK) { Slog.d(TAG, "getSourceDisplayId :" + displayId); } - mUsingVr2dDisplay = true; return displayId; } @@ -1667,7 +1654,7 @@ class ActivityStarter { } mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), - WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack.mStackId); + WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack); // If the caller has requested that the target task be reset, then do so. if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { @@ -1719,7 +1706,7 @@ class ActivityStarter { // mTaskToReturnTo values and we don't want to overwrite them accidentally. mMovedOtherTask = true; } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 - || mLaunchSingleInstance || mLaunchSingleTask) { + || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity, mLaunchFlags); if (top == null) { @@ -1748,7 +1735,8 @@ class ActivityStarter { // 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 (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop) + if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 + || LAUNCH_SINGLE_TOP == mLaunchMode) && intentActivity.realActivity.equals(mStartActivity.realActivity)) { if (intentActivity.frontOfTask) { intentActivity.getTask().setIntent(mStartActivity); @@ -1952,7 +1940,7 @@ class ActivityStarter { if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) { if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 - || mLaunchSingleTop || mLaunchSingleTask) { + || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)) { mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront"); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { @@ -2001,9 +1989,9 @@ class ActivityStarter { return; } - final int stackId = task.getStackId(); - if (StackId.resizeStackWithLaunchBounds(stackId)) { - mService.resizeStack(stackId, bounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); + final ActivityStack stack = task.getStack(); + if (stack != null && stack.resizeStackWithLaunchBounds()) { + mService.resizeStack(stack.mStackId, bounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); } else { task.updateOverrideConfiguration(bounds); } @@ -2115,11 +2103,10 @@ class ActivityStarter { } if (stack == null) { // We first try to put the task in the first dynamic stack on home display. - final ArrayList<ActivityStack> homeDisplayStacks = - mSupervisor.getStacksOnDefaultDisplay(); - for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) { - stack = homeDisplayStacks.get(stackNdx); - if (isDynamicStack(stack.mStackId)) { + final ActivityDisplay display = mSupervisor.getDefaultDisplay(); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + stack = display.getChildAt(stackNdx); + if (!stack.isOnHomeDisplay()) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: Setting focused stack=" + stack); return stack; @@ -2138,7 +2125,6 @@ class ActivityStarter { private boolean canLaunchIntoFocusedStack(ActivityRecord r, boolean newTask) { final ActivityStack focusedStack = mSupervisor.mFocusedStack; final boolean canUseFocusedStack; - final int focusedStackId = mSupervisor.mFocusedStack.mStackId; if (focusedStack.isActivityTypeAssistant()) { canUseFocusedStack = r.isActivityTypeAssistant(); } else { @@ -2161,7 +2147,7 @@ class ActivityStarter { default: // Dynamic stacks behave similarly to the fullscreen stack and can contain any // resizeable task. - canUseFocusedStack = isDynamicStack(focusedStackId) + canUseFocusedStack = !focusedStack.isOnHomeDisplay() && r.canBeLaunchedOnDisplay(focusedStack.mDisplayId); } } @@ -2177,7 +2163,8 @@ class ActivityStarter { return mReuseTask.getStack(); } - final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY; + final int vrDisplayId = mPreferredDisplayId == mService.mVr2dDisplayId + ? mPreferredDisplayId : INVALID_DISPLAY; final ActivityStack launchStack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP, vrDisplayId); @@ -2205,7 +2192,7 @@ class ActivityStarter { return mSupervisor.mFocusedStack; } - if (parentStack != null && parentStack.isDockedStack()) { + if (parentStack != null && parentStack.inSplitScreenPrimaryWindowingMode()) { // If parent was in docked stack, the natural place to launch another activity // will be fullscreen, so it can appear alongside the docked window. final int activityType = mSupervisor.resolveActivityType(r, mOptions, task); @@ -2215,8 +2202,8 @@ class ActivityStarter { // If the parent is not in the docked stack, we check if there is docked window // and if yes, we will launch into that stack. If not, we just put the new // activity into parent's stack, because we can't find a better place. - final ActivityStack dockedStack = mSupervisor.getDefaultDisplay().getStack( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); + final ActivityStack dockedStack = + mSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); if (dockedStack != null && !dockedStack.shouldBeVisible(r)) { // There is a docked stack, but it isn't visible, so we can't launch into that. return null; @@ -2236,8 +2223,8 @@ class ActivityStarter { return newBounds; } - void setWindowManager(WindowManagerService wm) { - mWindowManager = wm; + private boolean isLaunchModeOneOf(int mode1, int mode2) { + return mode1 == mLaunchMode || mode2 == mLaunchMode; } static boolean isDocumentLaunchesIntoExisting(int flags) { @@ -2318,11 +2305,11 @@ class ActivityStarter { } pw.print(prefix); pw.print("mLaunchSingleTop="); - pw.print(mLaunchSingleTop); + pw.print(LAUNCH_SINGLE_TOP == mLaunchMode); pw.print(" mLaunchSingleInstance="); - pw.print(mLaunchSingleInstance); + pw.print(LAUNCH_SINGLE_INSTANCE == mLaunchMode); pw.print(" mLaunchSingleTask="); - pw.println(mLaunchSingleTask); + pw.println(LAUNCH_SINGLE_TASK == mLaunchMode); pw.print(prefix); pw.print("mLaunchFlags=0x"); pw.print(Integer.toHexString(mLaunchFlags)); diff --git a/com/android/server/am/AppTaskImpl.java b/com/android/server/am/AppTaskImpl.java new file mode 100644 index 00000000..a4e2e70e --- /dev/null +++ b/com/android/server/am/AppTaskImpl.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; + +import android.app.ActivityManager; +import android.app.IAppTask; +import android.app.IApplicationThread; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.UserHandle; + +/** + * An implementation of IAppTask, that allows an app to manage its own tasks via + * {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that + * only the process that calls getAppTasks() can call the AppTask methods. + */ +class AppTaskImpl extends IAppTask.Stub { + private ActivityManagerService mService; + + private int mTaskId; + private int mCallingUid; + + public AppTaskImpl(ActivityManagerService service, int taskId, int callingUid) { + mService = service; + mTaskId = taskId; + mCallingUid = callingUid; + } + + private void checkCaller() { + if (mCallingUid != Binder.getCallingUid()) { + throw new SecurityException("Caller " + mCallingUid + + " does not match caller of getAppTasks(): " + Binder.getCallingUid()); + } + } + + @Override + public void finishAndRemoveTask() { + checkCaller(); + + synchronized (mService) { + long origId = Binder.clearCallingIdentity(); + try { + // We remove the task from recents to preserve backwards + if (!mService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false, + REMOVE_FROM_RECENTS)) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + @Override + public ActivityManager.RecentTaskInfo getTaskInfo() { + checkCaller(); + + synchronized (mService) { + long origId = Binder.clearCallingIdentity(); + try { + TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId); + if (tr == null) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + return RecentTasks.createRecentTaskInfo(tr); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + @Override + public void moveToFront() { + checkCaller(); + // Will bring task to front if it already has a root activity. + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (this) { + mService.mStackSupervisor.startActivityFromRecentsInner(mTaskId, null); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + @Override + public int startActivity(IBinder whoThread, String callingPackage, + Intent intent, String resolvedType, Bundle bOptions) { + checkCaller(); + + int callingUser = UserHandle.getCallingUserId(); + TaskRecord tr; + IApplicationThread appThread; + synchronized (mService) { + tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId); + if (tr == null) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + appThread = IApplicationThread.Stub.asInterface(whoThread); + if (appThread == null) { + throw new IllegalArgumentException("Bad app thread " + appThread); + } + } + return mService.mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, + intent, resolvedType, null, null, null, null, 0, 0, null, null, + null, bOptions, false, callingUser, tr, "AppTaskImpl"); + } + + @Override + public void setExcludeFromRecents(boolean exclude) { + checkCaller(); + + synchronized (mService) { + long origId = Binder.clearCallingIdentity(); + try { + TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId); + if (tr == null) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + Intent intent = tr.getBaseIntent(); + if (exclude) { + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + } else { + intent.setFlags(intent.getFlags() + & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } +}
\ No newline at end of file diff --git a/com/android/server/am/BatteryStatsService.java b/com/android/server/am/BatteryStatsService.java index 7c9cd00e..68ed9aec 100644 --- a/com/android/server/am/BatteryStatsService.java +++ b/com/android/server/am/BatteryStatsService.java @@ -297,26 +297,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub void noteProcessStart(String name, int uid) { synchronized (mStats) { mStats.noteProcessStartLocked(name, uid); - - // TODO: remove this once we figure out properly where and how - // PROCESS_EVENT = 1112 - // KEY_STATE = 1 - // KEY_PACKAGE_NAME: 1002 - // KEY_UID: 2 - StatsLog.writeArray(1112, 1, 1, 1002, name, 2, uid); } } void noteProcessCrash(String name, int uid) { synchronized (mStats) { mStats.noteProcessCrashLocked(name, uid); - - // TODO: remove this once we figure out properly where and how - // PROCESS_EVENT = 1112 - // KEY_STATE = 1 - // KEY_PACKAGE_NAME: 1002 - // KEY_UID: 2 - StatsLog.writeArray(1112, 1, 2, 1002, name, 2, uid); } } @@ -334,6 +320,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub void noteUidProcessState(int uid, int state) { synchronized (mStats) { + // TODO: remove this once we figure out properly where and how + StatsLog.write(StatsLog.PROCESS_STATE_CHANGED, uid, state); + mStats.noteUidProcessStateLocked(uid, state); } } @@ -548,12 +537,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub enforceCallingPermission(); if (DBG) Slog.d(TAG, "begin noteScreenState"); synchronized (mStats) { - mStats.noteScreenStateLocked(state); // TODO: remove this once we figure out properly where and how - // SCREEN_EVENT = 2 - // KEY_STATE: 1 - // State value: state. We can change this to our own def later. - StatsLog.writeArray(2, 1, state); + StatsLog.write(StatsLog.SCREEN_STATE_CHANGED, state); + + mStats.noteScreenStateLocked(state); } if (DBG) Slog.d(TAG, "end noteScreenState"); } diff --git a/com/android/server/am/BroadcastFilter.java b/com/android/server/am/BroadcastFilter.java index f96b06fa..7ff227f5 100644 --- a/com/android/server/am/BroadcastFilter.java +++ b/com/android/server/am/BroadcastFilter.java @@ -19,6 +19,9 @@ package com.android.server.am; import android.content.IntentFilter; import android.util.PrintWriterPrinter; import android.util.Printer; +import android.util.proto.ProtoOutputStream; + +import com.android.server.am.proto.BroadcastFilterProto; import java.io.PrintWriter; @@ -44,27 +47,38 @@ final class BroadcastFilter extends IntentFilter { instantApp = _instantApp; visibleToInstantApp = _visibleToInstantApp; } - + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + long token = proto.start(fieldId); + super.writeToProto(proto, BroadcastFilterProto.INTENT_FILTER); + if (requiredPermission != null) { + proto.write(BroadcastFilterProto.REQUIRED_PERMISSION, requiredPermission); + } + proto.write(BroadcastFilterProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this))); + proto.write(BroadcastFilterProto.OWNING_USER_ID, owningUserId); + proto.end(token); + } + public void dump(PrintWriter pw, String prefix) { dumpInReceiverList(pw, new PrintWriterPrinter(pw), prefix); receiverList.dumpLocal(pw, prefix); } - + public void dumpBrief(PrintWriter pw, String prefix) { dumpBroadcastFilterState(pw, prefix); } - + public void dumpInReceiverList(PrintWriter pw, Printer pr, String prefix) { super.dump(pr, prefix); dumpBroadcastFilterState(pw, prefix); } - + void dumpBroadcastFilterState(PrintWriter pw, String prefix) { if (requiredPermission != null) { pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission); } } - + public String toString() { StringBuilder sb = new StringBuilder(); sb.append("BroadcastFilter{"); diff --git a/com/android/server/am/BroadcastQueue.java b/com/android/server/am/BroadcastQueue.java index d8354549..c62cc38b 100644 --- a/com/android/server/am/BroadcastQueue.java +++ b/com/android/server/am/BroadcastQueue.java @@ -51,9 +51,12 @@ import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; import static com.android.server.am.ActivityManagerDebugConfig.*; +import com.android.server.am.proto.BroadcastQueueProto; + /** * BROADCASTS * @@ -1585,6 +1588,55 @@ public final class BroadcastQueue { && (mPendingBroadcast == null); } + void writeToProto(ProtoOutputStream proto, long fieldId) { + long token = proto.start(fieldId); + proto.write(BroadcastQueueProto.QUEUE_NAME, mQueueName); + int N; + N = mParallelBroadcasts.size(); + for (int i = N - 1; i >= 0; i--) { + mParallelBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.PARALLEL_BROADCASTS); + } + N = mOrderedBroadcasts.size(); + for (int i = N - 1; i >= 0; i--) { + mOrderedBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS); + } + if (mPendingBroadcast != null) { + mPendingBroadcast.writeToProto(proto, BroadcastQueueProto.PENDING_BROADCAST); + } + + int lastIndex = mHistoryNext; + int ringIndex = lastIndex; + do { + // increasing index = more recent entry, and we want to print the most + // recent first and work backwards, so we roll through the ring backwards. + ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY); + BroadcastRecord r = mBroadcastHistory[ringIndex]; + if (r != null) { + r.writeToProto(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS); + } + } while (ringIndex != lastIndex); + + lastIndex = ringIndex = mSummaryHistoryNext; + do { + ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY); + Intent intent = mBroadcastSummaryHistory[ringIndex]; + if (intent == null) { + continue; + } + long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY); + intent.writeToProto(proto, BroadcastQueueProto.BroadcastSummary.INTENT, + false, true, true, false); + proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS, + mSummaryHistoryEnqueueTime[ringIndex]); + proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS, + mSummaryHistoryDispatchTime[ringIndex]); + proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS, + mSummaryHistoryFinishTime[ringIndex]); + proto.end(summaryToken); + } while (ringIndex != lastIndex); + proto.end(token); + } + final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage, boolean needSep) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); diff --git a/com/android/server/am/BroadcastRecord.java b/com/android/server/am/BroadcastRecord.java index 6bc0744f..5b3b2a8e 100644 --- a/com/android/server/am/BroadcastRecord.java +++ b/com/android/server/am/BroadcastRecord.java @@ -30,6 +30,9 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.PrintWriterPrinter; import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; + +import com.android.server.am.proto.BroadcastRecordProto; import java.io.PrintWriter; import java.text.SimpleDateFormat; @@ -331,9 +334,17 @@ final class BroadcastRecord extends Binder { return didSomething; } + @Override public String toString() { return "BroadcastRecord{" + Integer.toHexString(System.identityHashCode(this)) + " u" + userId + " " + intent.getAction() + "}"; } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + long token = proto.start(fieldId); + proto.write(BroadcastRecordProto.USER_ID, userId); + proto.write(BroadcastRecordProto.INTENT_ACTION, intent.getAction()); + proto.end(token); + } } diff --git a/com/android/server/am/KeyguardController.java b/com/android/server/am/KeyguardController.java index 5c48f90d..c3fed171 100644 --- a/com/android/server/am/KeyguardController.java +++ b/com/android/server/am/KeyguardController.java @@ -16,7 +16,6 @@ package com.android.server.am; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -47,7 +46,6 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; -import java.util.ArrayList; /** * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are @@ -238,9 +236,9 @@ class KeyguardController { final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity; mOccluded = false; mDismissingKeyguardActivity = null; - final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay(); - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); + final ActivityDisplay display = mStackSupervisor.getDefaultDisplay(); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); // Only the focused stack top activity may control occluded state if (mStackSupervisor.isFocusedStack(stack)) { @@ -342,7 +340,7 @@ class KeyguardController { // show on top of the lock screen. In this can we want to dismiss the docked // stack since it will be complicated/risky to try to put the activity on top // of the lock screen in the right fullscreen configuration. - final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenStack(); + final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); if (stack == null) { return; } diff --git a/com/android/server/am/LaunchingTaskPositioner.java b/com/android/server/am/LaunchingTaskPositioner.java index d6523418..0dc73e98 100644 --- a/com/android/server/am/LaunchingTaskPositioner.java +++ b/com/android/server/am/LaunchingTaskPositioner.java @@ -24,8 +24,8 @@ import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; import android.util.Slog; -import android.view.Display; import android.view.Gravity; +import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; @@ -64,43 +64,11 @@ class LaunchingTaskPositioner { private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2; private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3; - private boolean mDefaultStartBoundsConfigurationSet = false; private final Rect mAvailableRect = new Rect(); private final Rect mTmpProposal = new Rect(); private final Rect mTmpOriginal = new Rect(); - private int mDefaultFreeformStartX; - private int mDefaultFreeformStartY; - private int mDefaultFreeformWidth; - private int mDefaultFreeformHeight; - private int mDefaultFreeformStepHorizontal; - private int mDefaultFreeformStepVertical; - private int mDisplayWidth; - private int mDisplayHeight; - - void setDisplay(Display display) { - Point size = new Point(); - display.getSize(size); - mDisplayWidth = size.x; - mDisplayHeight = size.y; - } - - void configure(Rect stackBounds) { - if (stackBounds == null) { - mAvailableRect.set(0, 0, mDisplayWidth, mDisplayHeight); - } else { - mAvailableRect.set(stackBounds); - } - int width = mAvailableRect.width(); - int height = mAvailableRect.height(); - mDefaultFreeformStartX = mAvailableRect.left + width / MARGIN_SIZE_DENOMINATOR; - mDefaultFreeformStartY = mAvailableRect.top + height / MARGIN_SIZE_DENOMINATOR; - mDefaultFreeformWidth = width / WINDOW_SIZE_DENOMINATOR; - mDefaultFreeformHeight = height / WINDOW_SIZE_DENOMINATOR; - mDefaultFreeformStepHorizontal = Math.max(width / STEP_DENOMINATOR, MINIMAL_STEP); - mDefaultFreeformStepVertical = Math.max(height / STEP_DENOMINATOR, MINIMAL_STEP); - mDefaultStartBoundsConfigurationSet = true; - } + private final Point mDisplaySize = new Point(); /** * Tries to set task's bound in a way that it won't collide with any other task. By colliding @@ -114,104 +82,154 @@ class LaunchingTaskPositioner { */ void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks, @Nullable ActivityInfo.WindowLayout windowLayout) { - if (!mDefaultStartBoundsConfigurationSet) { - return; - } + updateAvailableRect(task, mAvailableRect); + if (windowLayout == null) { - positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight); + positionCenter(task, tasks, mAvailableRect, getFreeformWidth(mAvailableRect), + getFreeformHeight(mAvailableRect)); return; } - int width = getFinalWidth(windowLayout); - int height = getFinalHeight(windowLayout); + int width = getFinalWidth(windowLayout, mAvailableRect); + int height = getFinalHeight(windowLayout, mAvailableRect); int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK; int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (verticalGravity == Gravity.TOP) { if (horizontalGravity == Gravity.RIGHT) { - positionTopRight(task, tasks, width, height); + positionTopRight(task, tasks, mAvailableRect, width, height); } else { - positionTopLeft(task, tasks, width, height); + positionTopLeft(task, tasks, mAvailableRect, width, height); } } else if (verticalGravity == Gravity.BOTTOM) { if (horizontalGravity == Gravity.RIGHT) { - positionBottomRight(task, tasks, width, height); + positionBottomRight(task, tasks, mAvailableRect, width, height); } else { - positionBottomLeft(task, tasks, width, height); + positionBottomLeft(task, tasks, mAvailableRect, width, height); } } else { // Some fancy gravity setting that we don't support yet. We just put the activity in the // center. Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity + ", positioning in the center instead."); - positionCenter(task, tasks, width, height); + positionCenter(task, tasks, mAvailableRect, width, height); } } - private int getFinalWidth(ActivityInfo.WindowLayout windowLayout) { - int width = mDefaultFreeformWidth; + private void updateAvailableRect(TaskRecord task, Rect availableRect) { + final Rect stackBounds = task.getStack().mBounds; + + if (stackBounds != null) { + availableRect.set(stackBounds); + } else { + task.getStack().getDisplay().mDisplay.getSize(mDisplaySize); + availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); + } + } + + @VisibleForTesting + static int getFreeformStartLeft(Rect bounds) { + return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR; + } + + @VisibleForTesting + static int getFreeformStartTop(Rect bounds) { + return bounds.top + bounds.height() / MARGIN_SIZE_DENOMINATOR; + } + + @VisibleForTesting + static int getFreeformWidth(Rect bounds) { + return bounds.width() / WINDOW_SIZE_DENOMINATOR; + } + + @VisibleForTesting + static int getFreeformHeight(Rect bounds) { + return bounds.height() / WINDOW_SIZE_DENOMINATOR; + } + + @VisibleForTesting + static int getHorizontalStep(Rect bounds) { + return Math.max(bounds.width() / STEP_DENOMINATOR, MINIMAL_STEP); + } + + @VisibleForTesting + static int getVerticalStep(Rect bounds) { + return Math.max(bounds.height() / STEP_DENOMINATOR, MINIMAL_STEP); + } + + + + private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) { + int width = getFreeformWidth(availableRect); if (windowLayout.width > 0) { width = windowLayout.width; } if (windowLayout.widthFraction > 0) { - width = (int) (mAvailableRect.width() * windowLayout.widthFraction); + width = (int) (availableRect.width() * windowLayout.widthFraction); } return width; } - private int getFinalHeight(ActivityInfo.WindowLayout windowLayout) { - int height = mDefaultFreeformHeight; + private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) { + int height = getFreeformHeight(availableRect); if (windowLayout.height > 0) { height = windowLayout.height; } if (windowLayout.heightFraction > 0) { - height = (int) (mAvailableRect.height() * windowLayout.heightFraction); + height = (int) (availableRect.height() * windowLayout.heightFraction); } return height; } - private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height, - mAvailableRect.left + width, mAvailableRect.bottom); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT); + private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.left, availableRect.bottom - height, + availableRect.left + width, availableRect.bottom); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_RIGHT); } - private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height, - mAvailableRect.right, mAvailableRect.bottom); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT); + private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.right - width, availableRect.bottom - height, + availableRect.right, availableRect.bottom); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_LEFT); } - private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.left, mAvailableRect.top, - mAvailableRect.left + width, mAvailableRect.top + height); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT); + private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.left, availableRect.top, + availableRect.left + width, availableRect.top + height); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_RIGHT); } - private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top, - mAvailableRect.right, mAvailableRect.top + height); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT); + private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.right - width, availableRect.top, + availableRect.right, availableRect.top + height); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_LEFT); } - private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY, - mDefaultFreeformStartX + width, mDefaultFreeformStartY + height); - position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN); + private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + final int defaultFreeformLeft = getFreeformStartLeft(availableRect); + final int defaultFreeformTop = getFreeformStartTop(availableRect); + mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop, + defaultFreeformLeft + width, defaultFreeformTop + height); + position(task, tasks, availableRect, mTmpProposal, ALLOW_RESTART, + SHIFT_POLICY_DIAGONAL_DOWN); } - private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal, - boolean allowRestart, int shiftPolicy) { + private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect availableRect, + Rect proposal, boolean allowRestart, int shiftPolicy) { mTmpOriginal.set(proposal); boolean restarted = false; while (boundsConflict(proposal, tasks)) { // Unfortunately there is already a task at that spot, so we need to look for some // other place. - shiftStartingPoint(proposal, shiftPolicy); - if (shiftedToFar(proposal, shiftPolicy)) { + shiftStartingPoint(proposal, availableRect, shiftPolicy); + if (shiftedTooFar(proposal, availableRect, shiftPolicy)) { // We don't want the task to go outside of the stack, because it won't look // nice. Depending on the starting point we either restart, or immediately give up. if (!allowRestart) { @@ -220,13 +238,13 @@ class LaunchingTaskPositioner { } // We must have started not from the top. Let's restart from there because there // might be some space there. - proposal.set(mAvailableRect.left, mAvailableRect.top, - mAvailableRect.left + proposal.width(), - mAvailableRect.top + proposal.height()); + proposal.set(availableRect.left, availableRect.top, + availableRect.left + proposal.width(), + availableRect.top + proposal.height()); restarted = true; } - if (restarted && (proposal.left > mDefaultFreeformStartX - || proposal.top > mDefaultFreeformStartY)) { + if (restarted && (proposal.left > getFreeformStartLeft(availableRect) + || proposal.top > getFreeformStartTop(availableRect))) { // If we restarted and crossed the initial position, let's not struggle anymore. // The user already must have ton of tasks visible, we can just smack the new // one in the center. @@ -237,27 +255,30 @@ class LaunchingTaskPositioner { task.updateOverrideConfiguration(proposal); } - private boolean shiftedToFar(Rect start, int shiftPolicy) { + private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) { switch (shiftPolicy) { case SHIFT_POLICY_HORIZONTAL_LEFT: - return start.left < mAvailableRect.left; + return start.left < availableRect.left; case SHIFT_POLICY_HORIZONTAL_RIGHT: - return start.right > mAvailableRect.right; + return start.right > availableRect.right; default: // SHIFT_POLICY_DIAGONAL_DOWN - return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom; + return start.right > availableRect.right || start.bottom > availableRect.bottom; } } - private void shiftStartingPoint(Rect posposal, int shiftPolicy) { + private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) { + final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect); + final int defaultFreeformStepVertical = getVerticalStep(availableRect); + switch (shiftPolicy) { case SHIFT_POLICY_HORIZONTAL_LEFT: - posposal.offset(-mDefaultFreeformStepHorizontal, 0); + posposal.offset(-defaultFreeformStepHorizontal, 0); break; case SHIFT_POLICY_HORIZONTAL_RIGHT: - posposal.offset(mDefaultFreeformStepHorizontal, 0); + posposal.offset(defaultFreeformStepHorizontal, 0); break; default: // SHIFT_POLICY_DIAGONAL_DOWN: - posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical); + posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical); break; } } @@ -296,8 +317,4 @@ class LaunchingTaskPositioner { return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE; } - - void reset() { - mDefaultStartBoundsConfigurationSet = false; - } } diff --git a/com/android/server/am/LockTaskController.java b/com/android/server/am/LockTaskController.java index 72b5de88..940f9051 100644 --- a/com/android/server/am/LockTaskController.java +++ b/com/android/server/am/LockTaskController.java @@ -19,7 +19,6 @@ package com.android.server.am; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.StatusBarManager.DISABLE_BACK; import static android.app.StatusBarManager.DISABLE_HOME; import static android.app.StatusBarManager.DISABLE_MASK; @@ -59,7 +58,6 @@ import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.widget.LockPatternUtils; @@ -433,7 +431,7 @@ public class LockTaskController { mWindowManager.executeAppTransition(); } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) { mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, - DEFAULT_DISPLAY, task.getStackId(), true /* forceNonResizable */); + DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */); } } @@ -494,11 +492,7 @@ public class LockTaskController { } for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) { - ArrayList<ActivityStack> stacks = mSupervisor.getChildAt(displayNdx).mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); - stack.onLockTaskPackagesUpdatedLocked(); - } + mSupervisor.getChildAt(displayNdx).onLockTaskPackagesUpdated(); } final ActivityRecord r = mSupervisor.topRunningActivityLocked(); diff --git a/com/android/server/am/ProcessRecord.java b/com/android/server/am/ProcessRecord.java index 0e318d9c..e8477231 100644 --- a/com/android/server/am/ProcessRecord.java +++ b/com/android/server/am/ProcessRecord.java @@ -27,6 +27,7 @@ import android.util.Slog; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.app.procstats.ProcessState; import com.android.internal.os.BatteryStatsImpl; +import com.android.server.am.proto.ProcessRecordProto; import android.app.ActivityManager; import android.app.Dialog; @@ -44,6 +45,7 @@ import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; import java.io.PrintWriter; import java.util.ArrayList; @@ -621,6 +623,22 @@ final class ProcessRecord { } } + public void writeToProto(ProtoOutputStream proto, long fieldId) { + long token = proto.start(fieldId); + proto.write(ProcessRecordProto.PID, pid); + proto.write(ProcessRecordProto.PROCESS_NAME, processName); + if (info.uid < Process.FIRST_APPLICATION_UID) { + proto.write(ProcessRecordProto.UID, uid); + } else { + proto.write(ProcessRecordProto.USER_ID, userId); + proto.write(ProcessRecordProto.APP_ID, UserHandle.getAppId(info.uid)); + if (uid != info.uid) { + proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid)); + } + } + proto.end(token); + } + public String toShortString() { if (shortStringName != null) { return shortStringName; diff --git a/com/android/server/am/ReceiverList.java b/com/android/server/am/ReceiverList.java index 6ade7361..a9890631 100644 --- a/com/android/server/am/ReceiverList.java +++ b/com/android/server/am/ReceiverList.java @@ -21,6 +21,8 @@ import android.os.Binder; import android.os.IBinder; import android.util.PrintWriterPrinter; import android.util.Printer; +import android.util.proto.ProtoOutputStream; +import com.android.server.am.proto.ReceiverListProto; import java.io.PrintWriter; import java.util.ArrayList; @@ -41,7 +43,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter> boolean linkedToDeath = false; String stringName; - + ReceiverList(ActivityManagerService _owner, ProcessRecord _app, int _pid, int _uid, int _userId, IIntentReceiver _receiver) { owner = _owner; @@ -59,12 +61,31 @@ final class ReceiverList extends ArrayList<BroadcastFilter> public int hashCode() { return System.identityHashCode(this); } - + public void binderDied() { linkedToDeath = false; owner.unregisterReceiver(receiver); } - + + void writeToProto(ProtoOutputStream proto, long fieldId) { + long token = proto.start(fieldId); + app.writeToProto(proto, ReceiverListProto.APP); + proto.write(ReceiverListProto.PID, pid); + proto.write(ReceiverListProto.UID, uid); + proto.write(ReceiverListProto.USER, userId); + if (curBroadcast != null) { + curBroadcast.writeToProto(proto, ReceiverListProto.CURRENT); + } + proto.write(ReceiverListProto.LINKED_TO_DEATH, linkedToDeath); + final int N = size(); + for (int i=0; i<N; i++) { + BroadcastFilter bf = get(i); + bf.writeToProto(proto, ReceiverListProto.FILTERS); + } + proto.write(ReceiverListProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this))); + proto.end(token); + } + void dumpLocal(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("app="); pw.print(app != null ? app.toShortString() : null); pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid); @@ -74,7 +95,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter> pw.print(" linkedToDeath="); pw.println(linkedToDeath); } } - + void dump(PrintWriter pw, String prefix) { Printer pr = new PrintWriterPrinter(pw); dumpLocal(pw, prefix); @@ -89,7 +110,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter> bf.dumpInReceiverList(pw, pr, p2); } } - + public String toString() { if (stringName != null) { return stringName; diff --git a/com/android/server/am/RecentTasks.java b/com/android/server/am/RecentTasks.java index 365c5b1d..78274bdc 100644 --- a/com/android/server/am/RecentTasks.java +++ b/com/android/server/am/RecentTasks.java @@ -16,15 +16,25 @@ package com.android.server.am; +import static android.app.ActivityManager.FLAG_AND_UNLOCKED; +import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; +import static android.app.ActivityManager.RECENT_WITH_EXCLUDED; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import com.google.android.collect.Sets; @@ -37,43 +47,87 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.UserInfo; +import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Rect; +import android.os.Bundle; import android.os.Environment; +import android.os.IBinder; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArraySet; +import android.util.MutableBoolean; +import android.util.MutableInt; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.am.ActivityStack.ActivityState; + import java.io.File; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Set; +import java.util.concurrent.TimeUnit; /** - * Class for managing the recent tasks list. + * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the + * least recent. */ -class RecentTasks extends ArrayList<TaskRecord> { +class RecentTasks { private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; private static final String TAG_TASKS = TAG + POSTFIX_TASKS; + private static final boolean TRIMMED = true; - // Maximum number recent bitmaps to keep in memory. - private static final int MAX_RECENT_BITMAPS = 3; private static final int DEFAULT_INITIAL_CAPACITY = 5; // Whether or not to move all affiliated tasks to the front when one of the tasks is launched private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false; + // Comparator to sort by taskId + private static final Comparator<TaskRecord> TASK_ID_COMPARATOR = + (lhs, rhs) -> rhs.taskId - lhs.taskId; + + // Placeholder variables to keep track of activities/apps that are no longer avialble while + // iterating through the recents list + private static final ActivityInfo NO_ACTIVITY_INFO_TOKEN = new ActivityInfo(); + private static final ApplicationInfo NO_APPLICATION_INFO_TOKEN = new ApplicationInfo(); + + /** + * Callbacks made when manipulating the list. + */ + interface Callbacks { + /** + * Called when a task is added to the recent tasks list. + */ + void onRecentTaskAdded(TaskRecord task); + + /** + * Called when a task is removed from the recent tasks list. + */ + void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed); + } + /** * Save recent tasks information across reboots. */ private final TaskPersister mTaskPersister; private final ActivityManagerService mService; + private final UserController mUserController; + + /** + * Mapping of user id -> whether recent tasks have been loaded for that user. + */ private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray( DEFAULT_INITIAL_CAPACITY); @@ -81,21 +135,106 @@ class RecentTasks extends ArrayList<TaskRecord> { * Stores for each user task ids that are taken by tasks residing in persistent storage. These * tasks may or may not currently be in memory. */ - final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>( + private final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>( DEFAULT_INITIAL_CAPACITY); + // List of all active recent tasks + private final ArrayList<TaskRecord> mTasks = new ArrayList<>(); + private final ArrayList<Callbacks> mCallbacks = new ArrayList<>(); + + // These values are generally loaded from resources, but can be set dynamically in the tests + private boolean mHasVisibleRecentTasks; + private int mGlobalMaxNumTasks; + private int mMinNumVisibleTasks; + private int mMaxNumVisibleTasks; + private long mActiveTasksSessionDurationMs; + // Mainly to avoid object recreation on multiple calls. - private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>(); + private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>(); private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>(); private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>(); - private final ActivityInfo mTmpActivityInfo = new ActivityInfo(); - private final ApplicationInfo mTmpAppInfo = new ApplicationInfo(); + private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray(); - RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) { - File systemDir = Environment.getDataSystemDirectory(); + @VisibleForTesting + RecentTasks(ActivityManagerService service, TaskPersister taskPersister, + UserController userController) { mService = service; - mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, service, this); - mStackSupervisor.setRecentTasks(this); + mUserController = userController; + mTaskPersister = taskPersister; + mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic(); + mHasVisibleRecentTasks = true; + } + + RecentTasks(ActivityManagerService service, ActivityStackSupervisor stackSupervisor) { + final File systemDir = Environment.getDataSystemDirectory(); + final Resources res = service.mContext.getResources(); + mService = service; + mUserController = service.mUserController; + mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this); + mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic(); + mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents); + loadParametersFromResources(service.mContext.getResources()); + } + + @VisibleForTesting + void setParameters(int minNumVisibleTasks, int maxNumVisibleTasks, + long activeSessionDurationMs) { + mMinNumVisibleTasks = minNumVisibleTasks; + mMaxNumVisibleTasks = maxNumVisibleTasks; + mActiveTasksSessionDurationMs = activeSessionDurationMs; + } + + @VisibleForTesting + void setGlobalMaxNumTasks(int globalMaxNumTasks) { + mGlobalMaxNumTasks = globalMaxNumTasks; + } + + /** + * Loads the parameters from the system resources. + */ + @VisibleForTesting + void loadParametersFromResources(Resources res) { + if (ActivityManager.isLowRamDeviceStatic()) { + mMinNumVisibleTasks = res.getInteger( + com.android.internal.R.integer.config_minNumVisibleRecentTasks_lowRam); + mMaxNumVisibleTasks = res.getInteger( + com.android.internal.R.integer.config_maxNumVisibleRecentTasks_lowRam); + } else if (SystemProperties.getBoolean("ro.recents.grid", false)) { + mMinNumVisibleTasks = res.getInteger( + com.android.internal.R.integer.config_minNumVisibleRecentTasks_grid); + mMaxNumVisibleTasks = res.getInteger( + com.android.internal.R.integer.config_maxNumVisibleRecentTasks_grid); + } else { + mMinNumVisibleTasks = res.getInteger( + com.android.internal.R.integer.config_minNumVisibleRecentTasks); + mMaxNumVisibleTasks = res.getInteger( + com.android.internal.R.integer.config_maxNumVisibleRecentTasks); + } + final int sessionDurationHrs = res.getInteger( + com.android.internal.R.integer.config_activeTaskDurationHours); + mActiveTasksSessionDurationMs = (sessionDurationHrs > 0) + ? TimeUnit.HOURS.toMillis(sessionDurationHrs) + : -1; + } + + void registerCallback(Callbacks callback) { + mCallbacks.add(callback); + } + + void unregisterCallback(Callbacks callback) { + mCallbacks.remove(callback); + } + + private void notifyTaskAdded(TaskRecord task) { + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onRecentTaskAdded(task); + } + } + + private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed) { + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed); + } } /** @@ -106,6 +245,7 @@ class RecentTasks extends ArrayList<TaskRecord> { */ void loadUserRecentsLocked(int userId) { if (mUsersWithRecentsLoaded.get(userId)) { + // User already loaded, return early return; } @@ -114,14 +254,14 @@ class RecentTasks extends ArrayList<TaskRecord> { // Check if any tasks are added before recents is loaded final SparseBooleanArray preaddedTasks = new SparseBooleanArray(); - for (final TaskRecord task : this) { + for (final TaskRecord task : mTasks) { if (task.userId == userId && shouldPersistTaskLocked(task)) { preaddedTasks.put(task.taskId, true); } } Slog.i(TAG, "Loading recents for user " + userId + " into memory."); - addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks)); + mTasks.addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks)); cleanupLocked(userId); mUsersWithRecentsLoaded.put(userId, true); @@ -140,11 +280,25 @@ class RecentTasks extends ArrayList<TaskRecord> { } } - boolean taskIdTakenForUserLocked(int taskId, int userId) { + /** + * @return whether the {@param taskId} is currently in use for the given user. + */ + boolean containsTaskId(int taskId, int userId) { loadPersistedTaskIdsForUserLocked(userId); return mPersistedTaskIds.get(userId).get(taskId); } + /** + * @return all the task ids for the user with the given {@param userId}. + */ + SparseBooleanArray getTaskIdsForUser(int userId) { + loadPersistedTaskIdsForUserLocked(userId); + return mPersistedTaskIds.get(userId); + } + + /** + * Kicks off the task persister to write any pending tasks to disk. + */ void notifyTaskPersisterLocked(TaskRecord task, boolean flush) { final ActivityStack stack = task != null ? task.getStack() : null; if (stack != null && stack.isHomeOrRecentsStack()) { @@ -164,8 +318,8 @@ class RecentTasks extends ArrayList<TaskRecord> { mPersistedTaskIds.valueAt(i).clear(); } } - for (int i = size() - 1; i >= 0; i--) { - final TaskRecord task = get(i); + for (int i = mTasks.size() - 1; i >= 0; i--) { + final TaskRecord task = mTasks.get(i); if (shouldPersistTaskLocked(task)) { // Set of persisted taskIds for task.userId should not be null here // TODO Investigate why it can happen. For now initialize with an empty set @@ -180,12 +334,12 @@ class RecentTasks extends ArrayList<TaskRecord> { } private static boolean shouldPersistTaskLocked(TaskRecord task) { - final ActivityStack<?> stack = task.getStack(); + final ActivityStack stack = task.getStack(); return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack()); } void onSystemReadyLocked() { - clear(); + mTasks.clear(); mTaskPersister.startPersisting(); } @@ -225,14 +379,6 @@ class RecentTasks extends ArrayList<TaskRecord> { return usersWithRecentsLoaded; } - private void unloadUserRecentsLocked(int userId) { - if (mUsersWithRecentsLoaded.get(userId)) { - Slog.i(TAG, "Unloading recents for user " + userId + " from memory."); - mUsersWithRecentsLoaded.delete(userId); - removeTasksForUserLocked(userId); - } - } - /** * Removes recent tasks and any other state kept in memory for the passed in user. Does not * touch the information present on persistent storage. @@ -240,44 +386,36 @@ class RecentTasks extends ArrayList<TaskRecord> { * @param userId the id of the user */ void unloadUserDataFromMemoryLocked(int userId) { - unloadUserRecentsLocked(userId); + if (mUsersWithRecentsLoaded.get(userId)) { + Slog.i(TAG, "Unloading recents for user " + userId + " from memory."); + mUsersWithRecentsLoaded.delete(userId); + removeTasksForUserLocked(userId); + } mPersistedTaskIds.delete(userId); mTaskPersister.unloadUserDataFromMemory(userId); } - TaskRecord taskForIdLocked(int id) { - final int recentsCount = size(); - for (int i = 0; i < recentsCount; i++) { - TaskRecord tr = get(i); - if (tr.taskId == id) { - return tr; - } - } - return null; - } - /** Remove recent tasks for a user. */ - void removeTasksForUserLocked(int userId) { + private void removeTasksForUserLocked(int userId) { if(userId <= 0) { Slog.i(TAG, "Can't remove recent task on user " + userId); return; } - for (int i = size() - 1; i >= 0; --i) { - TaskRecord tr = get(i); + for (int i = mTasks.size() - 1; i >= 0; --i) { + TaskRecord tr = mTasks.get(i); if (tr.userId == userId) { if(DEBUG_TASKS) Slog.i(TAG_TASKS, "remove RecentTask " + tr + " when finishing user" + userId); - remove(i); - tr.removedFromRecents(); + remove(mTasks.get(i)); } } } void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) { final Set<String> packageNames = Sets.newHashSet(packages); - for (int i = size() - 1; i >= 0; --i) { - final TaskRecord tr = get(i); + for (int i = mTasks.size() - 1; i >= 0; --i) { + final TaskRecord tr = mTasks.get(i); if (tr.realActivity != null && packageNames.contains(tr.realActivity.getPackageName()) && tr.userId == userId @@ -286,7 +424,36 @@ class RecentTasks extends ArrayList<TaskRecord> { notifyTaskPersisterLocked(tr, false); } } + } + + void removeTasksByPackageName(String packageName, int userId) { + for (int i = mTasks.size() - 1; i >= 0; --i) { + final TaskRecord tr = mTasks.get(i); + final String taskPackageName = + tr.getBaseIntent().getComponent().getPackageName(); + if (tr.userId != userId) return; + if (!taskPackageName.equals(packageName)) return; + + mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS); + } + } + + void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses, + int userId) { + for (int i = mTasks.size() - 1; i >= 0; --i) { + final TaskRecord tr = mTasks.get(i); + if (userId != UserHandle.USER_ALL && tr.userId != userId) { + continue; + } + ComponentName cn = tr.intent.getComponent(); + final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName) + && (filterByClasses == null || filterByClasses.contains(cn.getClassName())); + if (sameComponent) { + mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, + REMOVE_FROM_RECENTS); + } + } } /** @@ -295,24 +462,28 @@ class RecentTasks extends ArrayList<TaskRecord> { * of affiliations. */ void cleanupLocked(int userId) { - int recentsCount = size(); + int recentsCount = mTasks.size(); if (recentsCount == 0) { // Happens when called from the packagemanager broadcast before boot, // or just any empty list. return; } + // Clear the temp lists + mTmpAvailActCache.clear(); + mTmpAvailAppCache.clear(); + final IPackageManager pm = AppGlobals.getPackageManager(); for (int i = recentsCount - 1; i >= 0; i--) { - final TaskRecord task = get(i); + final TaskRecord task = mTasks.get(i); if (userId != UserHandle.USER_ALL && task.userId != userId) { // Only look at tasks for the user ID of interest. continue; } if (task.autoRemoveRecents && task.getTopActivity() == null) { // This situation is broken, and we should just get rid of it now. - remove(i); - task.removedFromRecents(); + mTasks.remove(i); + notifyTaskRemoved(task, !TRIMMED); Slog.w(TAG, "Removing auto-remove without activity: " + task); continue; } @@ -331,11 +502,11 @@ class RecentTasks extends ArrayList<TaskRecord> { continue; } if (ai == null) { - ai = mTmpActivityInfo; + ai = NO_ACTIVITY_INFO_TOKEN; } mTmpAvailActCache.put(task.realActivity, ai); } - if (ai == mTmpActivityInfo) { + if (ai == NO_ACTIVITY_INFO_TOKEN) { // This could be either because the activity no longer exists, or the // app is temporarily gone. For the former we want to remove the recents // entry; for the latter we want to mark it as unavailable. @@ -350,15 +521,15 @@ class RecentTasks extends ArrayList<TaskRecord> { continue; } if (app == null) { - app = mTmpAppInfo; + app = NO_APPLICATION_INFO_TOKEN; } mTmpAvailAppCache.put(task.realActivity.getPackageName(), app); } - if (app == mTmpAppInfo + if (app == NO_APPLICATION_INFO_TOKEN || (app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { // Doesn't exist any more! Good-bye. - remove(i); - task.removedFromRecents(); + mTasks.remove(i); + notifyTaskRemoved(task, !TRIMMED); Slog.w(TAG, "Removing no longer valid recent: " + task); continue; } else { @@ -390,121 +561,197 @@ class RecentTasks extends ArrayList<TaskRecord> { // Verify the affiliate chain for each task. int i = 0; - recentsCount = size(); + recentsCount = mTasks.size(); while (i < recentsCount) { i = processNextAffiliateChainLocked(i); } // recent tasks are now in sorted, affiliated order. } - private final boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) { - int recentsCount = size(); - TaskRecord top = task; - int topIndex = taskIndex; - while (top.mNextAffiliate != null && topIndex > 0) { - top = top.mNextAffiliate; - topIndex--; + /** + * @return whether the given {@param task} can be added to the list without causing another + * task to be trimmed as a result of that add. + */ + private boolean canAddTaskWithoutTrim(TaskRecord task) { + return findTrimIndexForAddTask(task) == -1; + } + + /** + * Returns the list of {@link ActivityManager.AppTask}s. + */ + ArrayList<IBinder> getAppTasksList(int callingUid, String callingPackage) { + final ArrayList<IBinder> list = new ArrayList<>(); + final int size = mTasks.size(); + for (int i = 0; i < size; i++) { + final TaskRecord tr = mTasks.get(i); + // Skip tasks that do not match the caller. We don't need to verify + // callingPackage, because we are also limiting to callingUid and know + // that will limit to the correct security sandbox. + if (tr.effectiveUid != callingUid) { + continue; + } + Intent intent = tr.getBaseIntent(); + if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) { + continue; + } + ActivityManager.RecentTaskInfo taskInfo = createRecentTaskInfo(tr); + AppTaskImpl taskImpl = new AppTaskImpl(mService, taskInfo.persistentId, callingUid); + list.add(taskImpl.asBinder()); } - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at " - + topIndex + " from intial " + taskIndex); - // Find the end of the chain, doing a sanity check along the way. - boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId; - int endIndex = topIndex; - TaskRecord prev = top; - while (endIndex < recentsCount) { - TaskRecord cur = get(endIndex); - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @" - + endIndex + " " + cur); - if (cur == top) { - // Verify start of the chain. - if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": first task has next affiliate: " + prev); - sane = false; - break; + return list; + } + + /** + * @return the list of recent tasks for presentation. + */ + ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags, + boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) { + final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0; + + if (!mService.isUserRunning(userId, FLAG_AND_UNLOCKED)) { + Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents"); + return ParceledListSlice.emptyList(); + } + loadUserRecentsLocked(userId); + + final Set<Integer> includedUsers = mUserController.getProfileIds(userId); + includedUsers.add(Integer.valueOf(userId)); + + final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>(); + final int size = mTasks.size(); + int numVisibleTasks = 0; + for (int i = 0; i < size; i++) { + final TaskRecord tr = mTasks.get(i); + + if (isVisibleRecentTask(tr)) { + numVisibleTasks++; + if (isInVisibleRange(tr, numVisibleTasks)) { + // Fall through + } else { + // Not in visible range + continue; } } else { - // Verify middle of the chain's next points back to the one before. - if (cur.mNextAffiliate != prev - || cur.mNextAffiliateTaskId != prev.taskId) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": middle task " + cur + " @" + endIndex - + " has bad next affiliate " - + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId - + ", expected " + prev); - sane = false; - break; - } + // Not visible + continue; } - if (cur.mPrevAffiliateTaskId == INVALID_TASK_ID) { - // Chain ends here. - if (cur.mPrevAffiliate != null) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": last task " + cur + " has previous affiliate " - + cur.mPrevAffiliate); - sane = false; - } - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex); - break; - } else { - // Verify middle of the chain's prev points to a valid item. - if (cur.mPrevAffiliate == null) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": task " + cur + " has previous affiliate " - + cur.mPrevAffiliate + " but should be id " - + cur.mPrevAffiliate); - sane = false; - break; - } + + // Skip remaining tasks once we reach the requested size + if (res.size() >= maxNum) { + continue; } - if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": task " + cur + " has affiliated id " - + cur.mAffiliatedTaskId + " but should be " - + task.mAffiliatedTaskId); - sane = false; - break; + + // Only add calling user or related users recent tasks + if (!includedUsers.contains(Integer.valueOf(tr.userId))) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr); + continue; } - prev = cur; - endIndex++; - if (endIndex >= recentsCount) { - Slog.wtf(TAG, "Bad chain ran off index " + endIndex - + ": last task " + prev); - sane = false; - break; + + if (tr.realActivitySuspended) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr); + continue; } - } - if (sane) { - if (endIndex < taskIndex) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": did not extend to task " + task + " @" + taskIndex); - sane = false; + + // Return the entry if desired by the caller. We always return + // the first entry, because callers always expect this to be the + // foreground app. We may filter others if the caller has + // not supplied RECENT_WITH_EXCLUDED and there is some reason + // we should exclude the entry. + + if (i == 0 + || withExcluded + || (tr.intent == null) + || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + == 0)) { + if (!getTasksAllowed) { + // If the caller doesn't have the GET_TASKS permission, then only + // allow them to see a small subset of tasks -- their own and home. + if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr); + continue; + } + } + if (tr.autoRemoveRecents && tr.getTopActivity() == null) { + // Don't include auto remove tasks that are finished or finishing. + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, auto-remove without activity: " + tr); + continue; + } + if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, unavail real act: " + tr); + continue; + } + + if (!tr.mUserSetupComplete) { + // Don't include task launched while user is not done setting-up. + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, user setup not complete: " + tr); + continue; + } + + ActivityManager.RecentTaskInfo rti = RecentTasks.createRecentTaskInfo(tr); + if (!getDetailedTasks) { + rti.baseIntent.replaceExtras((Bundle)null); + } + + res.add(rti); } } - if (sane) { - // All looks good, we can just move all of the affiliated tasks - // to the top. - for (int i=topIndex; i<=endIndex; i++) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task - + " from " + i + " to " + (i-topIndex)); - TaskRecord cur = remove(i); - add(i - topIndex, cur); + return new ParceledListSlice<>(res); + } + + /** + * @return the list of persistable task ids. + */ + void getPersistableTaskIds(ArraySet<Integer> persistentTaskIds) { + final int size = mTasks.size(); + for (int i = 0; i < size; i++) { + final TaskRecord task = mTasks.get(i); + if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + + " persistable=" + task.isPersistable); + final ActivityStack stack = task.getStack(); + if ((task.isPersistable || task.inRecents) + && (stack == null || !stack.isHomeOrRecentsStack())) { + if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task); + persistentTaskIds.add(task.taskId); + } else { + if (TaskPersister.DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + + task); } - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex - + " to " + endIndex); - return true; } + } - // Whoops, couldn't do it. - return false; + @VisibleForTesting + ArrayList<TaskRecord> getRawTasks() { + return mTasks; + } + + /** + * @return the task in the task list with the given {@param id} if one exists. + */ + TaskRecord getTask(int id) { + final int recentsCount = mTasks.size(); + for (int i = 0; i < recentsCount; i++) { + TaskRecord tr = mTasks.get(i); + if (tr.taskId == id) { + return tr; + } + } + return null; } - final void addLocked(TaskRecord task) { + /** + * Add a new task to the recent tasks list. + */ + void add(TaskRecord task) { + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task); + final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId || task.mNextAffiliateTaskId != INVALID_TASK_ID || task.mPrevAffiliateTaskId != INVALID_TASK_ID; - int recentsCount = size(); + int recentsCount = mTasks.size(); // Quick case: never add voice sessions. // TODO: VI what about if it's just an activity? // Probably nothing to do here @@ -514,15 +761,15 @@ class RecentTasks extends ArrayList<TaskRecord> { return; } // Another quick case: check if the top-most recent task is the same. - if (!isAffiliated && recentsCount > 0 && get(0) == task) { + if (!isAffiliated && recentsCount > 0 && mTasks.get(0) == task) { if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task); return; } // Another quick case: check if this is part of a set of affiliated // tasks that are at the top. if (isAffiliated && recentsCount > 0 && task.inRecents - && task.mAffiliatedTaskId == get(0).mAffiliatedTaskId) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + get(0) + && task.mAffiliatedTaskId == mTasks.get(0).mAffiliatedTaskId) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0) + " at top when adding " + task); return; } @@ -532,12 +779,12 @@ class RecentTasks extends ArrayList<TaskRecord> { // Slightly less quick case: the task is already in recents, so all we need // to do is move it. if (task.inRecents) { - int taskIndex = indexOf(task); + int taskIndex = mTasks.indexOf(task); if (taskIndex >= 0) { - if (!isAffiliated || MOVE_AFFILIATED_TASKS_TO_FRONT) { + if (!isAffiliated || !MOVE_AFFILIATED_TASKS_TO_FRONT) { // Simple case: this is not an affiliated task, so we just move it to the front. - remove(taskIndex); - add(0, task); + mTasks.remove(taskIndex); + mTasks.add(0, task); notifyTaskPersisterLocked(task, false); if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task + " from " + taskIndex); @@ -560,20 +807,14 @@ class RecentTasks extends ArrayList<TaskRecord> { } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task); - trimForTaskLocked(task, true); + trimForAddTask(task); - recentsCount = size(); - final int maxRecents = ActivityManager.getMaxRecentTasksStatic(); - while (recentsCount >= maxRecents) { - final TaskRecord tr = remove(recentsCount - 1); - tr.removedFromRecents(); - recentsCount--; - } task.inRecents = true; if (!isAffiliated || needAffiliationFix) { // If this is a simple non-affiliated task, or we had some failure trying to // handle it as part of an affilated task, then just place it at the top. - add(0, task); + mTasks.add(0, task); + notifyTaskAdded(task); if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task); } else if (isAffiliated) { // If this is a new affiliated task, then move all of the affiliated tasks @@ -583,7 +824,7 @@ class RecentTasks extends ArrayList<TaskRecord> { other = task.mPrevAffiliate; } if (other != null) { - int otherIndex = indexOf(other); + int otherIndex = mTasks.indexOf(other); if (otherIndex >= 0) { // Insert new task at appropriate location. int taskIndex; @@ -598,7 +839,8 @@ class RecentTasks extends ArrayList<TaskRecord> { } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: new affiliated task added at " + taskIndex + ": " + task); - add(taskIndex, task); + mTasks.add(taskIndex, task); + notifyTaskAdded(task); // Now move everything to the front. if (moveAffiliatedTasksToFront(task, taskIndex)) { @@ -625,21 +867,235 @@ class RecentTasks extends ArrayList<TaskRecord> { if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations"); cleanupLocked(task.userId); } + + // Trim the set of tasks to the active set + trimInactiveRecentTasks(); + } + + /** + * Add the task to the bottom if possible. + */ + boolean addToBottom(TaskRecord task) { + if (!canAddTaskWithoutTrim(task)) { + // Adding this task would cause the task to be removed (since it's appended at + // the bottom and would be trimmed) so just return now + return false; + } + + add(task); + return true; + } + + /** + * Remove a task from the recent tasks list. + */ + void remove(TaskRecord task) { + mTasks.remove(task); + notifyTaskRemoved(task, !TRIMMED); + } + + /** + * Trims the recents task list to the global max number of recents. + */ + private void trimInactiveRecentTasks() { + int recentsCount = mTasks.size(); + + // Remove from the end of the list until we reach the max number of recents + while (recentsCount > mGlobalMaxNumTasks) { + final TaskRecord tr = mTasks.remove(recentsCount - 1); + notifyTaskRemoved(tr, TRIMMED); + recentsCount--; + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + tr + + " max=" + mGlobalMaxNumTasks); + } + + // Remove any tasks that belong to currently quiet profiles + final int[] profileUserIds = mUserController.getCurrentProfileIds(); + mTmpQuietProfileUserIds.clear(); + for (int userId : profileUserIds) { + final UserInfo userInfo = mUserController.getUserInfo(userId); + if (userInfo.isManagedProfile() && userInfo.isQuietModeEnabled()) { + mTmpQuietProfileUserIds.put(userId, true); + } + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "User: " + userInfo + + " quiet=" + mTmpQuietProfileUserIds.get(userId)); + } + + // Remove any inactive tasks, calculate the latest set of visible tasks + int numVisibleTasks = 0; + for (int i = 0; i < mTasks.size();) { + final TaskRecord task = mTasks.get(i); + + if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) { + if (!mHasVisibleRecentTasks) { + // Keep all active tasks if visible recent tasks is not supported + i++; + continue; + } + + if (!isVisibleRecentTask(task)) { + // Keep all active-but-invisible tasks + i++; + continue; + } else { + numVisibleTasks++; + if (isInVisibleRange(task, numVisibleTasks)) { + // Keep visible tasks in range + i++; + continue; + } else { + // Fall through to trim visible tasks that are no longer in range + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, + "Trimming out-of-range visible task=" + task); + } + } + } else { + // Fall through to trim inactive tasks + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming inactive task=" + task); + } + + // Task is no longer active, trim it from the list + mTasks.remove(task); + notifyTaskRemoved(task, TRIMMED); + notifyTaskPersisterLocked(task, false /* flush */); + } + } + + /** + * @return whether the given task should be considered active. + */ + private boolean isActiveRecentTask(TaskRecord task, SparseBooleanArray quietProfileUserIds) { + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task + + " globalMax=" + mGlobalMaxNumTasks); + + if (quietProfileUserIds.get(task.userId)) { + // Quiet profile user's tasks are never active + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\tisQuietProfileTask=true"); + return false; + } + + if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.taskId) { + // Keep the task active if its affiliated task is also active + final TaskRecord affiliatedTask = getTask(task.mAffiliatedTaskId); + if (affiliatedTask != null) { + if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) { + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, + "\taffiliatedWithTask=" + affiliatedTask + " is not active"); + return false; + } + } + } + + // All other tasks are considered active + return true; + } + + /** + * @return whether the given active task should be presented to the user through SystemUI. + */ + private boolean isVisibleRecentTask(TaskRecord task) { + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task + + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks + + " sessionDuration=" + mActiveTasksSessionDurationMs + + " inactiveDuration=" + task.getInactiveDuration() + + " activityType=" + task.getActivityType() + + " windowingMode=" + task.getWindowingMode()); + + // Ignore certain activity types completely + switch (task.getActivityType()) { + case ACTIVITY_TYPE_HOME: + case ACTIVITY_TYPE_RECENTS: + return false; + } + + // Ignore certain windowing modes + switch (task.getWindowingMode()) { + case WINDOWING_MODE_PINNED: + return false; + case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().topTask()); + final ActivityStack stack = task.getStack(); + if (stack != null && stack.topTask() == task) { + // Only the non-top task of the primary split screen mode is visible + return false; + } + } + + return true; + } + + /** + * @return whether the given visible task is within the policy range. + */ + private boolean isInVisibleRange(TaskRecord task, int numVisibleTasks) { + // Keep the last most task even if it is excluded from recents + final boolean isExcludeFromRecents = + (task.getBaseIntent().getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; + if (isExcludeFromRecents) { + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true"); + return numVisibleTasks == 1; + } + + if (mMinNumVisibleTasks >= 0 && numVisibleTasks <= mMinNumVisibleTasks) { + // Always keep up to the min number of recent tasks, after that fall through to the + // checks below + return true; + } + + if (mMaxNumVisibleTasks >= 0) { + // Always keep up to the max number of recent tasks, but return false afterwards + return numVisibleTasks <= mMaxNumVisibleTasks; + } + + if (mActiveTasksSessionDurationMs > 0) { + // Keep the task if the inactive time is within the session window, this check must come + // after the checks for the min/max visible task range + if (task.getInactiveDuration() <= mActiveTasksSessionDurationMs) { + return true; + } + } + + return false; } /** * If needed, remove oldest existing entries in recents that are for the same kind * of task as the given one. */ - int trimForTaskLocked(TaskRecord task, boolean doTrim) { - int recentsCount = size(); + private void trimForAddTask(TaskRecord task) { + final int removeIndex = findTrimIndexForAddTask(task); + if (removeIndex == -1) { + // Nothing to trim + return; + } + + // There is a similar task that will be removed for the addition of {@param task}, but it + // can be the same task, and if so, the task will be re-added in add(), so skip the + // callbacks here. + final TaskRecord removedTask = mTasks.remove(removeIndex); + if (removedTask != task) { + notifyTaskRemoved(removedTask, TRIMMED); + if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask + + " for addition of task=" + task); + } + notifyTaskPersisterLocked(removedTask, false /* flush */); + } + + /** + * Find the task that would be removed if the given {@param task} is added to the recent tasks + * list (if any). + */ + private int findTrimIndexForAddTask(TaskRecord task) { + int recentsCount = mTasks.size(); final Intent intent = task.intent; final boolean document = intent != null && intent.isDocument(); int maxRecents = task.maxRecents - 1; final ActivityStack stack = task.getStack(); for (int i = 0; i < recentsCount; i++) { - final TaskRecord tr = get(i); + final TaskRecord tr = mTasks.get(i); final ActivityStack trStack = tr.getStack(); + if (task != tr) { if (stack != null && trStack != null && stack != trStack) { continue; @@ -650,7 +1106,7 @@ class RecentTasks extends ArrayList<TaskRecord> { final Intent trIntent = tr.intent; final boolean sameAffinity = task.affinity != null && task.affinity.equals(tr.affinity); - final boolean sameIntentFilter = intent != null && intent.filterEquals(trIntent); + final boolean sameIntent = intent != null && intent.filterEquals(trIntent); boolean multiTasksAllowed = false; final int flags = intent.getFlags(); if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0 @@ -659,7 +1115,7 @@ class RecentTasks extends ArrayList<TaskRecord> { } final boolean trIsDocument = trIntent != null && trIntent.isDocument(); final boolean bothDocuments = document && trIsDocument; - if (!sameAffinity && !sameIntentFilter && !bothDocuments) { + if (!sameAffinity && !sameIntent && !bothDocuments) { continue; } @@ -668,17 +1124,17 @@ class RecentTasks extends ArrayList<TaskRecord> { final boolean sameActivity = task.realActivity != null && tr.realActivity != null && task.realActivity.equals(tr.realActivity); - // If the document is open in another app or is not the same - // document, we don't need to trim it. if (!sameActivity) { + // If the document is open in another app or is not the same document, we + // don't need to trim it. continue; - // Otherwise only trim if we are over our max recents for this task } else if (maxRecents > 0) { + // Otherwise only trim if we are over our max recents for this task --maxRecents; - if (!doTrim || !sameIntentFilter || multiTasksAllowed) { + if (!sameIntent || multiTasksAllowed) { // We don't want to trim if we are not over the max allowed entries and - // the caller doesn't want us to trim, the tasks are not of the same - // intent filter, or multiple entries fot the task is allowed. + // the tasks are not of the same intent filter, or multiple entries for + // the task is allowed. continue; } } @@ -689,44 +1145,14 @@ class RecentTasks extends ArrayList<TaskRecord> { continue; } } - - if (!doTrim) { - // If the caller is not actually asking for a trim, just tell them we reached - // a point where the trim would happen. - return i; - } - - // Either task and tr are the same or, their affinities match or their intents match - // and neither of them is a document, or they are documents using the same activity - // and their maxRecents has been reached. - remove(i); - if (task != tr) { - tr.removedFromRecents(); - } - i--; - recentsCount--; - if (task.intent == null) { - // If the new recent task we are adding is not fully - // specified, then replace it with the existing recent task. - task = tr; - } - notifyTaskPersisterLocked(tr, false); + return i; } - return -1; } - // Sort by taskId - private static Comparator<TaskRecord> sTaskRecordComparator = new Comparator<TaskRecord>() { - @Override - public int compare(TaskRecord lhs, TaskRecord rhs) { - return rhs.taskId - lhs.taskId; - } - }; - // Extract the affiliates of the chain containing recent at index start. private int processNextAffiliateChainLocked(int start) { - final TaskRecord startTask = get(start); + final TaskRecord startTask = mTasks.get(start); final int affiliateId = startTask.mAffiliatedTaskId; // Quick identification of isolated tasks. I.e. those not launched behind. @@ -741,17 +1167,17 @@ class RecentTasks extends ArrayList<TaskRecord> { // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents. mTmpRecents.clear(); - for (int i = size() - 1; i >= start; --i) { - final TaskRecord task = get(i); + for (int i = mTasks.size() - 1; i >= start; --i) { + final TaskRecord task = mTasks.get(i); if (task.mAffiliatedTaskId == affiliateId) { - remove(i); + mTasks.remove(i); mTmpRecents.add(task); } } // Sort them all by taskId. That is the order they were create in and that order will // always be correct. - Collections.sort(mTmpRecents, sTaskRecordComparator); + Collections.sort(mTmpRecents, TASK_ID_COMPARATOR); // Go through and fix up the linked list. // The first one is the end of the chain and has no next. @@ -789,11 +1215,197 @@ class RecentTasks extends ArrayList<TaskRecord> { notifyTaskPersisterLocked(last, false); } - // Insert the group back into mRecentTasks at start. - addAll(start, mTmpRecents); + // Insert the group back into mTmpTasks at start. + mTasks.addAll(start, mTmpRecents); mTmpRecents.clear(); // Let the caller know where we left off. return start + tmpSize; } + + private boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) { + int recentsCount = mTasks.size(); + TaskRecord top = task; + int topIndex = taskIndex; + while (top.mNextAffiliate != null && topIndex > 0) { + top = top.mNextAffiliate; + topIndex--; + } + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at " + + topIndex + " from intial " + taskIndex); + // Find the end of the chain, doing a sanity check along the way. + boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId; + int endIndex = topIndex; + TaskRecord prev = top; + while (endIndex < recentsCount) { + TaskRecord cur = mTasks.get(endIndex); + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @" + + endIndex + " " + cur); + if (cur == top) { + // Verify start of the chain. + if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": first task has next affiliate: " + prev); + sane = false; + break; + } + } else { + // Verify middle of the chain's next points back to the one before. + if (cur.mNextAffiliate != prev + || cur.mNextAffiliateTaskId != prev.taskId) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": middle task " + cur + " @" + endIndex + + " has bad next affiliate " + + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId + + ", expected " + prev); + sane = false; + break; + } + } + if (cur.mPrevAffiliateTaskId == INVALID_TASK_ID) { + // Chain ends here. + if (cur.mPrevAffiliate != null) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": last task " + cur + " has previous affiliate " + + cur.mPrevAffiliate); + sane = false; + } + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex); + break; + } else { + // Verify middle of the chain's prev points to a valid item. + if (cur.mPrevAffiliate == null) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": task " + cur + " has previous affiliate " + + cur.mPrevAffiliate + " but should be id " + + cur.mPrevAffiliate); + sane = false; + break; + } + } + if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": task " + cur + " has affiliated id " + + cur.mAffiliatedTaskId + " but should be " + + task.mAffiliatedTaskId); + sane = false; + break; + } + prev = cur; + endIndex++; + if (endIndex >= recentsCount) { + Slog.wtf(TAG, "Bad chain ran off index " + endIndex + + ": last task " + prev); + sane = false; + break; + } + } + if (sane) { + if (endIndex < taskIndex) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": did not extend to task " + task + " @" + taskIndex); + sane = false; + } + } + if (sane) { + // All looks good, we can just move all of the affiliated tasks + // to the top. + for (int i=topIndex; i<=endIndex; i++) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task + + " from " + i + " to " + (i-topIndex)); + TaskRecord cur = mTasks.remove(i); + mTasks.add(i - topIndex, cur); + } + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex + + " to " + endIndex); + return true; + } + + // Whoops, couldn't do it. + return false; + } + + void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) { + pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)"); + if (mTasks.isEmpty()) { + return; + } + + final MutableBoolean printedAnything = new MutableBoolean(false); + final MutableBoolean printedHeader = new MutableBoolean(false); + final int size = mTasks.size(); + for (int i = 0; i < size; i++) { + final TaskRecord tr = mTasks.get(i); + if (dumpPackage != null && (tr.realActivity == null || + !dumpPackage.equals(tr.realActivity.getPackageName()))) { + continue; + } + + if (!printedHeader.value) { + pw.println(" Recent tasks:"); + printedHeader.value = true; + printedAnything.value = true; + } + pw.print(" * Recent #"); pw.print(i); pw.print(": "); + pw.println(tr); + if (dumpAll) { + tr.dump(pw, " "); + } + } + + if (!printedAnything.value) { + pw.println(" (nothing)"); + } + } + + /** + * Creates a new RecentTaskInfo from a TaskRecord. + */ + static ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) { + // Update the task description to reflect any changes in the task stack + tr.updateTaskDescription(); + + // Compose the recent task info + ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); + rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId; + rti.persistentId = tr.taskId; + rti.baseIntent = new Intent(tr.getBaseIntent()); + rti.origActivity = tr.origActivity; + rti.realActivity = tr.realActivity; + rti.description = tr.lastDescription; + rti.stackId = tr.getStackId(); + rti.userId = tr.userId; + rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription); + rti.lastActiveTime = tr.lastActiveTime; + rti.affiliatedTaskId = tr.mAffiliatedTaskId; + rti.affiliatedTaskColor = tr.mAffiliatedTaskColor; + rti.numActivities = 0; + if (tr.mBounds != null) { + rti.bounds = new Rect(tr.mBounds); + } + rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode(); + rti.resizeMode = tr.mResizeMode; + rti.configuration.setTo(tr.getConfiguration()); + + ActivityRecord base = null; + ActivityRecord top = null; + ActivityRecord tmp; + + for (int i = tr.mActivities.size() - 1; i >= 0; --i) { + tmp = tr.mActivities.get(i); + if (tmp.finishing) { + continue; + } + base = tmp; + if (top == null || (top.state == ActivityState.INITIALIZING)) { + top = base; + } + rti.numActivities++; + } + + rti.baseActivity = (base != null) ? base.intent.getComponent() : null; + rti.topActivity = (top != null) ? top.intent.getComponent() : null; + + return rti; + } } diff --git a/com/android/server/am/ServiceRecord.java b/com/android/server/am/ServiceRecord.java index ac85e6b1..16995e50 100644 --- a/com/android/server/am/ServiceRecord.java +++ b/com/android/server/am/ServiceRecord.java @@ -33,6 +33,7 @@ import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; @@ -517,14 +518,27 @@ final class ServiceRecord extends Binder { } catch (PackageManager.NameNotFoundException e) { } } - if (localForegroundNoti.getSmallIcon() == null - || nm.getNotificationChannel(localPackageName, appUid, + if (nm.getNotificationChannel(localPackageName, appUid, localForegroundNoti.getChannelId()) == null) { + int targetSdkVersion = Build.VERSION_CODES.O_MR1; + try { + final ApplicationInfo applicationInfo = + ams.mContext.getPackageManager().getApplicationInfoAsUser( + appInfo.packageName, 0, userId); + targetSdkVersion = applicationInfo.targetSdkVersion; + } catch (PackageManager.NameNotFoundException e) { + } + if (targetSdkVersion >= Build.VERSION_CODES.O_MR1) { + throw new RuntimeException( + "invalid channel for service notification: " + + foregroundNoti); + } + } + if (localForegroundNoti.getSmallIcon() == null) { // Notifications whose icon is 0 are defined to not show // a notification, silently ignoring it. We don't want to // just ignore it, we want to prevent the service from // being foreground. - // Also every notification needs a channel. throw new RuntimeException("invalid service notification: " + foregroundNoti); } diff --git a/com/android/server/am/TaskPersister.java b/com/android/server/am/TaskPersister.java index 61994b55..2689d6a4 100644 --- a/com/android/server/am/TaskPersister.java +++ b/com/android/server/am/TaskPersister.java @@ -567,7 +567,7 @@ public class TaskPersister { SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>(); synchronized (mService) { for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) { - SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId); + SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForUser(userId); SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId); if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) { continue; @@ -640,7 +640,7 @@ public class TaskPersister { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>(); + ArraySet<Integer> persistentTaskIds = new ArraySet<>(); while (true) { // We can't lock mService while holding TaskPersister.this, but we don't want to // call removeObsoleteFiles every time through the loop, only the last time before @@ -654,20 +654,7 @@ public class TaskPersister { persistentTaskIds.clear(); synchronized (mService) { if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks); - for (int taskNdx = mRecentTasks.size() - 1; taskNdx >= 0; --taskNdx) { - final TaskRecord task = mRecentTasks.get(taskNdx); - if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + - " persistable=" + task.isPersistable); - final ActivityStack stack = task.getStack(); - if ((task.isPersistable || task.inRecents) - && (stack == null || !stack.isHomeOrRecentsStack())) { - if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task); - persistentTaskIds.add(task.taskId); - } else { - if (DEBUG) Slog.d(TAG, - "omitting from persistentTaskIds task=" + task); - } - } + mRecentTasks.getPersistableTaskIds(persistentTaskIds); mService.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds, mRecentTasks.usersWithRecentsLoadedLocked()); } diff --git a/com/android/server/am/TaskRecord.java b/com/android/server/am/TaskRecord.java index 0d8df796..a1b45a1e 100644 --- a/com/android/server/am/TaskRecord.java +++ b/com/android/server/am/TaskRecord.java @@ -18,10 +18,7 @@ package com.android.server.am; import static android.app.ActivityManager.RESIZE_MODE_FORCED; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -31,6 +28,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; @@ -45,7 +43,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; -import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; @@ -86,7 +83,6 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManager.StackId; import android.app.ActivityManager.TaskDescription; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityOptions; @@ -102,6 +98,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.Debug; import android.os.RemoteException; +import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; @@ -155,8 +152,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi private static final String ATTR_EFFECTIVE_UID = "effective_uid"; @Deprecated private static final String ATTR_TASKTYPE = "task_type"; - private static final String ATTR_FIRSTACTIVETIME = "first_active_time"; - private static final String ATTR_LASTACTIVETIME = "last_active_time"; private static final String ATTR_LASTDESCRIPTION = "last_description"; private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; @@ -168,7 +163,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi private static final String ATTR_CALLING_PACKAGE = "calling_package"; private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture"; private static final String ATTR_RESIZE_MODE = "resize_mode"; - private static final String ATTR_PRIVILEGED = "privileged"; private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; private static final String ATTR_MIN_WIDTH = "min_width"; private static final String ATTR_MIN_HEIGHT = "min_height"; @@ -212,9 +206,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi ComponentName realActivity; // The actual activity component that started the task. boolean realActivitySuspended; // True if the actual activity component that started the // task is suspended. - long firstActiveTime; // First time this task was active. - long lastActiveTime; // Last time this task was active, including sleep. boolean inRecents; // Actually in the recents list? + long lastActiveTime; // Last time this task was active in the current device session, + // including sleep. This time is initialized to the elapsed time when + // restored from disk. boolean isAvailable; // Is the activity available to be launched? boolean rootWasReset; // True if the intent at the root of the task had // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. @@ -237,10 +232,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // of the root activity. boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize // changes on a temporary basis. - private int mLockTaskMode; // Which tasklock mode to launch this task in. One of - // ActivityManager.LOCK_TASK_LAUNCH_MODE_* - private boolean mPrivileged; // The root activity application of this task holds - // privileged permissions. /** Can't be put in lockTask mode. */ final static int LOCK_TASK_AUTH_DONT_LOCK = 0; @@ -339,6 +330,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi TaskPersister.IMAGE_EXTENSION; userId = UserHandle.getUserId(info.applicationInfo.uid); taskId = _taskId; + lastActiveTime = SystemClock.elapsedRealtime(); mAffiliatedTaskId = _taskId; voiceSession = _voiceSession; voiceInteractor = _voiceInteractor; @@ -359,6 +351,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi TaskPersister.IMAGE_EXTENSION; userId = UserHandle.getUserId(info.applicationInfo.uid); taskId = _taskId; + lastActiveTime = SystemClock.elapsedRealtime(); mAffiliatedTaskId = _taskId; voiceSession = null; voiceInteractor = null; @@ -385,12 +378,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, - long _firstActiveTime, long _lastActiveTime, long lastTimeMoved, - boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, - int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, - int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, - boolean privileged, boolean _realActivitySuspended, boolean userSetupComplete, - int minWidth, int minHeight) { + long lastTimeMoved, boolean neverRelinquishIdentity, + TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, + int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, + int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, + boolean userSetupComplete, int minWidth, int minHeight) { mService = service; mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; @@ -412,8 +404,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi userId = _userId; mUserSetupComplete = userSetupComplete; effectiveUid = _effectiveUid; - firstActiveTime = _firstActiveTime; - lastActiveTime = _lastActiveTime; + lastActiveTime = SystemClock.elapsedRealtime(); lastDescription = _lastDescription; mActivities = activities; mLastTimeMoved = lastTimeMoved; @@ -427,7 +418,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mCallingPackage = callingPackage; mResizeMode = resizeMode; mSupportsPictureInPicture = supportsPictureInPicture; - mPrivileged = privileged; mMinWidth = minWidth; mMinHeight = minHeight; mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity); @@ -520,7 +510,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // All we can do for now is update the bounds so it can be used when the task is // added to window manager. updateOverrideConfiguration(bounds); - if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) { + if (!inFreeformWindowingMode()) { // re-restore the task so it can have the proper stack association. mService.mStackSupervisor.restoreRecentTaskLocked(this, null); } @@ -616,8 +606,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi * @return whether the task was reparented */ // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs. - // re-parenting the task. Can only be done when we are no longer using static stack Ids like - /** {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} */ + // re-parenting the task. Can only be done when we are no longer using static stack Ids. boolean reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason) { @@ -630,12 +619,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return false; } - final int sourceStackId = getStackId(); - final int stackId = toStack.getStackId(); + final int toStackWindowingMode = toStack.getWindowingMode(); final ActivityRecord topActivity = getTopActivity(); - final boolean mightReplaceWindow = StackId.replaceWindowsOnTaskMove(sourceStackId, stackId) - && topActivity != null; + final boolean mightReplaceWindow = + replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode) + && topActivity != null; if (mightReplaceWindow) { // We are about to relaunch the activity because its configuration changed due to // being maximized, i.e. size change. The activity will first remove the old window @@ -660,7 +649,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // In some cases the focused stack isn't the front stack. E.g. pinned stack. // Whenever we are moving the top activity from the front stack we want to make sure to // move the stack to the front. - final boolean wasFront = r != null && supervisor.isFrontStackOnDisplay(sourceStack) + final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay() && (sourceStack.topRunningActivityLocked() == r); // Adjust the position for the new parent stack as needed. @@ -707,10 +696,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi toStack.prepareFreezingTaskBounds(); // Make sure the task has the appropriate bounds/size for the stack it is in. - final int toStackWindowingMode = toStack.getWindowingMode(); final boolean toStackSplitScreenPrimary = toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; - if (stackId == FULLSCREEN_WORKSPACE_STACK_ID + if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN + || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) && !Objects.equals(mBounds, toStack.mBounds)) { kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, deferResume); @@ -749,9 +738,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } // TODO: Handle incorrect request to move before the actual move, not after. - final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenStack(); + final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenPrimaryStack(); supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(), - DEFAULT_DISPLAY, stackId); + DEFAULT_DISPLAY, toStack); boolean successful = (preferredStack == toStack); if (successful && toStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { @@ -761,6 +750,18 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return successful; } + /** + * Returns true if the windows of tasks being moved to the target stack from the source + * stack should be replaced, meaning that window manager will keep the old window around + * until the new is ready. + * @hide + */ + private static boolean replaceWindowsOnTaskMove( + int sourceWindowingMode, int targetWindowingMode) { + return sourceWindowingMode == WINDOWING_MODE_FREEFORM + || targetWindowingMode == WINDOWING_MODE_FREEFORM; + } + void cancelWindowTransition() { mWindowContainerController.cancelWindowTransition(); } @@ -780,14 +781,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } void touchActiveTime() { - lastActiveTime = System.currentTimeMillis(); - if (firstActiveTime == 0) { - firstActiveTime = lastActiveTime; - } + lastActiveTime = SystemClock.elapsedRealtime(); } long getInactiveDuration() { - return System.currentTimeMillis() - lastActiveTime; + return SystemClock.elapsedRealtime() - lastActiveTime; } /** Sets the original intent, and the calling uid and package. */ @@ -795,6 +793,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mCallingUid = r.launchedFromUid; mCallingPackage = r.launchedFromPackage; setIntent(r.intent, r.info); + setLockTaskAuth(r); } /** Sets the original intent, _without_ updating the calling uid or package. */ @@ -878,14 +877,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } mResizeMode = info.resizeMode; mSupportsPictureInPicture = info.supportsPictureInPicture(); - mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0; - mLockTaskMode = info.lockTaskLaunchMode; - if (!mPrivileged && (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS - || mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { - // Non-priv apps are not allowed to use always or never, fall back to default - mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; - } - setLockTaskAuth(); } /** Sets the original minimal width and height. */ @@ -1263,7 +1254,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mService.notifyTaskPersisterLocked(this, false); } - if (getStackId() == PINNED_STACK_ID) { + if (inPinnedWindowingMode()) { // We normally notify listeners of task stack changes on pause, however pinned stack // activities are normally in the paused state so no notification will be sent there // before the activity is removed. We send it here so instead. @@ -1422,8 +1413,17 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } void setLockTaskAuth() { + setLockTaskAuth(getRootActivity()); + } + + private void setLockTaskAuth(@Nullable ActivityRecord r) { + if (r == null) { + mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; + return; + } + final String pkg = (realActivity != null) ? realActivity.getPackageName() : null; - switch (mLockTaskMode) { + switch (r.lockTaskLaunchMode) { case LOCK_TASK_LAUNCH_MODE_DEFAULT: mLockTaskAuth = mService.mLockTaskController.isPackageWhitelisted(userId, pkg) ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; @@ -1493,7 +1493,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi * @return True if the requested bounds are okay for a resizing request. */ private boolean canResizeToBounds(Rect bounds) { - if (bounds == null || getStackId() != FREEFORM_WORKSPACE_STACK_ID) { + if (bounds == null || !inFreeformWindowingMode()) { // Note: If not on the freeform workspace, we ignore the bounds. return true; } @@ -1559,6 +1559,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // values in the TaskRecord. String label = null; String iconFilename = null; + int iconResource = -1; int colorPrimary = 0; int colorBackground = 0; int statusBarColor = 0; @@ -1570,6 +1571,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi if (label == null) { label = r.taskDescription.getLabel(); } + if (iconResource == -1) { + iconResource = r.taskDescription.getIconResource(); + } if (iconFilename == null) { iconFilename = r.taskDescription.getIconFilename(); } @@ -1584,8 +1588,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } topActivity = false; } - lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary, - colorBackground, statusBarColor, navigationBarColor); + lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename, + colorPrimary, colorBackground, statusBarColor, navigationBarColor); if (mWindowContainerController != null) { mWindowContainerController.setTaskDescription(lastTaskDescription); } @@ -1647,8 +1651,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi out.attribute(null, ATTR_USERID, String.valueOf(userId)); out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); - out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime)); - out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime)); out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); if (lastDescription != null) { @@ -1666,7 +1668,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, String.valueOf(mSupportsPictureInPicture)); - out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged)); if (mLastNonFullscreenBounds != null) { out.attribute( null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); @@ -1721,8 +1722,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi boolean userSetupComplete = true; int effectiveUid = -1; String lastDescription = null; - long firstActiveTime = -1; - long lastActiveTime = -1; long lastTimeOnTop = 0; boolean neverRelinquishIdentity = true; int taskId = INVALID_TASK_ID; @@ -1736,7 +1735,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi String callingPackage = ""; int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; boolean supportsPictureInPicture = false; - boolean privileged = false; Rect bounds = null; int minWidth = INVALID_MIN_SIZE; int minHeight = INVALID_MIN_SIZE; @@ -1774,10 +1772,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi effectiveUid = Integer.parseInt(attrValue); } else if (ATTR_TASKTYPE.equals(attrName)) { taskType = Integer.parseInt(attrValue); - } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) { - firstActiveTime = Long.parseLong(attrValue); - } else if (ATTR_LASTACTIVETIME.equals(attrName)) { - lastActiveTime = Long.parseLong(attrValue); } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { lastDescription = attrValue; } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { @@ -1802,8 +1796,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi resizeMode = Integer.parseInt(attrValue); } else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) { supportsPictureInPicture = Boolean.parseBoolean(attrValue); - } else if (ATTR_PRIVILEGED.equals(attrName)) { - privileged = Boolean.parseBoolean(attrValue); } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) { bounds = Rect.unflattenFromString(attrValue); } else if (ATTR_MIN_WIDTH.equals(attrName)) { @@ -1888,10 +1880,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, - activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, - taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, - callingUid, callingPackage, resizeMode, supportsPictureInPicture, privileged, - realActivitySuspended, userSetupComplete, minWidth, minHeight); + activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription, + taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, + callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, + userSetupComplete, minWidth, minHeight); task.updateOverrideConfiguration(bounds); for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { @@ -1911,7 +1903,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // If the task has no requested minimal size, we'd like to enforce a minimal size // so that the user can not render the task too small to manipulate. We don't need // to do this for the pinned stack as the bounds are controlled by the system. - if (getStackId() != PINNED_STACK_ID) { + if (!inPinnedWindowingMode()) { if (minWidth == INVALID_MIN_SIZE) { minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask; } @@ -2085,7 +2077,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return; } - if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { + if (inStack.inFreeformWindowingMode()) { if (!isResizeable()) { throw new IllegalArgumentException("Can not position non-resizeable task=" + this + " in stack=" + inStack); @@ -2220,7 +2212,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode)); pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture); pw.print(" isResizeable=" + isResizeable()); - pw.print(" firstActiveTime=" + firstActiveTime); pw.print(" lastActiveTime=" + lastActiveTime); pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); } |