Merge "Fix backup and restore of package blocks" into oc-dev

This commit is contained in:
TreeHugger Robot
2017-05-25 18:48:56 +00:00
committed by Android (Google) Code Review
3 changed files with 91 additions and 98 deletions

View File

@@ -90,7 +90,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.media.AudioManager;
@@ -114,7 +113,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.os.VibrationEffect;
import android.provider.Settings;
@@ -473,19 +471,6 @@ public class NotificationManagerService extends SystemService {
out.endDocument();
}
/** Use this when you actually want to post a notification or toast.
*
* Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
*/
private boolean noteNotificationOp(String pkg, int uid) {
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
!= AppOpsManager.MODE_ALLOWED) {
Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
return false;
}
return true;
}
/** Use this to check if a package can post a notification or toast. */
private boolean checkNotificationOp(String pkg, int uid) {
return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
@@ -1154,7 +1139,7 @@ public class NotificationManagerService extends SystemService {
final File systemDir = new File(Environment.getDataDirectory(), "system");
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
syncBlockDb();
loadPolicyFile();
// This is a ManagedServices object that keeps track of the listeners.
mListeners = notificationListeners;
@@ -1267,46 +1252,6 @@ public class NotificationManagerService extends SystemService {
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
}
/**
* Make sure the XML config and the the AppOps system agree about blocks.
*/
private void syncBlockDb() {
loadPolicyFile();
// sync bans from ranker into app opps
Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
for(Entry<Integer, String> ban : packageBans.entrySet()) {
final int uid = ban.getKey();
final String packageName = ban.getValue();
setNotificationsEnabledForPackageImpl(packageName, uid, false);
}
// sync bans from app opps into ranker
packageBans.clear();
for (UserInfo user : UserManager.get(getContext()).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
final PackageManager packageManager = getContext().getPackageManager();
List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
final int packageCount = packages.size();
for (int p = 0; p < packageCount; p++) {
final String packageName = packages.get(p).packageName;
try {
final int uid = packageManager.getPackageUidAsUser(packageName, userId);
if (!checkNotificationOp(packageName, uid)) {
packageBans.put(uid, packageName);
}
} catch (NameNotFoundException e) {
// forget you
}
}
}
for (Entry<Integer, String> ban : packageBans.entrySet()) {
mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
}
savePolicyFile();
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
@@ -1328,19 +1273,6 @@ public class NotificationManagerService extends SystemService {
}
}
void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
}
}
private void updateListenerHintsLocked() {
final int hints = calculateHints();
if (hints == mListenerHints) return;
@@ -1522,7 +1454,8 @@ public class NotificationManagerService extends SystemService {
isPackageSuspendedForUser(pkg, Binder.getCallingUid());
if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
(!noteNotificationOp(pkg, Binder.getCallingUid()) || isPackageSuspended)) {
(!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
|| isPackageSuspended)) {
Slog.e(TAG, "Suppressing toast from package " + pkg
+ (isPackageSuspended
? " due to package suspended by administrator."
@@ -1643,8 +1576,12 @@ public class NotificationManagerService extends SystemService {
public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
checkCallerIsSystem();
setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
mRankingHelper.setEnabled(pkg, uid, enabled);
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
}
savePolicyFile();
}
@@ -1662,8 +1599,8 @@ public class NotificationManagerService extends SystemService {
@Override
public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
checkCallerIsSystemOrSameApp(pkg);
return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
== AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
}
@Override
@@ -3400,8 +3337,7 @@ public class NotificationManagerService extends SystemService {
}
final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
|| r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
|| !noteNotificationOp(pkg, callingUid);
|| r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
if (isBlocked) {
Slog.e(TAG, "Suppressing notification from package by user request.");
usageStats.registerBlocked(r);

View File

@@ -21,8 +21,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.Preconditions;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -35,8 +33,6 @@ import android.content.pm.ParceledListSlice;
import android.metrics.LogMaker;
import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
@@ -189,6 +185,10 @@ public class RankingHelper implements RankingConfig {
safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY),
safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
safeBool(parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE));
r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
r.priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
r.visibility = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
r.showBadge = safeBool(parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
final int innerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT

View File

@@ -27,6 +27,7 @@ import static junit.framework.Assert.fail;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,15 +51,11 @@ import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContext;
import android.testing.TestableSettingsProvider;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
import java.io.BufferedInputStream;
@@ -87,10 +84,10 @@ import static org.mockito.Mockito.when;
public class RankingHelperTest extends NotificationTestCase {
private static final String PKG = "com.android.server.notification";
private static final int UID = 0;
private static final UserHandle USER = UserHandle.getUserHandleForUid(UID);
private static final UserHandle USER = UserHandle.of(0);
private static final String UPDATED_PKG = "updatedPkg";
private static final int UID2 = 1111111;
private static final UserHandle USER2 = UserHandle.getUserHandleForUid(UID2);
private static final int UID2 = 1111;
private static final UserHandle USER2 = UserHandle.of(10);
private static final String TEST_CHANNEL_ID = "test_channel_id";
@Mock NotificationUsageStats mUsageStats;
@@ -199,24 +196,21 @@ public class RankingHelperTest extends NotificationTestCase {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
serializer.startTag(null, "ranking");
mHelper.writeXml(serializer, forBackup);
serializer.endTag(null, "ranking");
serializer.endDocument();
serializer.flush();
for (String channelId : channelIds) {
mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
}
return baos;
}
private void loadStreamXml(ByteArrayOutputStream stream) throws Exception {
private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore) throws Exception {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(stream.toByteArray())),
null);
parser.nextTag();
mHelper.readXml(parser, false);
mHelper.readXml(parser, forRestore);
}
private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
@@ -323,7 +317,7 @@ public class RankingHelperTest extends NotificationTestCase {
channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});
loadStreamXml(baos);
loadStreamXml(baos, false);
assertTrue(mHelper.canShowBadge(PKG, UID));
assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
@@ -353,6 +347,70 @@ public class RankingHelperTest extends NotificationTestCase {
assertTrue(foundChannel2Group);
}
@Test
public void testChannelXmlForBackup() throws Exception {
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
NotificationChannel channel2 =
new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
channel2.setDescription("descriptions for all");
channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel2.enableLights(true);
channel2.setBypassDnd(true);
channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel2.enableVibration(false);
channel2.setGroup(ncg.getId());
channel2.setLightColor(Color.BLUE);
mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
mHelper.createNotificationChannel(PKG, UID, channel1, true);
mHelper.createNotificationChannel(PKG, UID, channel2, false);
mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true);
mHelper.setShowBadge(PKG, UID, true);
mHelper.setImportance(UPDATED_PKG, UID2, IMPORTANCE_NONE);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(),
channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG, UPDATED_PKG}, new int[]{UID, UID2});
mHelper.setShowBadge(UPDATED_PKG, UID2, true);
loadStreamXml(baos, true);
assertEquals(IMPORTANCE_NONE, mHelper.getImportance(UPDATED_PKG, UID2));
assertTrue(mHelper.canShowBadge(PKG, UID));
assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
compareChannels(channel2,
mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
List<NotificationChannelGroup> actualGroups =
mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
boolean foundNcg = false;
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
foundNcg = true;
compareGroups(ncg, actual);
} else if (ncg2.getId().equals(actual.getId())) {
compareGroups(ncg2, actual);
}
}
assertTrue(foundNcg);
boolean foundChannel2Group = false;
for (NotificationChannelGroup actual : actualGroups) {
if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
foundChannel2Group = true;
break;
}
}
assertTrue(foundChannel2Group);
}
@Test
public void testChannelXml_backup() throws Exception {
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
@@ -397,7 +455,7 @@ public class RankingHelperTest extends NotificationTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
NotificationChannel.DEFAULT_CHANNEL_ID);
loadStreamXml(baos);
loadStreamXml(baos, false);
final NotificationChannel updated = mHelper.getNotificationChannel(PKG, UID,
NotificationChannel.DEFAULT_CHANNEL_ID, false);
@@ -417,7 +475,7 @@ public class RankingHelperTest extends NotificationTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
NotificationChannel.DEFAULT_CHANNEL_ID);
loadStreamXml(baos);
loadStreamXml(baos, false);
assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
@@ -465,7 +523,7 @@ public class RankingHelperTest extends NotificationTestCase {
final ApplicationInfo upgraded = new ApplicationInfo();
upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
loadStreamXml(baos);
loadStreamXml(baos, false);
// Default Channel should be gone.
assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
@@ -483,7 +541,7 @@ public class RankingHelperTest extends NotificationTestCase {
final ApplicationInfo upgraded = new ApplicationInfo();
upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
loadStreamXml(baos);
loadStreamXml(baos, false);
// Default Channel should be gone.
assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
@@ -497,7 +555,7 @@ public class RankingHelperTest extends NotificationTestCase {
mHelper.createNotificationChannel(PKG, UID,
new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
loadStreamXml(baos);
loadStreamXml(baos, false);
// Should still have the newly created channel that wasn't in the xml.
assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null);
@@ -1271,5 +1329,4 @@ public class RankingHelperTest extends NotificationTestCase {
assertFalse(mHelper.badgingEnabled(USER));
assertTrue(mHelper.badgingEnabled(USER2));
}
}