diff options
14 files changed, 576 insertions, 21 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 788579f001a6..350602c14ded 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10659,6 +10659,15 @@ public final class Settings { public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants"; /** + * Feature flag to enable or disable the activity starts logging feature. + * Type: int (0 for false, 1 for true) + * Default: 0 + * @hide + */ + public static final String ACTIVITY_STARTS_LOGGING_ENABLED + = "activity_starts_logging_enabled"; + + /** * App ops specific settings. * This is encoded as a key=value list, separated by commas. Ex: * diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 5542f003fa7e..71627ab3c0b6 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -97,6 +97,7 @@ public class SettingsBackupTest { private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS = newHashSet( Settings.Global.ACTIVITY_MANAGER_CONSTANTS, + Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, Settings.Global.ADB_ENABLED, Settings.Global.ADD_USERS_WHEN_LOCKED, diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 02f04398d6ac..6cc6221e50d5 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -6180,6 +6180,250 @@ message MetricsEvent { // OS: Q DIALOG_ACCESSIBILITY_HEARINGAID = 1512; + // ACTION: Activity start + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + ACTION_ACTIVITY_START = 1513; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Calling UID + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_CALLING_UID = 1514; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Calling package name + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_CALLING_PACKAGE_NAME = 1515; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Calling UID proc state + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_CALLING_UID_PROC_STATE = 1516; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Calling UID has any visible window + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW = 1517; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Real calling UID + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_REAL_CALLING_UID = 1518; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Real calling UID proc state + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_REAL_CALLING_UID_PROC_STATE = 1519; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Real calling UID has any visible window + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW = 1520; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Target UID + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_TARGET_UID = 1521; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Target UID package name + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_TARGET_PACKAGE_NAME = 1522; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Target UID proc state + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_TARGET_UID_PROC_STATE = 1523; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Target UID has any visible window + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW = 1524; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Target doze whitelist tag + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_TARGET_WHITELIST_TAG = 1525; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Target short component name + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_TARGET_SHORT_COMPONENT_NAME = 1526; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Coming from pending intent + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_COMING_FROM_PENDING_INTENT = 1527; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Intent action + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_INTENT_ACTION = 1528; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record process name + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_PROCESS_NAME = 1529; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record current proc state + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_CUR_PROC_STATE = 1530; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record has client activities + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES = 1531; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record has foreground services + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES = 1532; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record has foreground activities + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES = 1533; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record has top UI + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_HAS_TOP_UI = 1534; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record has overlay UI + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_HAS_OVERLAY_UI = 1535; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Caller app process record pending UI clean + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_PENDING_UI_CLEAN = 1536; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Millis since caller app's process record last interaction event + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT = 1537; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Millis since caller app's process record fg interaction + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION = 1538; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Millis since caller app's process record last became unimportant + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT = 1539; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record launch mode + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_LAUNCH_MODE = 1540; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record target activity + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY = 1541; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record flags + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_FLAGS = 1542; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record real activity + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_REAL_ACTIVITY = 1543; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record short component name + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME = 1544; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record process name + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_PROCESS_NAME = 1545; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record is fullscreen + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_IS_FULLSCREEN = 1546; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record is no display + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY = 1547; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Millis since activity was last visible + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE = 1548; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record's resultTo packageName + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME = 1549; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record's resultTo shortComponentName + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME = 1550; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record is visible + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_IS_VISIBLE = 1551; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Activity record is visible ignoring keyguard + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD = 1552; + + // Tagged data for ACTION_ACTIVITY_START. + // FIELD: Millis since activity's last launch + // CATEGORY: OTHER + // OS: Q (will also ship in PQ1A) + FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH = 1553; // ---- End Q Constants, all Q constants go above this line ---- diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 6550d06b8a12..9bf72fb86cd6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -207,6 +207,10 @@ final class ActivityManagerConstants extends ContentObserver { // Indicates if the processes need to be started asynchronously. public boolean FLAG_PROCESS_START_ASYNC = DEFAULT_PROCESS_START_ASYNC; + // Indicates whether the activity starts logging is enabled. + // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED + boolean mFlagActivityStartsLoggingEnabled; + private final ActivityManagerService mService; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -235,6 +239,12 @@ final class ActivityManagerConstants extends ContentObserver { // memory trimming. public int CUR_TRIM_CACHED_PROCESSES; + private static final Uri ACTIVITY_MANAGER_CONSTANTS_URI = Settings.Global.getUriFor( + Settings.Global.ACTIVITY_MANAGER_CONSTANTS); + + private static final Uri ACTIVITY_STARTS_LOGGING_ENABLED_URI = Settings.Global.getUriFor( + Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED); + public ActivityManagerConstants(ActivityManagerService service, Handler handler) { super(handler); mService = service; @@ -243,9 +253,10 @@ final class ActivityManagerConstants extends ContentObserver { public void start(ContentResolver resolver) { mResolver = resolver; - mResolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.ACTIVITY_MANAGER_CONSTANTS), false, this); + mResolver.registerContentObserver(ACTIVITY_MANAGER_CONSTANTS_URI, false, this); + mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this); updateConstants(); + updateActivityStartsLoggingEnabled(); } public void setOverrideMaxCachedProcesses(int value) { @@ -263,7 +274,12 @@ final class ActivityManagerConstants extends ContentObserver { @Override public void onChange(boolean selfChange, Uri uri) { - updateConstants(); + if (uri == null) return; + if (ACTIVITY_MANAGER_CONSTANTS_URI.equals(uri)) { + updateConstants(); + } else if (ACTIVITY_STARTS_LOGGING_ENABLED_URI.equals(uri)) { + updateActivityStartsLoggingEnabled(); + } } private void updateConstants() { @@ -337,6 +353,11 @@ final class ActivityManagerConstants extends ContentObserver { } } + private void updateActivityStartsLoggingEnabled() { + mFlagActivityStartsLoggingEnabled = Settings.Global.getInt(mResolver, + Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 0) == 1; + } + private void updateMaxCachedProcesses() { CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0 ? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a6600405a633..680f1707ac1b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7216,6 +7216,20 @@ public class ActivityManagerService extends IActivityManager.Stub || mPendingTempWhitelist.indexOfKey(uid) >= 0; } + /** + * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on + * the whitelist + */ + String getPendingTempWhitelistTagForUidLocked(int uid) { + final PendingTempWhitelist ptw = mPendingTempWhitelist.get(uid); + return ptw != null ? ptw.tag : null; + } + + @VisibleForTesting + boolean isActivityStartsLoggingEnabled() { + return mConstants.mFlagActivityStartsLoggingEnabled; + } + private ProviderInfo getProviderInfoLocked(String authority, int userHandle, int pmFlags) { ProviderInfo pi = null; ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userHandle); diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index d3e3af386add..263c34f850ce 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -2,6 +2,7 @@ package com.android.server.am; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.ActivityManager.processStateAmToProto; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; @@ -9,6 +10,7 @@ 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; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ACTIVITY_START; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME; @@ -21,8 +23,48 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TR import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_FLAGS; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_FULLSCREEN; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_LAUNCH_MODE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_PROCESS_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_REAL_ACTIVITY; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_PACKAGE_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_PROC_STATE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_COMING_FROM_PENDING_INTENT; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INTENT_ACTION; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_CUR_PROC_STATE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_OVERLAY_UI; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_TOP_UI; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PENDING_UI_CLEAN; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PROCESS_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_PROC_STATE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_PACKAGE_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_SHORT_COMPONENT_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_PROC_STATE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_WHITELIST_TAG; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_REASON; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_FILTER; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH; @@ -37,6 +79,7 @@ import static com.android.server.am.MemoryStatUtil.MemoryStat; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.dex.ArtManagerInternal; import android.content.pm.dex.PackageOptimizationInfo; @@ -612,6 +655,95 @@ class ActivityMetricsLogger { startupTimeMs); } + void logActivityStart(Intent intent, ProcessRecord callerApp, ActivityRecord r, + int callingUid, String callingPackage, int callingUidProcState, + boolean callingUidHasAnyVisibleWindow, + int realCallingUid, int realCallingUidProcState, + boolean realCallingUidHasAnyVisibleWindow, + int targetUid, String targetPackage, int targetUidProcState, + boolean targetUidHasAnyVisibleWindow, String targetWhitelistTag, + boolean comingFromPendingIntent) { + + final long nowElapsed = SystemClock.elapsedRealtime(); + final long nowUptime = SystemClock.uptimeMillis(); + final LogMaker builder = new LogMaker(ACTION_ACTIVITY_START); + builder.setTimestamp(System.currentTimeMillis()); + builder.addTaggedData(FIELD_CALLING_UID, callingUid); + builder.addTaggedData(FIELD_CALLING_PACKAGE_NAME, callingPackage); + builder.addTaggedData(FIELD_CALLING_UID_PROC_STATE, + processStateAmToProto(callingUidProcState)); + builder.addTaggedData(FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW, + callingUidHasAnyVisibleWindow ? 1 : 0); + builder.addTaggedData(FIELD_REAL_CALLING_UID, realCallingUid); + builder.addTaggedData(FIELD_REAL_CALLING_UID_PROC_STATE, + processStateAmToProto(realCallingUidProcState)); + builder.addTaggedData(FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW, + realCallingUidHasAnyVisibleWindow ? 1 : 0); + builder.addTaggedData(FIELD_TARGET_UID, targetUid); + builder.addTaggedData(FIELD_TARGET_PACKAGE_NAME, targetPackage); + builder.addTaggedData(FIELD_TARGET_UID_PROC_STATE, + processStateAmToProto(targetUidProcState)); + builder.addTaggedData(FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW, + targetUidHasAnyVisibleWindow ? 1 : 0); + builder.addTaggedData(FIELD_TARGET_WHITELIST_TAG, targetWhitelistTag); + builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME, r.shortComponentName); + builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0); + builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction()); + if (callerApp != null) { + builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.processName); + builder.addTaggedData(FIELD_PROCESS_RECORD_CUR_PROC_STATE, + processStateAmToProto(callerApp.curProcState)); + builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES, + callerApp.hasClientActivities ? 1 : 0); + builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES, + callerApp.hasForegroundServices() ? 1 : 0); + builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES, + callerApp.foregroundActivities ? 1 : 0); + builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_TOP_UI, callerApp.hasTopUi ? 1 : 0); + builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_OVERLAY_UI, + callerApp.hasOverlayUi ? 1 : 0); + builder.addTaggedData(FIELD_PROCESS_RECORD_PENDING_UI_CLEAN, + callerApp.pendingUiClean ? 1 : 0); + if (callerApp.interactionEventTime != 0) { + builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT, + (nowElapsed - callerApp.interactionEventTime)); + } + if (callerApp.fgInteractionTime != 0) { + builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION, + (nowElapsed - callerApp.fgInteractionTime)); + } + if (callerApp.whenUnimportant != 0) { + builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT, + (nowUptime - callerApp.whenUnimportant)); + } + } + builder.addTaggedData(FIELD_ACTIVITY_RECORD_LAUNCH_MODE, r.info.launchMode); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY, r.info.targetActivity); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_FLAGS, r.info.flags); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_REAL_ACTIVITY, r.realActivity.toShortString()); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME, r.shortComponentName); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_PROCESS_NAME, r.processName); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_FULLSCREEN, r.fullscreen ? 1 : 0); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY, r.noDisplay ? 1 : 0); + if (r.lastVisibleTime != 0) { + builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE, + (nowUptime - r.lastVisibleTime)); + } + if (r.resultTo != null) { + builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME, r.resultTo.packageName); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME, + r.resultTo.shortComponentName); + } + builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE, r.visible ? 1 : 0); + builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD, + r.visibleIgnoringKeyguard ? 1 : 0); + if (r.lastLaunchTime != 0) { + builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH, + (nowUptime - r.lastLaunchTime)); + } + mMetricsLogger.write(builder); + } + private int getTransitionType(WindowingModeTransitionInfo info) { if (info.currentTransitionProcessRunning) { if (info.startResult == START_SUCCESS) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 27a4460da937..9809bfa38252 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -4863,7 +4863,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return mService.getActivityStartController().startActivityInPackage( task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null, null, 0, 0, options, userId, task, "startActivityFromRecents", - false /* validateIncomingUser */); + false /* validateIncomingUser */, null /* originatingPendingIntent */); } finally { if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) { // If we are launching the task in the docked stack, put it into resizing mode so diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index 2cba720612cc..6e3a79c3aa95 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -249,7 +249,8 @@ public class ActivityStartController { final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, SafeActivityOptions options, - int userId, TaskRecord inTask, String reason, boolean validateIncomingUser) { + int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, + PendingIntentRecord originatingPendingIntent) { userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid, reason); @@ -268,6 +269,7 @@ public class ActivityStartController { .setActivityOptions(options) .setMayWait(userId) .setInTask(inTask) + .setOriginatingPendingIntent(originatingPendingIntent) .execute(); } @@ -279,10 +281,12 @@ public class ActivityStartController { * @param intents Intents to start. * @param userId Start the intents on this user. * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID. + * @param originatingPendingIntent PendingIntentRecord that originated this activity start or + * null if not originated by PendingIntent */ final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, - boolean validateIncomingUser) { + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) { final String reason = "startActivityInPackage"; @@ -291,12 +295,12 @@ public class ActivityStartController { // TODO: Switch to user app stacks here. return startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, options, - userId, reason); + userId, reason, originatingPendingIntent); } int startActivities(IApplicationThread caller, int callingUid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, - int userId, String reason) { + int userId, String reason, PendingIntentRecord originatingPendingIntent) { if (intents == null) { throw new NullPointerException("intents is null"); } @@ -375,6 +379,7 @@ public class ActivityStartController { // Top activity decides on animation being run, so we allow only for the // top one as otherwise an activity below might consume it. .setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/) + .setOriginatingPendingIntent(originatingPendingIntent) .execute(); if (res < 0) { diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 05fae837364a..dcf93441659e 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -99,6 +99,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; +import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.service.voice.IVoiceInteractionSession; @@ -313,6 +314,7 @@ class ActivityStarter { int userId; WaitResult waitResult; int filterCallingUid; + PendingIntentRecord originatingPendingIntent; /** * If set to {@code true}, allows this activity start to look into @@ -369,6 +371,7 @@ class ActivityStarter { avoidMoveToFront = false; allowPendingRemoteAnimationRegistryLookup = true; filterCallingUid = UserHandle.USER_NULL; + originatingPendingIntent = null; } /** @@ -407,6 +410,7 @@ class ActivityStarter { allowPendingRemoteAnimationRegistryLookup = request.allowPendingRemoteAnimationRegistryLookup; filterCallingUid = request.filterCallingUid; + originatingPendingIntent = request.originatingPendingIntent; } } @@ -490,7 +494,8 @@ class ActivityStarter { mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId, mRequest.inTask, mRequest.reason, - mRequest.allowPendingRemoteAnimationRegistryLookup); + mRequest.allowPendingRemoteAnimationRegistryLookup, + mRequest.originatingPendingIntent); } else { return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo, @@ -500,7 +505,8 @@ class ActivityStarter { mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.componentSpecified, mRequest.outActivity, mRequest.inTask, mRequest.reason, - mRequest.allowPendingRemoteAnimationRegistryLookup); + mRequest.allowPendingRemoteAnimationRegistryLookup, + mRequest.originatingPendingIntent); } } finally { onExecutionComplete(); @@ -532,7 +538,8 @@ class ActivityStarter { String callingPackage, int realCallingPid, int realCallingUid, int startFlags, SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, TaskRecord inTask, String reason, - boolean allowPendingRemoteAnimationRegistryLookup) { + boolean allowPendingRemoteAnimationRegistryLookup, + PendingIntentRecord originatingPendingIntent) { if (TextUtils.isEmpty(reason)) { throw new IllegalArgumentException("Need to specify a reason."); @@ -545,7 +552,7 @@ class ActivityStarter { aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord, - inTask, allowPendingRemoteAnimationRegistryLookup); + inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent); if (outActivity != null) { // mLastStartActivityRecord[0] is set in the call to startActivity above. @@ -575,7 +582,8 @@ class ActivityStarter { String callingPackage, int realCallingPid, int realCallingUid, int startFlags, SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, - TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) { + TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup, + PendingIntentRecord originatingPendingIntent) { int err = ActivityManager.START_SUCCESS; // Pull the optional Ephemeral Installer-only bundle out of the options early. final Bundle verificationBundle @@ -857,10 +865,58 @@ class ActivityStarter { mService.onStartActivitySetDidAppSwitch(); mController.doPendingActivityLaunches(false); + maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp, r, + originatingPendingIntent); + return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, outActivity); } + private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid, + Intent intent, ProcessRecord callerApp, ActivityRecord r, + PendingIntentRecord originatingPendingIntent) { + boolean callerAppHasForegroundActivity = (callerApp != null) + ? callerApp.foregroundActivities + : false; + if (!mService.mAm.isActivityStartsLoggingEnabled() || callerAppHasForegroundActivity + || r == null) { + // skip logging in this case + return; + } + + try { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "logActivityStart"); + final int callingUidProcState = mService.mAm.getUidStateLocked(callingUid); + final boolean callingUidHasAnyVisibleWindow = + mService.mWindowManager.isAnyWindowVisibleForUid(callingUid); + final int realCallingUidProcState = (callingUid == realCallingUid) + ? callingUidProcState + : mService.mAm.getUidStateLocked(realCallingUid); + final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid) + ? callingUidHasAnyVisibleWindow + : mService.mWindowManager.isAnyWindowVisibleForUid(realCallingUid); + final String targetPackage = r.packageName; + final int targetUid = (r.appInfo != null) ? r.appInfo.uid : -1; + final int targetUidProcState = mService.mAm.getUidStateLocked(targetUid); + final boolean targetUidHasAnyVisibleWindow = (targetUid != -1) + ? mService.mWindowManager.isAnyWindowVisibleForUid(targetUid) + : false; + final String targetWhitelistTag = (targetUid != -1) + ? mService.mAm.getPendingTempWhitelistTagForUidLocked(targetUid) + : null; + + mSupervisor.getActivityMetricsLogger().logActivityStart(intent, callerApp, r, + callingUid, callingPackage, callingUidProcState, + callingUidHasAnyVisibleWindow, + realCallingUid, realCallingUidProcState, + realCallingUidHasAnyVisibleWindow, + targetUid, targetPackage, targetUidProcState, + targetUidHasAnyVisibleWindow, targetWhitelistTag, + (originatingPendingIntent != null)); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + } /** * Creates a launch intent for the given auxiliary resolution data. @@ -941,7 +997,8 @@ class ActivityStarter { ProfilerInfo profilerInfo, WaitResult outResult, Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity, int userId, TaskRecord inTask, String reason, - boolean allowPendingRemoteAnimationRegistryLookup) { + boolean allowPendingRemoteAnimationRegistryLookup, + PendingIntentRecord originatingPendingIntent) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -1087,7 +1144,7 @@ class ActivityStarter { voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason, - allowPendingRemoteAnimationRegistryLookup); + allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent); Binder.restoreCallingIdentity(origId); @@ -2615,6 +2672,11 @@ class ActivityStarter { return this; } + ActivityStarter setOriginatingPendingIntent(PendingIntentRecord originatingPendingIntent) { + mRequest.originatingPendingIntent = originatingPendingIntent; + return this; + } + void dump(PrintWriter pw, String prefix) { prefix = prefix + " "; pw.print(prefix); diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 68b1d762644d..11f8bb1e2883 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -727,7 +727,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason); // TODO: Switch to user app stacks here. return getActivityStartController().startActivities(caller, -1, callingPackage, intents, - resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, reason); + resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, reason, + null /* originatingPendingIntent */); } @Override @@ -5093,7 +5094,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { packageUid, packageName, intents, resolvedTypes, null /* resultTo */, SafeActivityOptions.fromBundle(bOptions), userId, - false /* validateIncomingUser */); + false /* validateIncomingUser */, null /* originatingPendingIntent */); } } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 3b98f373d817..162f344d012f 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -491,7 +491,8 @@ class AppErrors { task.intent, null, null, null, 0, 0, new SafeActivityOptions(ActivityOptions.makeBasic()), task.userId, null, - "AppErrors", false /*validateIncomingUser*/); + "AppErrors", false /*validateIncomingUser*/, + null /* originatingPendingIntent */); } } } diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index db0916523056..ee1166e2a6e8 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -307,7 +307,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { } else if (finalIntent.getComponent() != null) { finalIntent.getComponent().appendShortString(tag); } else if (finalIntent.getData() != null) { - tag.append(finalIntent.getData()); + tag.append(finalIntent.getData().toSafeString()); } owner.tempWhitelistForPendingIntentLocked(callingPid, callingUid, uid, duration, tag.toString()); @@ -346,13 +346,15 @@ final class PendingIntentRecord extends IIntentSender.Stub { res = owner.mActivityTaskManager.getActivityStartController().startActivitiesInPackage( uid, key.packageName, allIntents, allResolvedTypes, resultTo, mergedOptions, userId, - false /* validateIncomingUser */); + false /* validateIncomingUser */, + this /* originatingPendingIntent */); } else { res = owner.mActivityTaskManager.getActivityStartController().startActivityInPackage(uid, callingPid, callingUid, key.packageName, finalIntent, resolvedType, resultTo, resultWho, requestCode, 0, mergedOptions, userId, null, "PendingIntentRecord", - false /* validateIncomingUser */); + false /* validateIncomingUser */, + this /* originatingPendingIntent */); } } catch (RuntimeException e) { Slog.w(TAG, "Unable to send startActivity intent", e); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0015693ec0db..3acecba8db26 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6204,6 +6204,17 @@ public class WindowManagerService extends IWindowManager.Stub } /** + * Returns true if the callingUid has any window currently visible to the user. + */ + public boolean isAnyWindowVisibleForUid(int callingUid) { + synchronized (mWindowMap) { + return mRoot.forAllWindows(w -> { + return w.getOwningUid() == callingUid && w.isVisible(); + }, true /* traverseTopToBottom */); + } + } + + /** * Called when a task has been removed from the recent tasks list. * <p> * Note: This doesn't go through {@link TaskWindowContainerController} yet as the window diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java index 409a2a84210b..90607adacaf3 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java @@ -54,6 +54,7 @@ import android.view.Gravity; import org.junit.runner.RunWith; import org.junit.Test; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED; import static com.android.server.am.ActivityManagerService.ANIMATE; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; @@ -64,11 +65,13 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyObject; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.times; @@ -92,6 +95,7 @@ public class ActivityStarterTests extends ActivityTestsBase { private ActivityTaskManagerService mService; private ActivityStarter mStarter; private ActivityStartController mController; + private ActivityMetricsLogger mActivityMetricsLogger; private static final int PRECONDITION_NO_CALLER_APP = 1; private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1; @@ -105,11 +109,17 @@ public class ActivityStarterTests extends ActivityTestsBase { private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9; private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10; + private static final int FAKE_CALLING_UID = 666; + private static final int FAKE_REAL_CALLING_UID = 667; + private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude"; + @Override public void setUp() throws Exception { super.setUp(); mService = createActivityTaskManagerService(); mController = mock(ActivityStartController.class); + mActivityMetricsLogger = mock(ActivityMetricsLogger.class); + clearInvocations(mActivityMetricsLogger); mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor, mock(ActivityStartInterceptor.class)); } @@ -480,4 +490,46 @@ public class ActivityStarterTests extends ActivityTestsBase { assertTrue(stack.getAllTasks().isEmpty()); } } + + /** + * This test ensures that activity starts are not being logged when the logging is disabled. + */ + @Test + public void testActivityStartsLogging_noLoggingWhenDisabled() { + doReturn(false).when(mService.mAm).isActivityStartsLoggingEnabled(); + doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger(); + + ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK); + starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute(); + + // verify logging wasn't done + verify(mActivityMetricsLogger, never()).logActivityStart(any(), any(), any(), anyInt(), + any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyInt(), any(), + anyInt(), anyBoolean(), any(), anyBoolean()); + } + + /** + * This test ensures that activity starts are being logged when the logging is enabled. + */ + @Test + public void testActivityStartsLogging_logsWhenEnabled() { + // note: conveniently this package doesn't have any activity visible + doReturn(true).when(mService.mAm).isActivityStartsLoggingEnabled(); + doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger(); + + ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK) + .setCallingUid(FAKE_CALLING_UID) + .setRealCallingUid(FAKE_REAL_CALLING_UID) + .setCallingPackage(FAKE_CALLING_PACKAGE) + .setOriginatingPendingIntent(null); + + starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute(); + + // verify the above activity start was logged + verify(mActivityMetricsLogger, times(1)).logActivityStart(any(), any(), any(), + eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(), + eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), anyInt(), + eq(ActivityBuilder.getDefaultComponent().getPackageName()), anyInt(), anyBoolean(), + any(), eq(false)); + } } |