Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2beaf386 authored by Beverly's avatar Beverly
Browse files

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
parent 59ac27f9
Loading
Loading
Loading
Loading
+38 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
        }
    }
@@ -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);
@@ -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)) {
@@ -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)
@@ -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) {
@@ -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
+61 −10
Original line number Diff line number Diff line
@@ -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;
@@ -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;

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