Loading services/core/java/com/android/server/notification/ZenModeHelper.java +38 −14 Original line number Diff line number Diff line Loading @@ -88,7 +88,6 @@ import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; Loading @@ -106,6 +105,9 @@ public class ZenModeHelper { // 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; Loading Loading @@ -384,17 +386,25 @@ public class ZenModeHelper { 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); } } Loading Loading @@ -1192,7 +1202,6 @@ public class ZenModeHelper { 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); Loading @@ -1208,16 +1217,16 @@ public class ZenModeHelper { .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)) { Loading @@ -1231,9 +1240,6 @@ public class ZenModeHelper { 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) Loading @@ -1242,7 +1248,7 @@ public class ZenModeHelper { .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) { Loading @@ -1252,6 +1258,24 @@ public class ZenModeHelper { 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 Loading services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +61 −10 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import static org.mockito.Mockito.atLeastOnce; 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; Loading Loading @@ -101,7 +102,6 @@ import android.util.Xml; 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; Loading @@ -110,9 +110,7 @@ import org.junit.Test; 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; Loading @@ -134,9 +132,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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; Loading @@ -146,7 +148,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory; @Before public void setUp() { public void setUp() throws PackageManager.NameNotFoundException { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); Loading @@ -169,6 +171,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 { Loading Loading @@ -238,19 +244,24 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 Loading Loading @@ -893,7 +904,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 { Loading @@ -903,6 +914,46 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertTrue("couldn't find custom rule", foundCustomEvent); } @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(); Loading Loading
services/core/java/com/android/server/notification/ZenModeHelper.java +38 −14 Original line number Diff line number Diff line Loading @@ -88,7 +88,6 @@ import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; Loading @@ -106,6 +105,9 @@ public class ZenModeHelper { // 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; Loading Loading @@ -384,17 +386,25 @@ public class ZenModeHelper { 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); } } Loading Loading @@ -1192,7 +1202,6 @@ public class ZenModeHelper { 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); Loading @@ -1208,16 +1217,16 @@ public class ZenModeHelper { .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)) { Loading @@ -1231,9 +1240,6 @@ public class ZenModeHelper { 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) Loading @@ -1242,7 +1248,7 @@ public class ZenModeHelper { .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) { Loading @@ -1252,6 +1258,24 @@ public class ZenModeHelper { 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 Loading
services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +61 −10 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import static org.mockito.Mockito.atLeastOnce; 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; Loading Loading @@ -101,7 +102,6 @@ import android.util.Xml; 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; Loading @@ -110,9 +110,7 @@ import org.junit.Test; 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; Loading @@ -134,9 +132,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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; Loading @@ -146,7 +148,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory; @Before public void setUp() { public void setUp() throws PackageManager.NameNotFoundException { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); Loading @@ -169,6 +171,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 { Loading Loading @@ -238,19 +244,24 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 Loading Loading @@ -893,7 +904,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 { Loading @@ -903,6 +914,46 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertTrue("couldn't find custom rule", foundCustomEvent); } @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(); Loading