Log BAL and full screen intent to statsd.

Test: atest StatusBarNotificationActivityStarterTest
Test: atest ActivityStarterTests
Bug: 261910877
Change-Id: I4fdfbe80ea0c368a4809e5613e5f9c3a8369e2a3
This commit is contained in:
Yu-Ting Tseng
2023-01-19 09:34:35 -08:00
parent 2a85f93f59
commit 4fb8913bfc
5 changed files with 222 additions and 79 deletions

View File

@@ -27,6 +27,7 @@ import android.app.PendingIntent;
import android.app.TaskStackBuilder; import android.app.TaskStackBuilder;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@@ -45,6 +46,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper; import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.EventLogTags; 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.statusbar.policy.KeyguardStateController;
import com.android.systemui.wmshell.BubblesManager; import com.android.systemui.wmshell.BubblesManager;
import dagger.Lazy;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import javax.inject.Inject; import javax.inject.Inject;
import dagger.Lazy;
/** /**
* Status bar implementation of {@link NotificationActivityStarter}. * Status bar implementation of {@link NotificationActivityStarter}.
@@ -572,16 +576,29 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
}); });
// not immersive & a fullscreen alert should be shown // not immersive & a fullscreen alert should be shown
final PendingIntent fullscreenIntent = final PendingIntent fullScreenIntent =
entry.getSbn().getNotification().fullScreenIntent; entry.getSbn().getNotification().fullScreenIntent;
mLogger.logSendingFullScreenIntent(entry, fullscreenIntent); mLogger.logSendingFullScreenIntent(entry, fullScreenIntent);
try { try {
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
entry.getKey()); entry.getKey());
mCentralSurfaces.wakeUpForFullScreenIntent(); mCentralSurfaces.wakeUpForFullScreenIntent();
fullscreenIntent.send(); fullScreenIntent.send();
entry.notifyFullScreenIntentLaunched(); entry.notifyFullScreenIntentLaunched();
mMetricsLogger.count("note_fullscreen", 1); mMetricsLogger.count("note_fullscreen", 1);
String activityName;
List<ResolveInfo> 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) { } catch (PendingIntent.CanceledException e) {
// ignore // ignore
} }

View File

@@ -18,6 +18,9 @@ package com.android.systemui.statusbar.phone;
import static android.service.notification.NotificationListenerService.REASON_CLICK; 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.AdditionalAnswers.answerVoid;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; 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.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -38,6 +40,8 @@ import android.app.KeyguardManager;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.os.Handler; import android.os.Handler;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
@@ -51,6 +55,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper; import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
@@ -90,9 +95,12 @@ import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -398,4 +406,40 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// THEN display should try wake up for the full screen intent // THEN display should try wake up for the full screen intent
verify(mCentralSurfaces).wakeUpForFullScreenIntent(); 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();
}
} }

View File

@@ -45,6 +45,7 @@ import android.util.ArraySet;
import android.util.DebugUtils; import android.util.DebugUtils;
import android.util.Slog; import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord; import com.android.server.am.PendingIntentRecord;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@@ -176,22 +177,24 @@ public class BackgroundActivityStartController {
if (callingUid == Process.ROOT_UID if (callingUid == Process.ROOT_UID
|| callingAppId == Process.SYSTEM_UID || callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) { || callingAppId == Process.NFC_UID) {
return logStartAllowedAndReturnCode(/*background*/ false, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false,
BAL_ALLOW_ALLOWLISTED_UID, "Important callingUid"); callingUid, realCallingUid, intent, "Important callingUid");
} }
// Always allow home application to start activities. // Always allow home application to start activities.
if (isHomeApp(callingUid, callingPackage)) { if (isHomeApp(callingUid, callingPackage)) {
return logStartAllowedAndReturnCode(/*background*/ false, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
BAL_ALLOW_ALLOWLISTED_COMPONENT, "Home app"); /*background*/ false, callingUid, realCallingUid, intent,
"Home app");
} }
// IME should always be allowed to start activity, like IME settings. // IME should always be allowed to start activity, like IME settings.
final WindowState imeWindow = final WindowState imeWindow =
mService.mRootWindowContainer.getCurrentInputMethodWindow(); mService.mRootWindowContainer.getCurrentInputMethodWindow();
if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) { if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
return logStartAllowedAndReturnCode(/*background*/ false, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
BAL_ALLOW_ALLOWLISTED_COMPONENT, "Active ime"); /*background*/ false, callingUid, realCallingUid, intent,
"Active ime");
} }
} }
@@ -218,8 +221,8 @@ public class BackgroundActivityStartController {
&& callingUidHasAnyVisibleWindow) && callingUidHasAnyVisibleWindow)
|| isCallingUidPersistentSystemProcess; || isCallingUidPersistentSystemProcess;
if (useCallingUidState && allowCallingUidStartActivity) { if (useCallingUidState && allowCallingUidStartActivity) {
return logStartAllowedAndReturnCode(/*background*/ false, return logStartAllowedAndReturnCode(BAL_ALLOW_VISIBLE_WINDOW,
BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false, callingUid, realCallingUid, intent,
"callingUidHasAnyVisibleWindow = " "callingUidHasAnyVisibleWindow = "
+ callingUid + callingUid
+ ", isCallingUidPersistentSystemProcess = " + ", isCallingUidPersistentSystemProcess = "
@@ -254,8 +257,8 @@ public class BackgroundActivityStartController {
Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid)); Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) { if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
return logStartAllowedAndReturnCode(/*background*/ false, realCallingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX,
BAL_ALLOW_SDK_SANDBOX, /*background*/ false, callingUid, realCallingUid, intent,
"uid in SDK sandbox has visible (non-toast) window"); "uid in SDK sandbox has visible (non-toast) window");
} }
} }
@@ -276,16 +279,16 @@ public class BackgroundActivityStartController {
-1, -1,
true) true)
== PackageManager.PERMISSION_GRANTED) { == PackageManager.PERMISSION_GRANTED) {
return logStartAllowedAndReturnCode(/*background*/ false, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
BAL_ALLOW_PENDING_INTENT, /*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid has BAL permission. realCallingUid: " + realCallingUid); "realCallingUid has BAL permission. realCallingUid: " + realCallingUid);
} }
// don't abort if the realCallingUid has a visible window // don't abort if the realCallingUid has a visible window
// TODO(b/171459802): We should check appSwitchAllowed also // TODO(b/171459802): We should check appSwitchAllowed also
if (realCallingUidHasAnyVisibleWindow) { if (realCallingUidHasAnyVisibleWindow) {
return logStartAllowedAndReturnCode(/*background*/ false, return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
callingUid, BAL_ALLOW_PENDING_INTENT, /*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid has visible (non-toast) window. realCallingUid: " "realCallingUid has visible (non-toast) window. realCallingUid: "
+ realCallingUid); + realCallingUid);
} }
@@ -293,9 +296,8 @@ public class BackgroundActivityStartController {
// wasn't allowed to start an activity // wasn't allowed to start an activity
if (isRealCallingUidPersistentSystemProcess if (isRealCallingUidPersistentSystemProcess
&& backgroundStartPrivileges.allowsBackgroundActivityStarts()) { && backgroundStartPrivileges.allowsBackgroundActivityStarts()) {
return logStartAllowedAndReturnCode(/*background*/ false, return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
callingUid, /*background*/ false, callingUid, realCallingUid, intent,
BAL_ALLOW_PENDING_INTENT,
"realCallingUid is persistent system process AND intent " "realCallingUid is persistent system process AND intent "
+ "sender allowed (allowBackgroundActivityStart = true). " + "sender allowed (allowBackgroundActivityStart = true). "
+ "realCallingUid: " + realCallingUid); + "realCallingUid: " + realCallingUid);
@@ -303,8 +305,9 @@ public class BackgroundActivityStartController {
// don't abort if the realCallingUid is an associated companion app // don't abort if the realCallingUid is an associated companion app
if (mService.isAssociatedCompanionApp( if (mService.isAssociatedCompanionApp(
UserHandle.getUserId(realCallingUid), realCallingUid)) { UserHandle.getUserId(realCallingUid), realCallingUid)) {
return logStartAllowedAndReturnCode(/*background*/ false, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
BAL_ALLOW_PENDING_INTENT, "realCallingUid is a companion app. " /*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid is a companion app. "
+ "realCallingUid: " + realCallingUid); + "realCallingUid: " + realCallingUid);
} }
} }
@@ -312,25 +315,28 @@ public class BackgroundActivityStartController {
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND,
callingPid, callingUid) == PERMISSION_GRANTED) { callingPid, callingUid) == PERMISSION_GRANTED) {
return logStartAllowedAndReturnCode(/*background*/ true, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
BAL_ALLOW_PERMISSION, /*background*/ true, callingUid, realCallingUid, intent,
"START_ACTIVITIES_FROM_BACKGROUND permission granted"); "START_ACTIVITIES_FROM_BACKGROUND permission granted");
} }
// don't abort if the caller has the same uid as the recents component // don't abort if the caller has the same uid as the recents component
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) { if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
return logStartAllowedAndReturnCode(/*background*/ true, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
BAL_ALLOW_ALLOWLISTED_COMPONENT, "Recents Component"); /*background*/ true, callingUid, realCallingUid,
intent, "Recents Component");
} }
// don't abort if the callingUid is the device owner // don't abort if the callingUid is the device owner
if (mService.isDeviceOwner(callingUid)) { if (mService.isDeviceOwner(callingUid)) {
return logStartAllowedAndReturnCode(/*background*/ true, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
BAL_ALLOW_ALLOWLISTED_COMPONENT, "Device Owner"); /*background*/ true, callingUid, realCallingUid,
intent, "Device Owner");
} }
// don't abort if the callingUid has companion device // don't abort if the callingUid has companion device
final int callingUserId = UserHandle.getUserId(callingUid); final int callingUserId = UserHandle.getUserId(callingUid);
if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) { if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
return logStartAllowedAndReturnCode(/*background*/ true, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
BAL_ALLOW_ALLOWLISTED_COMPONENT, "Companion App"); /*background*/ true, callingUid, realCallingUid,
intent, "Companion App");
} }
// don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) { if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
@@ -339,8 +345,9 @@ public class BackgroundActivityStartController {
"Background activity start for " "Background activity start for "
+ callingPackage + callingPackage
+ " allowed because SYSTEM_ALERT_WINDOW permission is granted."); + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
return logStartAllowedAndReturnCode(/*background*/ true, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION,
BAL_ALLOW_SAW_PERMISSION, "SYSTEM_ALERT_WINDOW permission is granted"); /*background*/ true, callingUid, realCallingUid,
intent, "SYSTEM_ALERT_WINDOW permission is granted");
} }
// don't abort if the callingUid and callingPackage have the // don't abort if the callingUid and callingPackage have the
// OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop // OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop
@@ -349,8 +356,8 @@ public class BackgroundActivityStartController {
callingUid, callingUid,
callingPackage) callingPackage)
== AppOpsManager.MODE_ALLOWED) { == AppOpsManager.MODE_ALLOWED) {
return logStartAllowedAndReturnCode(/*background*/ true, callingUid, return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
BAL_ALLOW_PERMISSION, /*background*/ true, callingUid, realCallingUid, intent,
"OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted"); "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
} }
} }
@@ -369,7 +376,8 @@ public class BackgroundActivityStartController {
@BalCode int balAllowedForCaller = callerApp @BalCode int balAllowedForCaller = callerApp
.areBackgroundActivityStartsAllowed(appSwitchState); .areBackgroundActivityStartsAllowed(appSwitchState);
if (balAllowedForCaller != BAL_BLOCK) { if (balAllowedForCaller != BAL_BLOCK) {
return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForCaller, return logStartAllowedAndReturnCode(balAllowedForCaller,
/*background*/ true, callingUid, realCallingUid, intent,
"callerApp process (pid = " + callerApp.getPid() "callerApp process (pid = " + callerApp.getPid()
+ ", uid = " + callerAppUid + ") is allowed"); + ", uid = " + callerAppUid + ") is allowed");
} }
@@ -382,7 +390,8 @@ public class BackgroundActivityStartController {
int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState); int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState);
if (proc != callerApp if (proc != callerApp
&& balAllowedForUid != BAL_BLOCK) { && balAllowedForUid != BAL_BLOCK) {
return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForUid, return logStartAllowedAndReturnCode(balAllowedForUid,
/*background*/ true, callingUid, realCallingUid, intent,
"process" + proc.getPid() "process" + proc.getPid()
+ " from uid " + callerAppUid + " is allowed"); + " from uid " + callerAppUid + " is allowed");
} }
@@ -448,27 +457,21 @@ public class BackgroundActivityStartController {
return BAL_BLOCK; return BAL_BLOCK;
} }
private int logStartAllowedAndReturnCode(boolean background, int callingUid, int code, static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
String msg) { int callingUid, int realCallingUid, Intent intent, int pid, String msg) {
if (DEBUG_ACTIVITY_STARTS) { return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent,
return logStartAllowedAndReturnCode(background, code, DEBUG_ACTIVITY_STARTS ? ("[Process(" + pid + ")]" + msg) : "");
msg, "callingUid: " + callingUid);
}
return code;
} }
private int logStartAllowedAndReturnCode(boolean background, int code, static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
String... msg) { int callingUid, int realCallingUid, Intent intent, String msg) {
statsLogBalAllowed(code, callingUid, realCallingUid, intent);
if (DEBUG_ACTIVITY_STARTS) { if (DEBUG_ACTIVITY_STARTS) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
if (background) { if (background) {
builder.append("Background "); builder.append("Background ");
} }
builder.append("Activity start allowed: "); builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". ");
for (int i = 0; i < msg.length; i++) {
builder.append(msg[i]);
builder.append(". ");
}
builder.append("BAL Code: "); builder.append("BAL Code: ");
builder.append(code); builder.append(code);
Slog.d(TAG, builder.toString()); Slog.d(TAG, builder.toString());
@@ -482,4 +485,27 @@ public class BackgroundActivityStartController {
/* name= */ "system_exempt_from_activity_bg_start_restriction_enabled", /* name= */ "system_exempt_from_activity_bg_start_restriction_enabled",
/* defaultValue= */ true); /* 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);
}
}
} }

View File

@@ -104,37 +104,29 @@ class BackgroundLaunchProcessController {
long lastActivityFinishTime) { long lastActivityFinishTime) {
// Allow if the proc is instrumenting with background activity starts privs. // Allow if the proc is instrumenting with background activity starts privs.
if (hasBackgroundActivityStartPrivileges) { if (hasBackgroundActivityStartPrivileges) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process instrumenting with background " pid, "Activity start allowed: process instrumenting with background "
+ "activity starts privileges"); + "activity starts privileges");
} }
return BAL_ALLOW_PERMISSION;
}
// Allow if the flag was explicitly set. // Allow if the flag was explicitly set.
if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) { if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process allowed by token"); pid, "Activity start allowed: process allowed by token");
}
return BAL_ALLOW_PERMISSION;
} }
// Allow if the caller is bound by a UID that's currently foreground. // Allow if the caller is bound by a UID that's currently foreground.
if (isBoundByForegroundUid()) { if (isBoundByForegroundUid()) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process bound by foreground uid"); pid, "Activity start allowed: process bound by foreground uid");
}
return BAL_ALLOW_VISIBLE_WINDOW;
} }
// Allow if the caller has an activity in any foreground task. // Allow if the caller has an activity in any foreground task.
if (hasActivityInVisibleTask if (hasActivityInVisibleTask
&& (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) { && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: process has activity in foreground task"); pid, "Activity start allowed: process has activity in foreground task");
}
return BAL_ALLOW_FOREGROUND;
} }
// If app switching is not allowed, we ignore all the start activity grace period // If app switching is not allowed, we ignore all the start activity grace period
@@ -149,13 +141,11 @@ class BackgroundLaunchProcessController {
// let app to be able to start background activity even it's in grace period. // let app to be able to start background activity even it's in grace period.
if (lastActivityLaunchTime > lastStopAppSwitchesTime if (lastActivityLaunchTime > lastStopAppSwitchesTime
|| lastActivityFinishTime > lastStopAppSwitchesTime) { || lastActivityFinishTime > lastStopAppSwitchesTime) {
if (DEBUG_ACTIVITY_STARTS) { return BackgroundActivityStartController.logStartAllowedAndReturnCode(
Slog.d(TAG, "[Process(" + pid BAL_ALLOW_GRACE_PERIOD, /*background*/ true, uid, uid, /*intent*/ null,
+ ")] Activity start allowed: within " pid, "Activity start allowed: within "
+ ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
} }
return BAL_ALLOW_GRACE_PERIOD;
}
if (DEBUG_ACTIVITY_STARTS) { if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "[Process(" + pid + ")] Activity start within " Slog.d(TAG, "[Process(" + pid + ")] Activity start within "
+ ACTIVITY_BG_START_GRACE_PERIOD_MS + ACTIVITY_BG_START_GRACE_PERIOD_MS

View File

@@ -16,6 +16,7 @@
package com.android.server.wm; 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.Activity.RESULT_CANCELED;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_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_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID; import static android.os.Process.SYSTEM_UID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations; 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.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 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.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.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 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.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.ArgumentMatchers.notNull;
@@ -111,6 +115,8 @@ import android.window.TaskFragmentOrganizerToken;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.DeviceConfigStateHelper; 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.pm.pkg.AndroidPackage;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker; import com.android.server.wm.utils.MockTracker;
@@ -120,6 +126,8 @@ import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@@ -880,6 +888,64 @@ public class ActivityStarterTests extends WindowTestsBase {
false, false, false, false, false, false, false); 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, private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,