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

Commit d9f045eb authored by Evan Severson's avatar Evan Severson
Browse files

Usb launch preference denial able to be remembered

When a device is connected the user might be prompted with
a dialog to launch an application. This change creates the
api that the system UI will use to give the user a
"deny [for this device+package] and remember" option.

Test: Manual:
      Edit usb_device_manager.xml and observe correct behavior
      Call new methods and observe correct changes in xml file
Bug: 136496922

Change-Id: I20e377d601ec11b8d42c79e4c726b9a4cb68c8b0
parent fcedf736
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -55,6 +55,18 @@ interface IUsbManager
     */
    void setAccessoryPackage(in UsbAccessory accessory, String packageName, int userId);

    /* Adds packages to the set of "denied and don't ask again" launch preferences for a device */
    void addDevicePackagesToPreferenceDenied(in UsbDevice device, in String[] packageNames, in UserHandle user);

    /* Adds packages to the set of "denied and don't ask again" launch preferences for an accessory */
    void addAccessoryPackagesToPreferenceDenied(in UsbAccessory accessory, in String[] packageNames, in UserHandle user);

    /* Removes packages from the set of "denied and don't ask again" launch preferences for a device */
    void removeDevicePackagesFromPreferenceDenied(in UsbDevice device, in String[] packageNames, in UserHandle user);

    /* Removes packages from the set of "denied and don't ask again" launch preferences for an accessory */
    void removeAccessoryPackagesFromPreferenceDenied(in UsbAccessory device, in String[] packageNames, in UserHandle user);

    /* Sets the persistent permission granted state for USB device
     */
    void setDevicePersistentPermission(in UsbDevice device, int uid, in UserHandle user, boolean shouldBeGranted);
+311 −4
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ import android.service.usb.UsbProfileGroupSettingsManagerProto;
import android.service.usb.UsbSettingsAccessoryPreferenceProto;
import android.service.usb.UsbSettingsDevicePreferenceProto;
import android.service.usb.UserPackageProto;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
@@ -70,6 +72,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ProtocolException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
@@ -102,10 +105,20 @@ class UsbProfileGroupSettingsManager {
    @GuardedBy("mLock")
    private final HashMap<DeviceFilter, UserPackage> mDevicePreferenceMap = new HashMap<>();

    /** Maps DeviceFilter to set of UserPackages not to ask for launch preference anymore */
    @GuardedBy("mLock")
    private final ArrayMap<DeviceFilter, ArraySet<UserPackage>> mDevicePreferenceDeniedMap =
            new ArrayMap<>();

    /** Maps AccessoryFilter to user preferred application package */
    @GuardedBy("mLock")
    private final HashMap<AccessoryFilter, UserPackage> mAccessoryPreferenceMap = new HashMap<>();

    /** Maps AccessoryFilter to set of UserPackages not to ask for launch preference anymore */
    @GuardedBy("mLock")
    private final ArrayMap<AccessoryFilter, ArraySet<UserPackage>> mAccessoryPreferenceDeniedMap =
            new ArrayMap<>();

    private final Object mLock = new Object();

    /**
@@ -248,11 +261,11 @@ class UsbProfileGroupSettingsManager {
    }

    /**
     * Remove all defaults for a user.
     * Remove all defaults and denied packages for a user.
     *
     * @param userToRemove The user the defaults belong to.
     * @param userToRemove The user
     */
    void removeAllDefaultsForUser(@NonNull UserHandle userToRemove) {
    void removeUser(@NonNull UserHandle userToRemove) {
        synchronized (mLock) {
            boolean needToPersist = false;
            Iterator<Map.Entry<DeviceFilter, UserPackage>> devicePreferenceIt = mDevicePreferenceMap
@@ -277,6 +290,28 @@ class UsbProfileGroupSettingsManager {
                }
            }

            int numEntries = mDevicePreferenceDeniedMap.size();
            for (int i = 0; i < numEntries; i++) {
                ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.valueAt(i);
                for (int j = userPackages.size() - 1; j >= 0; j--) {
                    if (userPackages.valueAt(j).user.equals(userToRemove)) {
                        userPackages.removeAt(j);
                        needToPersist = true;
                    }
                }
            }

            numEntries = mAccessoryPreferenceDeniedMap.size();
            for (int i = 0; i < numEntries; i++) {
                ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.valueAt(i);
                for (int j = userPackages.size() - 1; j >= 0; j--) {
                    if (userPackages.valueAt(j).user.equals(userToRemove)) {
                        userPackages.removeAt(j);
                        needToPersist = true;
                    }
                }
            }

            if (needToPersist) {
                scheduleWriteSettingsLocked();
            }
@@ -284,7 +319,7 @@ class UsbProfileGroupSettingsManager {
    }

    private void readPreference(XmlPullParser parser)
            throws XmlPullParserException, IOException {
            throws IOException, XmlPullParserException {
        String packageName = null;

        // If not set, assume it to be the parent profile
@@ -317,6 +352,67 @@ class UsbProfileGroupSettingsManager {
        XmlUtils.nextElement(parser);
    }

    private void readPreferenceDeniedList(@NonNull XmlPullParser parser)
            throws IOException, XmlPullParserException {
        int outerDepth = parser.getDepth();
        if (!XmlUtils.nextElementWithin(parser, outerDepth)) {
            return;
        }

        if ("usb-device".equals(parser.getName())) {
            DeviceFilter filter = DeviceFilter.read(parser);
            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                if ("user-package".equals(parser.getName())) {
                    try {
                        int userId = XmlUtils.readIntAttribute(parser, "user");

                        String packageName = XmlUtils.readStringAttribute(parser, "package");
                        if (packageName == null) {
                            Slog.e(TAG, "Unable to parse package name");
                        }

                        ArraySet<UserPackage> set = mDevicePreferenceDeniedMap.get(filter);
                        if (set == null) {
                            set = new ArraySet<>();
                            mDevicePreferenceDeniedMap.put(filter, set);
                        }
                        set.add(new UserPackage(packageName, UserHandle.of(userId)));
                    } catch (ProtocolException e) {
                        Slog.e(TAG, "Unable to parse user id", e);
                    }
                }
            }
        } else if ("usb-accessory".equals(parser.getName())) {
            AccessoryFilter filter = AccessoryFilter.read(parser);

            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                if ("user-package".equals(parser.getName())) {
                    try {
                        int userId = XmlUtils.readIntAttribute(parser, "user");

                        String packageName = XmlUtils.readStringAttribute(parser, "package");
                        if (packageName == null) {
                            Slog.e(TAG, "Unable to parse package name");
                        }

                        ArraySet<UserPackage> set = mAccessoryPreferenceDeniedMap.get(filter);
                        if (set == null) {
                            set = new ArraySet<>();
                            mAccessoryPreferenceDeniedMap.put(filter, set);
                        }
                        set.add(new UserPackage(packageName, UserHandle.of(userId)));
                    } catch (ProtocolException e) {
                        Slog.e(TAG, "Unable to parse user id", e);
                    }
                }
            }
        }

        while (parser.getDepth() > outerDepth) {
            parser.nextTag(); // ignore unknown tags
        }
    }

    /**
     * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
     * Should only be called by owner.
@@ -373,6 +469,8 @@ class UsbProfileGroupSettingsManager {
                String tagName = parser.getName();
                if ("preference".equals(tagName)) {
                    readPreference(parser);
                } else if ("preference-denied-list".equals(tagName)) {
                    readPreferenceDeniedList(parser);
                } else {
                    XmlUtils.nextElement(parser);
                }
@@ -436,6 +534,46 @@ class UsbProfileGroupSettingsManager {
                        serializer.endTag(null, "preference");
                    }

                    int numEntries = mDevicePreferenceDeniedMap.size();
                    for (int i = 0; i < numEntries; i++) {
                        DeviceFilter filter = mDevicePreferenceDeniedMap.keyAt(i);
                        ArraySet<UserPackage> userPackageSet = mDevicePreferenceDeniedMap
                                .valueAt(i);
                        serializer.startTag(null, "preference-denied-list");
                        filter.write(serializer);

                        int numUserPackages = userPackageSet.size();
                        for (int j = 0; j < numUserPackages; j++) {
                            UserPackage userPackage = userPackageSet.valueAt(j);
                            serializer.startTag(null, "user-package");
                            serializer.attribute(null, "user",
                                    String.valueOf(getSerial(userPackage.user)));
                            serializer.attribute(null, "package", userPackage.packageName);
                            serializer.endTag(null, "user-package");
                        }
                        serializer.endTag(null, "preference-denied-list");
                    }

                    numEntries = mAccessoryPreferenceDeniedMap.size();
                    for (int i = 0; i < numEntries; i++) {
                        AccessoryFilter filter = mAccessoryPreferenceDeniedMap.keyAt(i);
                        ArraySet<UserPackage> userPackageSet =
                                mAccessoryPreferenceDeniedMap.valueAt(i);
                        serializer.startTag(null, "preference-denied-list");
                        filter.write(serializer);

                        int numUserPackages = userPackageSet.size();
                        for (int j = 0; j < numUserPackages; j++) {
                            UserPackage userPackage = userPackageSet.valueAt(j);
                            serializer.startTag(null, "user-package");
                            serializer.attribute(null, "user",
                                    String.valueOf(getSerial(userPackage.user)));
                            serializer.attribute(null, "package", userPackage.packageName);
                            serializer.endTag(null, "user-package");
                        }
                        serializer.endTag(null, "preference-denied-list");
                    }

                    serializer.endTag(null, "settings");
                    serializer.endDocument();

@@ -834,6 +972,25 @@ class UsbProfileGroupSettingsManager {
    private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches,
            @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device,
            @Nullable UsbAccessory accessory) {
        // Remove all matches which are on the denied list
        ArraySet deniedPackages = null;
        if (device != null) {
            deniedPackages = mDevicePreferenceDeniedMap.get(new DeviceFilter(device));
        } else if (accessory != null) {
            deniedPackages = mAccessoryPreferenceDeniedMap.get(new AccessoryFilter(accessory));
        }
        if (deniedPackages != null) {
            for (int i = matches.size() - 1; i >= 0; i--) {
                ResolveInfo match = matches.get(i);
                String packageName = match.activityInfo.packageName;
                UserHandle user = UserHandle
                        .getUserHandleForUid(match.activityInfo.applicationInfo.uid);
                if (deniedPackages.contains(new UserPackage(packageName, user))) {
                    matches.remove(i);
                }
            }
        }

        // don't show the resolver activity if there are no choices available
        if (matches.size() == 0) {
            if (accessory != null) {
@@ -1075,6 +1232,156 @@ class UsbProfileGroupSettingsManager {
        }
    }

    /**
     * Add package to the denied for handling a device
     *
     * @param device the device to add to the denied
     * @param packageNames the packages to not become handler
     * @param user the user
     */
    void addDevicePackagesToDenied(@NonNull UsbDevice device, @NonNull String[] packageNames,
            @NonNull UserHandle user) {
        if (packageNames.length == 0) {
            return;
        }
        DeviceFilter filter = new DeviceFilter(device);

        synchronized (mLock) {
            ArraySet<UserPackage> userPackages;
            if (mDevicePreferenceDeniedMap.containsKey(filter)) {
                userPackages = mDevicePreferenceDeniedMap.get(filter);
            } else {
                userPackages = new ArraySet<>();
                mDevicePreferenceDeniedMap.put(filter, userPackages);
            }

            boolean shouldWrite = false;
            for (String packageName : packageNames) {
                UserPackage userPackage = new UserPackage(packageName, user);
                if (!userPackages.contains(userPackage)) {
                    userPackages.add(userPackage);
                    shouldWrite = true;
                }
            }

            if (shouldWrite) {
                scheduleWriteSettingsLocked();
            }
        }
    }

    /**
     * Add package to the denied for handling a accessory
     *
     * @param accessory the accessory to add to the denied
     * @param packageNames the packages to not become handler
     * @param user the user
     */
    void addAccessoryPackagesToDenied(@NonNull UsbAccessory accessory,
            @NonNull String[] packageNames, @NonNull UserHandle user) {
        if (packageNames.length == 0) {
            return;
        }
        AccessoryFilter filter = new AccessoryFilter(accessory);

        synchronized (mLock) {
            ArraySet<UserPackage> userPackages;
            if (mAccessoryPreferenceDeniedMap.containsKey(filter)) {
                userPackages = mAccessoryPreferenceDeniedMap.get(filter);
            } else {
                userPackages = new ArraySet<>();
                mAccessoryPreferenceDeniedMap.put(filter, userPackages);
            }

            boolean shouldWrite = false;
            for (String packageName : packageNames) {
                UserPackage userPackage = new UserPackage(packageName, user);
                if (!userPackages.contains(userPackage)) {
                    userPackages.add(userPackage);
                    shouldWrite = true;
                }
            }

            if (shouldWrite) {
                scheduleWriteSettingsLocked();
            }
        }
    }

    /**
     * Remove UserPackage from the denied for handling a device
     *
     * @param device the device to remove denied packages from
     * @param packageName the packages to remove
     * @param user the user
     */
    void removeDevicePackagesFromDenied(@NonNull UsbDevice device, @NonNull String[] packageNames,
            @NonNull UserHandle user) {
        DeviceFilter filter = new DeviceFilter(device);

        synchronized (mLock) {
            ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.get(filter);

            if (userPackages != null) {
                boolean shouldWrite = false;
                for (String packageName : packageNames) {
                    UserPackage userPackage = new UserPackage(packageName, user);

                    if (userPackages.contains(userPackage)) {
                        userPackages.remove(userPackage);
                        shouldWrite = true;

                        if (userPackages.size() == 0) {
                            mDevicePreferenceDeniedMap.remove(filter);
                            break;
                        }
                    }
                }

                if (shouldWrite) {
                    scheduleWriteSettingsLocked();
                }
            }
        }
    }

    /**
     * Remove UserPackage from the denied for handling a accessory
     *
     * @param accessory the accessory to remove denied packages from
     * @param packageName the packages to remove
     * @param user the user
     */
    void removeAccessoryPackagesFromDenied(@NonNull UsbAccessory accessory,
            @NonNull String[] packageNames, @NonNull UserHandle user) {
        AccessoryFilter filter = new AccessoryFilter(accessory);

        synchronized (mLock) {
            ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.get(filter);

            if (userPackages != null) {
                boolean shouldWrite = false;
                for (String packageName : packageNames) {
                    UserPackage userPackage = new UserPackage(packageName, user);

                    if (userPackages.contains(userPackage)) {
                        userPackages.remove(userPackage);
                        shouldWrite = true;

                        if (userPackages.size() == 0) {
                            mAccessoryPreferenceDeniedMap.remove(filter);
                            break;
                        }
                    }
                }

                if (shouldWrite) {
                    scheduleWriteSettingsLocked();
                }
            }
        }
    }

    /**
     * Set a package as default handler for a accessory.
     *
+72 −0
Original line number Diff line number Diff line
@@ -360,6 +360,78 @@ public class UsbService extends IUsbManager.Stub {
        }
    }

    @Override
    public void addDevicePackagesToPreferenceDenied(UsbDevice device, String[] packageNames,
            UserHandle user) {
        device = Preconditions.checkNotNull(device);
        packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
        user = Preconditions.checkNotNull(user);

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);

        final long token = Binder.clearCallingIdentity();
        try {
            mSettingsManager.getSettingsForProfileGroup(user)
                    .addDevicePackagesToDenied(device, packageNames, user);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public void addAccessoryPackagesToPreferenceDenied(UsbAccessory accessory,
            String[] packageNames, UserHandle user) {
        accessory = Preconditions.checkNotNull(accessory);
        packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
        user = Preconditions.checkNotNull(user);

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);

        final long token = Binder.clearCallingIdentity();
        try {
            mSettingsManager.getSettingsForProfileGroup(user)
                    .addAccessoryPackagesToDenied(accessory, packageNames, user);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public void removeDevicePackagesFromPreferenceDenied(UsbDevice device, String[] packageNames,
            UserHandle user) {
        device = Preconditions.checkNotNull(device);
        packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
        user = Preconditions.checkNotNull(user);

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);

        final long token = Binder.clearCallingIdentity();
        try {
            mSettingsManager.getSettingsForProfileGroup(user)
                    .removeDevicePackagesFromDenied(device, packageNames, user);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public void removeAccessoryPackagesFromPreferenceDenied(UsbAccessory accessory,
            String[] packageNames, UserHandle user) {
        accessory = Preconditions.checkNotNull(accessory);
        packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
        user = Preconditions.checkNotNull(user);

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);

        final long token = Binder.clearCallingIdentity();
        try {
            mSettingsManager.getSettingsForProfileGroup(user)
                    .removeAccessoryPackagesFromDenied(accessory, packageNames, user);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public void setDevicePersistentPermission(UsbDevice device, int uid, UserHandle user,
            boolean shouldBeGranted) {
+1 −1
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ class UsbSettingsManager {
                // it from all profile groups.
                int numProfileGroups = mSettingsByProfileGroup.size();
                for (int i = 0; i < numProfileGroups; i++) {
                    mSettingsByProfileGroup.valueAt(i).removeAllDefaultsForUser(userToRemove);
                    mSettingsByProfileGroup.valueAt(i).removeUser(userToRemove);
                }
            }
        }