From 7f9368637c8d2726b87cbe184b240512055da037 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Tue, 9 May 2017 15:33:18 -0700 Subject: [PATCH] Introduce result ranges for activity start return results. The return result from starting activity actually represents two pieces of information. First, it conveys whether the activity started. Secondly, it conveys whether there was a fatal error if the activity did not start. Many parts of the code assume that a value greater than or equal to the defined success means that the activity successfully started. This is not the case as there are a number of results greater than success where the activity does not start. This change addresses the issue by introducing three distinct result ranges. The first represents results where the activity could not start due to a fatal error. The second represents results where the activity did not start due to a non-fatal error. The last range represents successful activity starts. Two convenience methods have been added to ActivityManager to return whether the result represents a fatal error and whether the result was successful. Change-Id: Ifaf844c353641a28b03b3c2d7b6be053fd9b8b44 Fixes: 38021882 Test: cts-tradefed run cts-dev --module DevicePolicyManager --test com.android.cts.devicepolicy.DeviceOwnerTest#testLockTask_deviceOwnerUser --- core/java/android/app/ActivityManager.java | 60 ++++++++++++++----- core/java/android/app/Instrumentation.java | 2 +- .../keyguard/WorkLockActivityController.java | 2 +- .../android/server/UiModeManagerService.java | 2 +- .../android/server/am/ActivityStarter.java | 5 +- .../server/pm/LauncherAppsService.java | 4 +- 6 files changed, 52 insertions(+), 23 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 9af74ba29d2bb..09252175a1dbd 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -126,6 +126,14 @@ public class ActivityManager { private static volatile boolean sSystemReady = false; + + private static final int FIRST_START_FATAL_ERROR_CODE = -100; + private static final int LAST_START_FATAL_ERROR_CODE = -1; + private static final int FIRST_START_SUCCESS_CODE = 0; + private static final int LAST_START_SUCCESS_CODE = 99; + private static final int FIRST_START_NON_FATAL_ERROR_CODE = 100; + private static final int LAST_START_NON_FATAL_ERROR_CODE = 199; + /** * System property to enable task snapshots. * @hide @@ -219,53 +227,56 @@ public class ActivityManager { */ public static final String META_HOME_ALTERNATE = "android.app.home.alternate"; + // NOTE: Before adding a new start result, please reference the defined ranges to ensure the + // result is properly categorized. + /** * Result for IActivityManager.startVoiceActivity: active session is currently hidden. * @hide */ - public static final int START_VOICE_HIDDEN_SESSION = -10; + public static final int START_VOICE_HIDDEN_SESSION = FIRST_START_FATAL_ERROR_CODE; /** * Result for IActivityManager.startVoiceActivity: active session does not match * the requesting token. * @hide */ - public static final int START_VOICE_NOT_ACTIVE_SESSION = -9; + public static final int START_VOICE_NOT_ACTIVE_SESSION = FIRST_START_FATAL_ERROR_CODE + 1; /** * Result for IActivityManager.startActivity: trying to start a background user * activity that shouldn't be displayed for all users. * @hide */ - public static final int START_NOT_CURRENT_USER_ACTIVITY = -8; + public static final int START_NOT_CURRENT_USER_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 2; /** * Result for IActivityManager.startActivity: trying to start an activity under voice * control when that activity does not support the VOICE category. * @hide */ - public static final int START_NOT_VOICE_COMPATIBLE = -7; + public static final int START_NOT_VOICE_COMPATIBLE = FIRST_START_FATAL_ERROR_CODE + 3; /** * Result for IActivityManager.startActivity: an error where the * start had to be canceled. * @hide */ - public static final int START_CANCELED = -6; + public static final int START_CANCELED = FIRST_START_FATAL_ERROR_CODE + 4; /** * Result for IActivityManager.startActivity: an error where the * thing being started is not an activity. * @hide */ - public static final int START_NOT_ACTIVITY = -5; + public static final int START_NOT_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 5; /** * Result for IActivityManager.startActivity: an error where the * caller does not have permission to start the activity. * @hide */ - public static final int START_PERMISSION_DENIED = -4; + public static final int START_PERMISSION_DENIED = FIRST_START_FATAL_ERROR_CODE + 6; /** * Result for IActivityManager.startActivity: an error where the @@ -273,49 +284,49 @@ public class ActivityManager { * a result. * @hide */ - public static final int START_FORWARD_AND_REQUEST_CONFLICT = -3; + public static final int START_FORWARD_AND_REQUEST_CONFLICT = FIRST_START_FATAL_ERROR_CODE + 7; /** * Result for IActivityManager.startActivity: an error where the * requested class is not found. * @hide */ - public static final int START_CLASS_NOT_FOUND = -2; + public static final int START_CLASS_NOT_FOUND = FIRST_START_FATAL_ERROR_CODE + 8; /** * Result for IActivityManager.startActivity: an error where the * given Intent could not be resolved to an activity. * @hide */ - public static final int START_INTENT_NOT_RESOLVED = -1; + public static final int START_INTENT_NOT_RESOLVED = FIRST_START_FATAL_ERROR_CODE + 9; /** * Result for IActivityManaqer.startActivity: the activity was started * successfully as normal. * @hide */ - public static final int START_SUCCESS = 0; + public static final int START_SUCCESS = FIRST_START_SUCCESS_CODE; /** * Result for IActivityManaqer.startActivity: the caller asked that the Intent not * be executed if it is the recipient, and that is indeed the case. * @hide */ - public static final int START_RETURN_INTENT_TO_CALLER = 1; + public static final int START_RETURN_INTENT_TO_CALLER = FIRST_START_SUCCESS_CODE + 1; /** * Result for IActivityManaqer.startActivity: activity wasn't really started, but * a task was simply brought to the foreground. * @hide */ - public static final int START_TASK_TO_FRONT = 2; + public static final int START_TASK_TO_FRONT = FIRST_START_SUCCESS_CODE + 2; /** * Result for IActivityManaqer.startActivity: activity wasn't really started, but * the given Intent was given to the existing top activity. * @hide */ - public static final int START_DELIVERED_TO_TOP = 3; + public static final int START_DELIVERED_TO_TOP = FIRST_START_SUCCESS_CODE + 3; /** * Result for IActivityManaqer.startActivity: request was canceled because @@ -323,14 +334,15 @@ public class ActivityManager { * (such as pressing home) is performed. * @hide */ - public static final int START_SWITCHES_CANCELED = 4; + public static final int START_SWITCHES_CANCELED = FIRST_START_NON_FATAL_ERROR_CODE; /** * Result for IActivityManaqer.startActivity: a new activity was attempted to be started * while in Lock Task Mode. * @hide */ - public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION = 5; + public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION = + FIRST_START_NON_FATAL_ERROR_CODE + 1; /** * Flag for IActivityManaqer.startActivity: do special start mode where @@ -565,6 +577,22 @@ public class ActivityManager { mContext = context; } + /** + * Returns whether the launch was successful. + * @hide + */ + public static final boolean isStartResultSuccessful(int result) { + return FIRST_START_SUCCESS_CODE <= result && result <= LAST_START_SUCCESS_CODE; + } + + /** + * Returns whether the launch result was a fatal error. + * @hide + */ + public static final boolean isStartResultFatalError(int result) { + return FIRST_START_FATAL_ERROR_CODE <= result && result <= LAST_START_FATAL_ERROR_CODE; + } + /** * Screen compatibility mode: the application most always run in * compatibility mode. diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 69ed439799f72..16cbb7c368476 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1921,7 +1921,7 @@ public class Instrumentation { /** @hide */ public static void checkStartActivityResult(int res, Object intent) { - if (res >= ActivityManager.START_SUCCESS) { + if (!ActivityManager.isStartResultFatalError(res)) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java index 5eb483d692b76..f198229af6914 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java @@ -64,7 +64,7 @@ public class WorkLockActivityController { options.setTaskOverlay(true, false /* canResume */); final int result = startActivityAsUser(intent, options.toBundle(), UserHandle.USER_CURRENT); - if (result >= ActivityManager.START_SUCCESS) { + if (ActivityManager.isStartResultSuccessful(result)) { // OK } else { // Starting the activity inside the task failed. We can't be sure why, so to be diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 04421cc7ee3c4..6b5366a39a437 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -640,7 +640,7 @@ final class UiModeManagerService extends SystemService { int result = ActivityManager.getService().startActivityWithConfig( null, null, homeIntent, null, null, null, 0, 0, mConfiguration, null, UserHandle.USER_CURRENT); - if (result >= ActivityManager.START_SUCCESS) { + if (ActivityManager.isStartResultSuccessful(result)) { dockAppStarted = true; } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) { Slog.e(TAG, "Could not start dock app: " + homeIntent diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 6d4eb5b03d89e..a2eec5c4bfae0 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -544,7 +544,7 @@ class ActivityStarter { ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord, ActivityStack targetStack) { - if (result < START_SUCCESS) { + if (ActivityManager.isStartResultFatalError(result)) { return; } @@ -956,7 +956,8 @@ class ActivityStarter { // If we are not able to proceed, disassociate the activity from the task. Leaving an // activity in an incomplete state can lead to issues, such as performing operations // without a window container. - if (result < START_SUCCESS && mStartActivity.getTask() != null) { + if (ActivityManager.isStartResultFatalError(result) + && mStartActivity.getTask() != null) { mStartActivity.getTask().removeActivity(mStartActivity); } mService.mWindowManager.continueSurfaceLayout(); diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index f79f6f40294c7..29f9f7c709bbc 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -546,12 +546,12 @@ public class LauncherAppsService extends SystemService { try { code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage, userId, intents, startActivityOptions); - if (code >= ActivityManager.START_SUCCESS) { + if (ActivityManager.isStartResultSuccessful(code)) { return true; // Success } else { Log.e(TAG, "Couldn't start activity, code=" + code); } - return code >= ActivityManager.START_SUCCESS; + return false; } catch (SecurityException e) { if (DEBUG) { Slog.d(TAG, "SecurityException while launching intent", e);