Merge "Allow custom toasts only if app has resumed activity" into rvc-dev am: 9bcbce4a20
Change-Id: Ib7fe904bbdf7599259328417bfe20f591781d4f7
This commit is contained in:
@@ -261,6 +261,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;
|
||||
@@ -391,6 +392,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;
|
||||
@@ -1858,10 +1860,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(),
|
||||
@@ -1871,6 +1873,7 @@ public class NotificationManagerService extends SystemService {
|
||||
mAccessibilityManager =
|
||||
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
|
||||
mAm = am;
|
||||
mAtm = atm;
|
||||
mUgm = ugm;
|
||||
mUgmInternal = ugmInternal;
|
||||
mPackageManager = packageManager;
|
||||
@@ -2057,6 +2060,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(),
|
||||
@@ -2793,7 +2797,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 {
|
||||
@@ -2871,6 +2877,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);
|
||||
|
||||
@@ -168,6 +168,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.
|
||||
*
|
||||
|
||||
@@ -6171,6 +6171,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) {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
@@ -165,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 +253,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Mock
|
||||
IActivityManager mAm;
|
||||
@Mock
|
||||
ActivityTaskManagerInternal mAtm;
|
||||
@Mock
|
||||
IUriGrantsManager mUgm;
|
||||
@Mock
|
||||
UriGrantsManagerInternal mUgmInternal;
|
||||
@@ -454,7 +456,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);
|
||||
@@ -4704,8 +4706,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(),
|
||||
@@ -4723,8 +4724,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(),
|
||||
@@ -4742,8 +4742,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(),
|
||||
@@ -4761,8 +4760,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(),
|
||||
@@ -4820,8 +4818,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(),
|
||||
@@ -4843,8 +4840,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(),
|
||||
@@ -4852,6 +4848,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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user