diff options
3 files changed, 153 insertions, 71 deletions
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 2315795a003b..c7e44b347f6b 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -40,6 +40,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; @@ -169,22 +170,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"); } } @@ -211,8 +214,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 = " @@ -247,8 +250,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"); } } @@ -267,25 +270,24 @@ 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); } // if the realCallingUid is a persistent system process, abort if the IntentSender // wasn't allowed to start an activity if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) { - 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); @@ -293,8 +295,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); } } @@ -302,25 +305,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_BAL_PERMISSION, + return logStartAllowedAndReturnCode(BAL_ALLOW_BAL_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)) { @@ -329,8 +335,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"); } } // If we don't have callerApp at this point, no caller was provided to startActivity(). @@ -348,7 +355,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"); } @@ -361,7 +369,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"); } @@ -427,31 +436,48 @@ 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()); } return code; } + + 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_BAL_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 020e9c582ebe..cc47528f9950 100644 --- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java @@ -93,12 +93,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 " @@ -110,37 +108,29 @@ class BackgroundLaunchProcessController { } // 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_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process instrumenting with background " + "activity starts privileges"); - } - return BAL_ALLOW_BAL_PERMISSION; } // 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"); } // 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_FOREGROUND; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process bound by foreground uid"); } // 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_BAL_PERMISSION; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process allowed by token"); } return BAL_BLOCK; } 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 1d859bf0198a..0a6cb37a7fa9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -16,7 +16,9 @@ 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; import static android.app.ActivityManager.START_ABORTED; import static android.app.ActivityManager.START_CANCELED; @@ -42,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; @@ -49,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; @@ -73,6 +77,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; @@ -103,6 +108,8 @@ import android.window.TaskFragmentOrganizerToken; import androidx.test.filters.SmallTest; +import com.android.internal.util.FrameworkStatsLog; +import com.android.server.am.PendingIntentRecord; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import com.android.server.wm.utils.MockTracker; @@ -110,6 +117,8 @@ import com.android.server.wm.utils.MockTracker; import org.junit.Before; 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; @@ -729,6 +738,63 @@ public class ActivityStarterTests extends WindowTestsBase { isCallingUidDeviceOwner, false /* isPinnedSingleInstance */); } + /** + * 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); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + "", // activity name + BackgroundActivityStartController.BAL_ALLOW_BAL_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(true).when( + () -> PendingIntentRecord.isPendingIntentBalAllowedByCaller(anyObject())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, + false, true, 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, |