Use app uids in DndRule proto pulled atom
Rules created by the system ("android") have uid=1000 and apps have
their own unique uids.
Cached uids are removed when the automatic rule is removed.
- ConditionProviders removes automatic rule on package removal
- NotificationAccessDetails + NotificationAccessPreferenceController +
ZenAccessController remove automatic rules on permission changes
Test: atest ZenModeHelperTest
Fixes: 158647401
Change-Id: I100490c4e4cd823a7f12faa518fbc4c2a172a9f7
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 5cd22e0..de77372 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -88,7 +88,6 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
@@ -106,6 +105,9 @@
// The amount of time rules instances can exist without their owning app being installed.
private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+ // pkg|userId => uid
+ protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
+
private final Context mContext;
private final H mHandler;
private final SettingsObserver mSettingsObserver;
@@ -145,7 +147,7 @@
mHandler = new H(looper);
addCallback(mMetrics);
mAppOps = context.getSystemService(AppOpsManager.class);
- mNotificationManager = context.getSystemService(NotificationManager.class);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
mDefaultConfig = readDefaultConfig(mContext.getResources());
updateDefaultAutomaticRuleNames();
@@ -384,17 +386,25 @@
synchronized (mConfig) {
if (mConfig == null) return false;
newConfig = mConfig.copy();
- ZenRule rule = newConfig.automaticRules.get(id);
- if (rule == null) return false;
- if (canManageAutomaticZenRule(rule)) {
+ ZenRule ruleToRemove = newConfig.automaticRules.get(id);
+ if (ruleToRemove == null) return false;
+ if (canManageAutomaticZenRule(ruleToRemove)) {
newConfig.automaticRules.remove(id);
+ if (ruleToRemove.pkg != null && !"android".equals(ruleToRemove.pkg)) {
+ for (ZenRule currRule : newConfig.automaticRules.values()) {
+ if (currRule.pkg != null && currRule.pkg.equals(ruleToRemove.pkg)) {
+ break; // no need to remove from cache
+ }
+ }
+ mRulesUidCache.remove(getPackageUserKey(ruleToRemove.pkg, newConfig.user));
+ }
if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
} else {
throw new SecurityException(
"Cannot delete rules not owned by your condition provider");
}
dispatchOnAutomaticRuleStatusChanged(
- mConfig.user, rule.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
+ mConfig.user, ruleToRemove.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
return setConfigLocked(newConfig, reason, null, true);
}
}
@@ -1192,7 +1202,6 @@
public void pullRules(List<StatsEvent> events) {
synchronized (mConfig) {
final int numConfigs = mConfigs.size();
- int id = 0;
for (int i = 0; i < numConfigs; i++) {
final int user = mConfigs.keyAt(i);
final ZenModeConfig config = mConfigs.valueAt(i);
@@ -1208,16 +1217,16 @@
.writeByteArray(config.toZenPolicy().toProto());
events.add(data.build());
if (config.manualRule != null && config.manualRule.enabler != null) {
- ruleToProto(user, config.manualRule, events);
+ ruleToProtoLocked(user, config.manualRule, events);
}
for (ZenRule rule : config.automaticRules.values()) {
- ruleToProto(user, rule, events);
+ ruleToProtoLocked(user, rule, events);
}
}
}
}
- private void ruleToProto(int user, ZenRule rule, List<StatsEvent> events) {
+ private void ruleToProtoLocked(int user, ZenRule rule, List<StatsEvent> events) {
// Make the ID safe.
String id = rule.id == null ? "" : rule.id;
if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) {
@@ -1231,9 +1240,6 @@
id = ZenModeConfig.MANUAL_RULE_ID;
}
- // TODO: fetch the uid from the package manager
- int uid = "android".equals(pkg) ? Process.SYSTEM_UID : 0;
-
SysUiStatsEvent.Builder data;
data = mStatsEventBuilderFactory.newBuilder()
.setAtomId(DND_MODE_RULE)
@@ -1242,7 +1248,7 @@
.writeBoolean(false) // channels_bypassing unused for rules
.writeInt(rule.zenMode)
.writeString(id)
- .writeInt(uid)
+ .writeInt(getPackageUid(pkg, user))
.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
byte[] policyProto = new byte[]{};
if (rule.zenPolicy != null) {
@@ -1252,6 +1258,24 @@
events.add(data.build());
}
+ private int getPackageUid(String pkg, int user) {
+ if ("android".equals(pkg)) {
+ return Process.SYSTEM_UID;
+ }
+ final String key = getPackageUserKey(pkg, user);
+ if (mRulesUidCache.get(key) == null) {
+ try {
+ mRulesUidCache.put(key, mPm.getPackageUidAsUser(pkg, user));
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+ return mRulesUidCache.getOrDefault(key, -1);
+ }
+
+ private static String getPackageUserKey(String pkg, int user) {
+ return pkg + "|" + user;
+ }
+
@VisibleForTesting
protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
@Override
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index cfdd246..57d5323 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -58,6 +58,7 @@
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -101,7 +102,6 @@
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.ManagedServices.UserProfiles;
@@ -110,9 +110,7 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -134,9 +132,13 @@
private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
private static final int ZEN_MODE_FOR_TESTING = 99;
+ private static final String CUSTOM_PKG_NAME = "not.android";
+ private static final int CUSTOM_PKG_UID = 1;
+ private static final String CUSTOM_RULE_ID = "custom_rule";
ConditionProviders mConditionProviders;
@Mock NotificationManager mNotificationManager;
+ @Mock PackageManager mPackageManager;
private Resources mResources;
private TestableLooper mTestableLooper;
private ZenModeHelper mZenModeHelperSpy;
@@ -146,7 +148,7 @@
private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
@Before
- public void setUp() {
+ public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
@@ -169,6 +171,10 @@
mConditionProviders.addSystemProvider(new CountdownConditionProvider());
mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders, mStatsEventBuilderFactory));
+
+ when(mPackageManager.getPackageUidAsUser(eq(CUSTOM_PKG_NAME), anyInt()))
+ .thenReturn(CUSTOM_PKG_UID);
+ mZenModeHelperSpy.mPm = mPackageManager;
}
private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException {
@@ -238,19 +244,24 @@
private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules(int zenMode) {
ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
+ ZenModeConfig.ZenRule rule = createCustomAutomaticRule(zenMode, CUSTOM_RULE_ID);
+ automaticRules.put(rule.id, rule);
+ return automaticRules;
+ }
+
+ private ZenModeConfig.ZenRule createCustomAutomaticRule(int zenMode, String id) {
ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
final ScheduleInfo customRuleInfo = new ScheduleInfo();
customRule.enabled = true;
customRule.creationTime = 0;
- customRule.id = "customRule";
- customRule.name = "Custom Rule";
+ customRule.id = id;
+ customRule.name = "Custom Rule with id=" + id;
customRule.zenMode = zenMode;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.configurationActivity =
- new ComponentName("not.android", "ScheduleConditionProvider");
+ new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider");
customRule.pkg = customRule.configurationActivity.getPackageName();
- automaticRules.put("customRule", customRule);
- return automaticRules;
+ return customRule;
}
@Test
@@ -893,7 +904,7 @@
if (builder.getAtomId() == DND_MODE_RULE) {
if (ZEN_MODE_FOR_TESTING == builder.getInt(ZEN_MODE_FIELD_NUMBER)) {
foundCustomEvent = true;
- assertEquals(0, builder.getInt(UID_FIELD_NUMBER));
+ assertEquals(CUSTOM_PKG_UID, builder.getInt(UID_FIELD_NUMBER));
assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
}
} else {
@@ -904,6 +915,46 @@
}
@Test
+ public void ruleUidsCached() throws Exception {
+ setupZenConfig();
+ // one enabled automatic rule
+ mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+ List<StatsEvent> events = new LinkedList<>();
+ // first time retrieving uid:
+ mZenModeHelperSpy.pullRules(events);
+ verify(mPackageManager, atLeastOnce()).getPackageUidAsUser(anyString(), anyInt());
+
+ // second time retrieving uid:
+ reset(mPackageManager);
+ mZenModeHelperSpy.pullRules(events);
+ verify(mPackageManager, never()).getPackageUidAsUser(anyString(), anyInt());
+
+ // new rule from same package + user added
+ reset(mPackageManager);
+ ZenModeConfig.ZenRule rule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ CUSTOM_RULE_ID + "2");
+ mZenModeHelperSpy.mConfig.automaticRules.put(rule.id, rule);
+ mZenModeHelperSpy.pullRules(events);
+ verify(mPackageManager, never()).getPackageUidAsUser(anyString(), anyInt());
+ }
+
+ @Test
+ public void ruleUidAutomaticZenRuleRemovedUpdatesCache() throws Exception {
+ when(mContext.checkCallingPermission(anyString()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ setupZenConfig();
+ // one enabled automatic rule
+ mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+ List<StatsEvent> events = new LinkedList<>();
+
+ mZenModeHelperSpy.pullRules(events);
+ mZenModeHelperSpy.removeAutomaticZenRule(CUSTOM_RULE_ID, "test");
+ assertTrue(-1
+ == mZenModeHelperSpy.mRulesUidCache.getOrDefault(CUSTOM_PKG_NAME + "|" + 0, -1));
+ }
+
+ @Test
public void testProtoRedactsIds() throws Exception {
setupZenConfig();
// one enabled automatic rule