From 4fb8913bfce814e153ac91fdc8a7d3191cc52eab Mon Sep 17 00:00:00 2001 From: Yu-Ting Tseng Date: Thu, 19 Jan 2023 09:34:35 -0800 Subject: [PATCH] Log BAL and full screen intent to statsd. Test: atest StatusBarNotificationActivityStarterTest Test: atest ActivityStarterTests Bug: 261910877 Change-Id: I4fdfbe80ea0c368a4809e5613e5f9c3a8369e2a3 --- .../StatusBarNotificationActivityStarter.java | 25 +++- ...tusBarNotificationActivityStarterTest.java | 46 ++++++- .../wm/BackgroundActivityStartController.java | 122 +++++++++++------- .../wm/BackgroundLaunchProcessController.java | 42 +++--- .../server/wm/ActivityStarterTests.java | 66 ++++++++++ 5 files changed, 222 insertions(+), 79 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 078a00d33493d..3471a46566372 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -27,6 +27,7 @@ import android.app.PendingIntent; import android.app.TaskStackBuilder; import android.content.Context; import android.content.Intent; +import android.content.pm.ResolveInfo; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; @@ -45,6 +46,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.NotificationVisibility; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.ActivityIntentHelper; import com.android.systemui.EventLogTags; @@ -74,12 +76,14 @@ import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.wmshell.BubblesManager; +import dagger.Lazy; + +import java.util.List; import java.util.Optional; import java.util.concurrent.Executor; import javax.inject.Inject; -import dagger.Lazy; /** * Status bar implementation of {@link NotificationActivityStarter}. @@ -572,16 +576,29 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte }); // not immersive & a fullscreen alert should be shown - final PendingIntent fullscreenIntent = + final PendingIntent fullScreenIntent = entry.getSbn().getNotification().fullScreenIntent; - mLogger.logSendingFullScreenIntent(entry, fullscreenIntent); + mLogger.logSendingFullScreenIntent(entry, fullScreenIntent); try { EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, entry.getKey()); mCentralSurfaces.wakeUpForFullScreenIntent(); - fullscreenIntent.send(); + fullScreenIntent.send(); entry.notifyFullScreenIntentLaunched(); mMetricsLogger.count("note_fullscreen", 1); + + String activityName; + List resolveInfos = fullScreenIntent.queryIntentComponents(0); + if (resolveInfos.size() > 0 && resolveInfos.get(0) != null + && resolveInfos.get(0).activityInfo != null + && resolveInfos.get(0).activityInfo.name != null) { + activityName = resolveInfos.get(0).activityInfo.name; + } else { + activityName = ""; + } + FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED, + fullScreenIntent.getCreatorUid(), + activityName); } catch (PendingIntent.CanceledException e) { // ignore } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index ccc57ad72f364..ee7e082c839f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -18,6 +18,9 @@ package com.android.systemui.statusbar.phone; import static android.service.notification.NotificationListenerService.REASON_CLICK; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + import static org.mockito.AdditionalAnswers.answerVoid; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -28,7 +31,6 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @@ -38,6 +40,8 @@ import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.pm.ActivityInfo; +import android.content.pm.ResolveInfo; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; @@ -51,6 +55,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.NotificationVisibility; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.ActivityIntentHelper; import com.android.systemui.SysuiTestCase; @@ -90,9 +95,12 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -398,4 +406,40 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // THEN display should try wake up for the full screen intent verify(mCentralSurfaces).wakeUpForFullScreenIntent(); } + + @Test + public void testOnFullScreenIntentWhenDozing_logToStatsd() { + final int kTestUid = 12345; + final String kTestActivityName = "TestActivity"; + // GIVEN entry that can has a full screen intent that can show + PendingIntent mockFullScreenIntent = mock(PendingIntent.class); + when(mockFullScreenIntent.getCreatorUid()).thenReturn(kTestUid); + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.activityInfo = new ActivityInfo(); + resolveInfo.activityInfo.name = kTestActivityName; + when(mockFullScreenIntent.queryIntentComponents(anyInt())) + .thenReturn(Arrays.asList(resolveInfo)); + Notification.Builder nb = new Notification.Builder(mContext, "a") + .setContentTitle("foo") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setFullScreenIntent(mockFullScreenIntent, true); + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, + "tag" + System.currentTimeMillis(), 0, 0, + nb.build(), new UserHandle(0), null, 0); + NotificationEntry entry = mock(NotificationEntry.class); + when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH); + when(entry.getSbn()).thenReturn(sbn); + MockitoSession mockingSession = mockitoSession() + .mockStatic(FrameworkStatsLog.class) + .strictness(Strictness.LENIENT) + .startMocking(); + + // WHEN + mNotificationActivityStarter.launchFullScreenIntent(entry); + + // THEN the full screen intent should be logged to statsd. + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED, + kTestUid, kTestActivityName)); + mockingSession.finishMocking(); + } } diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index f452378e998a0..587138ded8cb4 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -45,6 +45,7 @@ import android.util.ArraySet; import android.util.DebugUtils; import android.util.Slog; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.am.PendingIntentRecord; import java.lang.annotation.Retention; @@ -176,22 +177,24 @@ public class BackgroundActivityStartController { if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID || callingAppId == Process.NFC_UID) { - return logStartAllowedAndReturnCode(/*background*/ false, callingUid, - BAL_ALLOW_ALLOWLISTED_UID, "Important callingUid"); + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false, + callingUid, realCallingUid, intent, "Important callingUid"); } // Always allow home application to start activities. if (isHomeApp(callingUid, callingPackage)) { - return logStartAllowedAndReturnCode(/*background*/ false, callingUid, - BAL_ALLOW_ALLOWLISTED_COMPONENT, "Home app"); + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ false, callingUid, realCallingUid, intent, + "Home app"); } // IME should always be allowed to start activity, like IME settings. final WindowState imeWindow = mService.mRootWindowContainer.getCurrentInputMethodWindow(); if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) { - return logStartAllowedAndReturnCode(/*background*/ false, callingUid, - BAL_ALLOW_ALLOWLISTED_COMPONENT, "Active ime"); + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ false, callingUid, realCallingUid, intent, + "Active ime"); } } @@ -218,8 +221,8 @@ public class BackgroundActivityStartController { && callingUidHasAnyVisibleWindow) || isCallingUidPersistentSystemProcess; if (useCallingUidState && allowCallingUidStartActivity) { - return logStartAllowedAndReturnCode(/*background*/ false, - BAL_ALLOW_VISIBLE_WINDOW, + return logStartAllowedAndReturnCode(BAL_ALLOW_VISIBLE_WINDOW, + /*background*/ false, callingUid, realCallingUid, intent, "callingUidHasAnyVisibleWindow = " + callingUid + ", isCallingUidPersistentSystemProcess = " @@ -254,8 +257,8 @@ public class BackgroundActivityStartController { Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid)); if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) { - return logStartAllowedAndReturnCode(/*background*/ false, realCallingUid, - BAL_ALLOW_SDK_SANDBOX, + return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX, + /*background*/ false, callingUid, realCallingUid, intent, "uid in SDK sandbox has visible (non-toast) window"); } } @@ -276,16 +279,16 @@ public class BackgroundActivityStartController { -1, true) == PackageManager.PERMISSION_GRANTED) { - return logStartAllowedAndReturnCode(/*background*/ false, callingUid, - BAL_ALLOW_PENDING_INTENT, + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, "realCallingUid has BAL permission. realCallingUid: " + realCallingUid); } // don't abort if the realCallingUid has a visible window // TODO(b/171459802): We should check appSwitchAllowed also if (realCallingUidHasAnyVisibleWindow) { - return logStartAllowedAndReturnCode(/*background*/ false, - callingUid, BAL_ALLOW_PENDING_INTENT, + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, "realCallingUid has visible (non-toast) window. realCallingUid: " + realCallingUid); } @@ -293,9 +296,8 @@ public class BackgroundActivityStartController { // wasn't allowed to start an activity if (isRealCallingUidPersistentSystemProcess && backgroundStartPrivileges.allowsBackgroundActivityStarts()) { - return logStartAllowedAndReturnCode(/*background*/ false, - callingUid, - BAL_ALLOW_PENDING_INTENT, + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, "realCallingUid is persistent system process AND intent " + "sender allowed (allowBackgroundActivityStart = true). " + "realCallingUid: " + realCallingUid); @@ -303,8 +305,9 @@ public class BackgroundActivityStartController { // don't abort if the realCallingUid is an associated companion app if (mService.isAssociatedCompanionApp( UserHandle.getUserId(realCallingUid), realCallingUid)) { - return logStartAllowedAndReturnCode(/*background*/ false, callingUid, - BAL_ALLOW_PENDING_INTENT, "realCallingUid is a companion app. " + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, + "realCallingUid is a companion app. " + "realCallingUid: " + realCallingUid); } } @@ -312,25 +315,28 @@ public class BackgroundActivityStartController { // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid) == PERMISSION_GRANTED) { - return logStartAllowedAndReturnCode(/*background*/ true, callingUid, - BAL_ALLOW_PERMISSION, + return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION, + /*background*/ true, callingUid, realCallingUid, intent, "START_ACTIVITIES_FROM_BACKGROUND permission granted"); } // don't abort if the caller has the same uid as the recents component if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) { - return logStartAllowedAndReturnCode(/*background*/ true, callingUid, - BAL_ALLOW_ALLOWLISTED_COMPONENT, "Recents Component"); + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ true, callingUid, realCallingUid, + intent, "Recents Component"); } // don't abort if the callingUid is the device owner if (mService.isDeviceOwner(callingUid)) { - return logStartAllowedAndReturnCode(/*background*/ true, callingUid, - BAL_ALLOW_ALLOWLISTED_COMPONENT, "Device Owner"); + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ true, callingUid, realCallingUid, + intent, "Device Owner"); } // don't abort if the callingUid has companion device final int callingUserId = UserHandle.getUserId(callingUid); if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) { - return logStartAllowedAndReturnCode(/*background*/ true, callingUid, - BAL_ALLOW_ALLOWLISTED_COMPONENT, "Companion App"); + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ true, callingUid, realCallingUid, + intent, "Companion App"); } // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) { @@ -339,8 +345,9 @@ public class BackgroundActivityStartController { "Background activity start for " + callingPackage + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); - return logStartAllowedAndReturnCode(/*background*/ true, callingUid, - BAL_ALLOW_SAW_PERMISSION, "SYSTEM_ALERT_WINDOW permission is granted"); + return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION, + /*background*/ true, callingUid, realCallingUid, + intent, "SYSTEM_ALERT_WINDOW permission is granted"); } // don't abort if the callingUid and callingPackage have the // OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop @@ -349,9 +356,9 @@ public class BackgroundActivityStartController { callingUid, callingPackage) == AppOpsManager.MODE_ALLOWED) { - return logStartAllowedAndReturnCode(/*background*/ true, callingUid, - BAL_ALLOW_PERMISSION, - "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted"); + return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION, + /*background*/ true, callingUid, realCallingUid, intent, + "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted"); } } // If we don't have callerApp at this point, no caller was provided to startActivity(). @@ -369,7 +376,8 @@ public class BackgroundActivityStartController { @BalCode int balAllowedForCaller = callerApp .areBackgroundActivityStartsAllowed(appSwitchState); if (balAllowedForCaller != BAL_BLOCK) { - return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForCaller, + return logStartAllowedAndReturnCode(balAllowedForCaller, + /*background*/ true, callingUid, realCallingUid, intent, "callerApp process (pid = " + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed"); } @@ -382,7 +390,8 @@ public class BackgroundActivityStartController { int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState); if (proc != callerApp && balAllowedForUid != BAL_BLOCK) { - return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForUid, + return logStartAllowedAndReturnCode(balAllowedForUid, + /*background*/ true, callingUid, realCallingUid, intent, "process" + proc.getPid() + " from uid " + callerAppUid + " is allowed"); } @@ -448,27 +457,21 @@ public class BackgroundActivityStartController { return BAL_BLOCK; } - private int logStartAllowedAndReturnCode(boolean background, int callingUid, int code, - String msg) { - if (DEBUG_ACTIVITY_STARTS) { - return logStartAllowedAndReturnCode(background, code, - msg, "callingUid: " + callingUid); - } - return code; + static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background, + int callingUid, int realCallingUid, Intent intent, int pid, String msg) { + return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent, + DEBUG_ACTIVITY_STARTS ? ("[Process(" + pid + ")]" + msg) : ""); } - private int logStartAllowedAndReturnCode(boolean background, int code, - String... msg) { + static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background, + int callingUid, int realCallingUid, Intent intent, String msg) { + statsLogBalAllowed(code, callingUid, realCallingUid, intent); if (DEBUG_ACTIVITY_STARTS) { StringBuilder builder = new StringBuilder(); if (background) { builder.append("Background "); } - builder.append("Activity start allowed: "); - for (int i = 0; i < msg.length; i++) { - builder.append(msg[i]); - builder.append(". "); - } + builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". "); builder.append("BAL Code: "); builder.append(code); Slog.d(TAG, builder.toString()); @@ -482,4 +485,27 @@ public class BackgroundActivityStartController { /* name= */ "system_exempt_from_activity_bg_start_restriction_enabled", /* defaultValue= */ true); } + + private static void statsLogBalAllowed( + @BalCode int code, int callingUid, int realCallingUid, Intent intent) { + if (code == BAL_ALLOW_PENDING_INTENT + && (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) { + String activityName = + intent != null ? intent.getComponent().flattenToShortString() : ""; + FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + activityName, + code, + callingUid, + realCallingUid); + } + if (code == BAL_ALLOW_PERMISSION || code == BAL_ALLOW_FOREGROUND + || code == BAL_ALLOW_SAW_PERMISSION) { + // We don't need to know which activity in this case. + FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + /*activityName*/ "", + code, + callingUid, + realCallingUid); + } + } } diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java index 9298afcdda3bc..74f0ddc19caa6 100644 --- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java @@ -104,37 +104,29 @@ class BackgroundLaunchProcessController { long lastActivityFinishTime) { // Allow if the proc is instrumenting with background activity starts privs. if (hasBackgroundActivityStartPrivileges) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process instrumenting with background " + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process instrumenting with background " + "activity starts privileges"); - } - return BAL_ALLOW_PERMISSION; } // Allow if the flag was explicitly set. if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process allowed by token"); - } - return BAL_ALLOW_PERMISSION; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process allowed by token"); } // Allow if the caller is bound by a UID that's currently foreground. if (isBoundByForegroundUid()) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process bound by foreground uid"); - } - return BAL_ALLOW_VISIBLE_WINDOW; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process bound by foreground uid"); } // Allow if the caller has an activity in any foreground task. if (hasActivityInVisibleTask && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process has activity in foreground task"); - } - return BAL_ALLOW_FOREGROUND; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process has activity in foreground task"); } // If app switching is not allowed, we ignore all the start activity grace period @@ -149,12 +141,10 @@ class BackgroundLaunchProcessController { // let app to be able to start background activity even it's in grace period. if (lastActivityLaunchTime > lastStopAppSwitchesTime || lastActivityFinishTime > lastStopAppSwitchesTime) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: within " - + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); - } - return BAL_ALLOW_GRACE_PERIOD; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_GRACE_PERIOD, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: within " + + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); } if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start within " diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 7b19e1f4db425..0a80abe4709f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.app.Activity.RESULT_CANCELED; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; import static android.app.ActivityManager.PROCESS_STATE_TOP; @@ -43,6 +44,7 @@ import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBE 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.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations; @@ -50,6 +52,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -77,6 +80,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; @@ -111,6 +115,8 @@ import android.window.TaskFragmentOrganizerToken; import androidx.test.filters.SmallTest; import com.android.compatibility.common.util.DeviceConfigStateHelper; +import com.android.internal.util.FrameworkStatsLog; +import com.android.server.am.PendingIntentRecord; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import com.android.server.wm.utils.MockTracker; @@ -120,6 +126,8 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import java.util.Arrays; import java.util.HashSet; @@ -880,6 +888,64 @@ public class ActivityStarterTests extends WindowTestsBase { false, false, false, false, false, false, false); } + /** + * This test ensures proper logging for BAL_ALLOW_PERMISSION. + */ + @Test + public void testBackgroundActivityStartsAllowed_logging() { + doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); + MockitoSession mockingSession = mockitoSession() + .mockStatic(ActivityTaskManagerService.class) + .mockStatic(FrameworkStatsLog.class) + .strictness(Strictness.LENIENT) + .startMocking(); + doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( + eq(START_ACTIVITIES_FROM_BACKGROUND), + anyInt(), anyInt())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, + false, true, false, false, false, false, false); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + "", // activity name + BackgroundActivityStartController.BAL_ALLOW_PERMISSION, + UNIMPORTANT_UID, + UNIMPORTANT_UID2)); + mockingSession.finishMocking(); + } + + /** + * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT. + */ + @Test + public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() { + doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); + MockitoSession mockingSession = mockitoSession() + .mockStatic(ActivityTaskManagerService.class) + .mockStatic(FrameworkStatsLog.class) + .mockStatic(PendingIntentRecord.class) + .strictness(Strictness.LENIENT) + .startMocking(); + doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( + eq(START_ACTIVITIES_FROM_BACKGROUND), + anyInt(), anyInt())); + doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( + () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( + anyObject(), anyInt())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, + false, true, false, false, false, false, false); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, + BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, + UNIMPORTANT_UID, + Process.SYSTEM_UID)); + mockingSession.finishMocking(); + } + private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,