Merge "Allow custom toasts only if app has resumed activity" into rvc-dev am: 9bcbce4a20

Change-Id: Ib7fe904bbdf7599259328417bfe20f591781d4f7
This commit is contained in:
Bernardo Rufino
2020-03-20 09:40:48 +00:00
committed by Automerger Merge Worker
6 changed files with 80 additions and 19 deletions

View File

@@ -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);

View File

@@ -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.
*

View File

@@ -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) {

View File

@@ -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()) {

View File

@@ -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;

View File

@@ -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),