summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java38
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java10
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java32
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java2
6 files changed, 80 insertions, 21 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 69a5b35a5b12..0ee7344e0e4d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -272,6 +272,7 @@ import com.android.server.pm.PackageManagerService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import libcore.io.IoUtils;
@@ -403,6 +404,7 @@ public class NotificationManagerService extends SystemService {
private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L;
private IActivityManager mAm;
+ private ActivityTaskManagerInternal mAtm;
private ActivityManager mActivityManager;
private IPackageManager mPackageManager;
private PackageManager mPackageManagerClient;
@@ -1905,10 +1907,10 @@ public class NotificationManagerService extends SystemService {
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
NotificationUsageStats usageStats, AtomicFile policyFile,
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
- UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
- IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
- UserManager userManager, NotificationHistoryManager historyManager,
- StatsManager statsManager) {
+ ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats,
+ DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
+ UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
+ NotificationHistoryManager historyManager, StatsManager statsManager) {
mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -1918,6 +1920,7 @@ public class NotificationManagerService extends SystemService {
mAccessibilityManager =
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
mAm = am;
+ mAtm = atm;
mUgm = ugm;
mUgmInternal = ugmInternal;
mPackageManager = packageManager;
@@ -2104,6 +2107,7 @@ public class NotificationManagerService extends SystemService {
systemDir, "notification_policy.xml"), "notification-policy"),
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
getGroupHelper(), ActivityManager.getService(),
+ LocalServices.getService(ActivityTaskManagerInternal.class),
LocalServices.getService(UsageStatsManagerInternal.class),
LocalServices.getService(DevicePolicyManagerInternal.class),
UriGrantsManager.getService(),
@@ -2835,7 +2839,9 @@ public class NotificationManagerService extends SystemService {
return;
}
- if (callback != null && !appIsForeground && !isSystemToast && isCustom) {
+ boolean isAppRenderedToast = (callback != null);
+ if (isAppRenderedToast && isCustom && !isSystemToast
+ && !isPackageInForegroundForToast(pkg, callingUid)) {
boolean block;
long id = Binder.clearCallingIdentity();
try {
@@ -2913,6 +2919,28 @@ public class NotificationManagerService extends SystemService {
}
}
+ /**
+ * Implementation note: Our definition of foreground for toasts is an implementation matter
+ * and should strike a balance between functionality and anti-abuse effectiveness. We
+ * currently worry about the following cases:
+ * <ol>
+ * <li>App with fullscreen activity: Allow toasts
+ * <li>App behind translucent activity from other app: Block toasts
+ * <li>App in multi-window: Allow toasts
+ * <li>App with expanded bubble: Allow toasts
+ * <li>App posting toasts on onCreate(), onStart(), onResume(): Allow toasts
+ * <li>App posting toasts on onPause(), onStop(), onDestroy(): Block toasts
+ * </ol>
+ * Checking if the UID has any resumed activities satisfy use-cases above.
+ *
+ * <p>Checking if {@code mActivityManager.getUidImportance(callingUid) ==
+ * IMPORTANCE_FOREGROUND} does not work because it considers the app in foreground if it has
+ * any visible activities, failing case 2 in list above.
+ */
+ private boolean isPackageInForegroundForToast(String pkg, int callingUid) {
+ return mAtm.hasResumedActivity(callingUid);
+ }
+
@Override
public void cancelToast(String pkg, IBinder token) {
Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index ca856ca7c1e6..edc87e5a4d88 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -169,6 +169,11 @@ public abstract class ActivityTaskManagerInternal {
public abstract List<IBinder> getTopVisibleActivities();
/**
+ * Returns whether {@code uid} has any resumed activity.
+ */
+ public abstract boolean hasResumedActivity(int uid);
+
+ /**
* Notify listeners that contents are drawn for the first time on a single task display.
*
* @param displayId An ID of the display on which contents are drawn.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7bacc427feb8..890b9454e6b6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6172,6 +6172,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
+ public boolean hasResumedActivity(int uid) {
+ synchronized (mGlobalLock) {
+ final ArraySet<WindowProcessController> processes = mProcessMap.getProcesses(uid);
+ for (int i = 0, n = processes.size(); i < n; i++) {
+ final WindowProcessController process = processes.valueAt(i);
+ if (process.hasResumedActivity()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
public int startActivitiesAsPackage(String packageName, @Nullable String featureId,
int userId, Intent[] intents, Bundle bOptions) {
Objects.requireNonNull(intents, "intents");
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 32eb932ea0ed..e5400d849e71 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -751,6 +751,16 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return false;
}
+ boolean hasResumedActivity() {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord activity = mActivities.get(i);
+ if (activity.isState(RESUMED)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void updateIntentForHeavyWeightActivity(Intent intent) {
if (mActivities.isEmpty()) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 64d481a2e6a0..6315ba6b2ee2 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -17,7 +17,6 @@
package com.android.server.notification;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
import static android.app.Notification.CATEGORY_CALL;
import static android.app.Notification.FLAG_AUTO_CANCEL;
@@ -41,8 +40,6 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -167,6 +164,7 @@ import com.android.server.notification.NotificationManagerService.NotificationAs
import com.android.server.notification.NotificationManagerService.NotificationListeners;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
@@ -253,6 +251,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Mock
IActivityManager mAm;
@Mock
+ ActivityTaskManagerInternal mAtm;
+ @Mock
IUriGrantsManager mUgm;
@Mock
UriGrantsManagerInternal mUgmInternal;
@@ -442,7 +442,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mRankingHandler, mPackageManager, mPackageManagerClient, mockLightsManager,
mListeners, mAssistants, mConditionProviders,
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
- mGroupHelper, mAm, mAppUsageStats,
+ mGroupHelper, mAm, mAtm, mAppUsageStats,
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
mAppOpsManager, mUm, mHistoryManager, mStatsManager);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
@@ -4632,8 +4632,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
- // this app is in the foreground
- when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_FOREGROUND);
+ setAppInForegroundForToasts(mUid, true);
// enqueue toast -> toast should still enqueue
((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
@@ -4651,8 +4650,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
.thenReturn(false);
- // this app is NOT in the foreground
- when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_NONE);
+ setAppInForegroundForToasts(mUid, false);
// enqueue toast -> no toasts enqueued
((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
@@ -4670,8 +4668,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
.thenReturn(false);
- // this app is in the foreground
- when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_FOREGROUND);
+ setAppInForegroundForToasts(mUid, true);
// enqueue toast -> toast should still enqueue
((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
@@ -4689,8 +4686,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
.thenReturn(false);
- // this app is NOT in the foreground
- when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_NONE);
+ setAppInForegroundForToasts(mUid, false);
// enqueue toast -> toast should still enqueue
((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
@@ -4748,8 +4744,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
- // this app is NOT in the foreground
- when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_GONE);
+ setAppInForegroundForToasts(mUid, false);
// enqueue toast -> no toasts enqueued
((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
@@ -4771,8 +4766,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
- // this app is NOT in the foreground
- when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_GONE);
+ setAppInForegroundForToasts(mUid, false);
// enqueue toast -> system toast can still be enqueued
((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
@@ -4780,6 +4774,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(1, mService.mToastQueue.size());
}
+ private void setAppInForegroundForToasts(int uid, boolean inForeground) {
+ int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE;
+ when(mActivityManager.getUidImportance(mUid)).thenReturn(importance);
+ when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground);
+ }
+
@Test
public void testOnPanelRevealedAndHidden() {
int items = 5;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index e4d50c0e1786..19ff683a46a1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -65,6 +65,7 @@ import com.android.server.lights.LightsManager;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
import com.android.server.notification.NotificationManagerService.NotificationListeners;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
@@ -147,6 +148,7 @@ public class RoleObserverTest extends UiServiceTestCase {
mock(SnoozeHelper.class), mock(NotificationUsageStats.class),
mock(AtomicFile.class), mock(ActivityManager.class),
mock(GroupHelper.class), mock(IActivityManager.class),
+ mock(ActivityTaskManagerInternal.class),
mock(UsageStatsManagerInternal.class),
mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
mock(UriGrantsManagerInternal.class),