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

Commit 7a976a43 authored by Mike Lockwood's avatar Mike Lockwood
Browse files

Fix UsbDeviceSettingsManager locking.



Change-Id: I93117ce791de95b0ab95017601f5d90ed5dd7a6a
Signed-off-by: default avatarMike Lockwood <lockwood@android.com>
parent c4308f01
Loading
Loading
Loading
Loading
+169 −132
Original line number Diff line number Diff line
@@ -64,18 +64,20 @@ class UsbDeviceSettingsManager {
    private final Context mContext;

    // maps UID to user approved USB devices
    final SparseArray<ArrayList<DeviceFilter>> mDevicePermissionMap =
    private final SparseArray<ArrayList<DeviceFilter>> mDevicePermissionMap =
            new SparseArray<ArrayList<DeviceFilter>>();
    // maps UID to user approved USB accessories
    final SparseArray<ArrayList<AccessoryFilter>> mAccessoryPermissionMap =
    private final SparseArray<ArrayList<AccessoryFilter>> mAccessoryPermissionMap =
            new SparseArray<ArrayList<AccessoryFilter>>();
    // Maps DeviceFilter to user preferred application package
    final HashMap<DeviceFilter, String> mDevicePreferenceMap =
    private final HashMap<DeviceFilter, String> mDevicePreferenceMap =
            new HashMap<DeviceFilter, String>();
    // Maps DeviceFilter to user preferred application package
    final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
    private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
            new HashMap<AccessoryFilter, String>();

    private final Object mLock = new Object();

    // This class is used to describe a USB device.
    // When used in HashMaps all values must be specified,
    // but wildcards can be used for any of the fields in
@@ -343,16 +345,20 @@ class UsbDeviceSettingsManager {

    private class MyPackageMonitor extends PackageMonitor {
        public void onPackageRemoved(String packageName, int uid) {
            synchronized (mLock) {
                // clear all activity preferences for the package
            if (clearPackageDefaults(packageName)) {
                writeSettings();
                if (clearPackageDefaultsLocked(packageName)) {
                    writeSettingsLocked();
                }
            }
        }

        public void onUidRemoved(int uid) {
            synchronized (mLock) {
                // clear all permissions for the UID
            if (clearUidDefaults(uid)) {
                writeSettings();
                if (clearUidDefaultsLocked(uid)) {
                    writeSettingsLocked();
                }
            }
        }
    }
@@ -360,7 +366,9 @@ class UsbDeviceSettingsManager {

    public UsbDeviceSettingsManager(Context context) {
        mContext = context;
        readSettings();
        synchronized (mLock) {
            readSettingsLocked();
        }
        mPackageMonitor.register(context, true);
    }

@@ -423,7 +431,7 @@ class UsbDeviceSettingsManager {
        XmlUtils.nextElement(parser);
    }

    private void readSettings() {
    private void readSettingsLocked() {
        FileInputStream stream = null;
        try {
            stream = new FileInputStream(sSettingsFile);
@@ -458,7 +466,7 @@ class UsbDeviceSettingsManager {
        }
    }

    private void writeSettings() {
    private void writeSettingsLocked() {
        FileOutputStream fos = null;
        try {
            FileOutputStream fstr = new FileOutputStream(sSettingsFile);
@@ -524,7 +532,7 @@ class UsbDeviceSettingsManager {

    // Checks to see if a package matches a device or accessory.
    // Only one of device and accessory should be non-null.
    private boolean packageMatches(ResolveInfo info, String metaDataName,
    private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
            UsbDevice device, UsbAccessory accessory) {
        ActivityInfo ai = info.activityInfo;
        PackageManager pm = mContext.getPackageManager();
@@ -562,7 +570,7 @@ class UsbDeviceSettingsManager {
        return false;
    }

    private final ArrayList<ResolveInfo> getDeviceMatches(UsbDevice device, Intent intent) {
    private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
        ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
        PackageManager pm = mContext.getPackageManager();
        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
@@ -570,14 +578,15 @@ class UsbDeviceSettingsManager {
        int count = resolveInfos.size();
        for (int i = 0; i < count; i++) {
            ResolveInfo resolveInfo = resolveInfos.get(i);
            if (packageMatches(resolveInfo, intent.getAction(), device, null)) {
            if (packageMatchesLocked(resolveInfo, intent.getAction(), device, null)) {
                matches.add(resolveInfo);
            }
        }
        return matches;
    }

    private final ArrayList<ResolveInfo> getAccessoryMatches(UsbAccessory accessory, Intent intent) {
    private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
            UsbAccessory accessory, Intent intent) {
        ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
        PackageManager pm = mContext.getPackageManager();
        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
@@ -585,7 +594,7 @@ class UsbDeviceSettingsManager {
        int count = resolveInfos.size();
        for (int i = 0; i < count; i++) {
            ResolveInfo resolveInfo = resolveInfos.get(i);
            if (packageMatches(resolveInfo, intent.getAction(), null, accessory)) {
            if (packageMatchesLocked(resolveInfo, intent.getAction(), null, accessory)) {
                matches.add(resolveInfo);
            }
        }
@@ -597,10 +606,15 @@ class UsbDeviceSettingsManager {
        deviceIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
        deviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        ArrayList<ResolveInfo> matches = getDeviceMatches(device, deviceIntent);
        ArrayList<ResolveInfo> matches;
        String defaultPackage;
        synchronized (mLock) {
            matches = getDeviceMatchesLocked(device, deviceIntent);
            // Launch our default activity directly, if we have one.
            // Otherwise we will start the UsbResolverActivity to allow the user to choose.
        String defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
            defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
        }

        if (defaultPackage != null) {
            int count = matches.size();
            for (int i = 0; i < count; i++) {
@@ -623,8 +637,7 @@ class UsbDeviceSettingsManager {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        intent.putExtra(Intent.EXTRA_INTENT, deviceIntent);
        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS,
                matches);
        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
        try {
            mContext.startActivity(intent);
        } catch (ActivityNotFoundException e) {
@@ -644,10 +657,15 @@ class UsbDeviceSettingsManager {
        accessoryIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
        accessoryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        ArrayList<ResolveInfo> matches = getAccessoryMatches(accessory, accessoryIntent);
        ArrayList<ResolveInfo> matches;
        String defaultPackage;
        synchronized (mLock) {
            matches = getAccessoryMatchesLocked(accessory, accessoryIntent);
            // Launch our default activity directly, if we have one.
            // Otherwise we will start the UsbResolverActivity to allow the user to choose.
        String defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
            defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
        }

        if (defaultPackage != null) {
            int count = matches.size();
            for (int i = 0; i < count; i++) {
@@ -670,8 +688,7 @@ class UsbDeviceSettingsManager {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        intent.putExtra(Intent.EXTRA_INTENT, accessoryIntent);
        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS,
                matches);
        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
        try {
            mContext.startActivity(intent);
        } catch (ActivityNotFoundException e) {
@@ -688,6 +705,7 @@ class UsbDeviceSettingsManager {

    public void checkPermission(UsbDevice device) {
        if (device == null) return;
        synchronized (mLock) {
            ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(Binder.getCallingUid());
            if (filterList != null) {
                int count = filterList.size();
@@ -699,11 +717,13 @@ class UsbDeviceSettingsManager {
                    }
                }
            }
        }
        throw new SecurityException("User has not given permission to device " + device);
    }

    public void checkPermission(UsbAccessory accessory) {
        if (accessory == null) return;
        synchronized (mLock) {
            ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(Binder.getCallingUid());
            if (filterList != null) {
                int count = filterList.size();
@@ -715,32 +735,38 @@ class UsbDeviceSettingsManager {
                    }
                }
            }
        }
        throw new SecurityException("User has not given permission to accessory " + accessory);
    }

    public void setDevicePackage(UsbDevice device, String packageName) {
        DeviceFilter filter = new DeviceFilter(device);
        synchronized (mLock) {
            if (packageName == null) {
                mDevicePreferenceMap.remove(filter);
            } else {
                mDevicePreferenceMap.put(filter, packageName);
            }
           // FIXME - only if changed
        writeSettings();
            writeSettingsLocked();
        }
    }

    public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
        AccessoryFilter filter = new AccessoryFilter(accessory);
        synchronized (mLock) {
            if (packageName == null) {
                mAccessoryPreferenceMap.remove(filter);
            } else {
                mAccessoryPreferenceMap.put(filter, packageName);
            }
            // FIXME - only if changed
        writeSettings();
            writeSettingsLocked();
        }
    }

    public void grantDevicePermission(UsbDevice device, int uid) {
        synchronized (mLock) {
            ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(uid);
            if (filterList == null) {
                filterList = new ArrayList<DeviceFilter>();
@@ -752,10 +778,12 @@ class UsbDeviceSettingsManager {
                }
            }
            filterList.add(new DeviceFilter(device));
        writeSettings();
            writeSettingsLocked();
        }
    }

    public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
        synchronized (mLock) {
            ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(uid);
            if (filterList == null) {
                filterList = new ArrayList<AccessoryFilter>();
@@ -767,26 +795,31 @@ class UsbDeviceSettingsManager {
                }
            }
            filterList.add(new AccessoryFilter(accessory));
        writeSettings();
            writeSettingsLocked();
        }
    }

    public boolean hasDefaults(String packageName, int uid) {
        synchronized (mLock) {
            if (mDevicePermissionMap.get(uid) != null) return true;
            if (mAccessoryPermissionMap.get(uid) != null) return true;
            if (mDevicePreferenceMap.values().contains(packageName)) return true;
            if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
            return false;
        }
    }

    public void clearDefaults(String packageName, int uid) {
        boolean packageCleared = clearPackageDefaults(packageName);
        boolean uidCleared = clearUidDefaults(uid);
        synchronized (mLock) {
            boolean packageCleared = clearPackageDefaultsLocked(packageName);
            boolean uidCleared = clearUidDefaultsLocked(uid);
            if (packageCleared || uidCleared) {
            writeSettings();
                writeSettingsLocked();
            }
        }
    }

    private boolean clearUidDefaults(int uid) {
    private boolean clearUidDefaultsLocked(int uid) {
        boolean cleared = false;
        int index = mDevicePermissionMap.indexOfKey(uid);
        if (index >= 0) {
@@ -801,8 +834,9 @@ class UsbDeviceSettingsManager {
        return cleared;
    }

    private boolean clearPackageDefaults(String packageName) {
    private boolean clearPackageDefaultsLocked(String packageName) {
        boolean cleared = false;
        synchronized (mLock) {
            if (mDevicePreferenceMap.containsValue(packageName)) {
                // make a copy of the key set to avoid ConcurrentModificationException
                Object[] keys = mDevicePreferenceMap.keySet().toArray();
@@ -827,8 +861,10 @@ class UsbDeviceSettingsManager {
            }
            return cleared;
        }
    }

    public void dump(FileDescriptor fd, PrintWriter pw) {
        synchronized (mLock) {
            pw.println("  Device permissions:");
            int count = mDevicePermissionMap.size();
            for (int i = 0; i < count; i++) {
@@ -859,3 +895,4 @@ class UsbDeviceSettingsManager {
            }
        }
    }
}
+12 −24
Original line number Diff line number Diff line
@@ -454,46 +454,34 @@ public class UsbService extends IUsbManager.Stub {
    }

    public void setDevicePackage(UsbDevice device, String packageName) {
        synchronized (mLock) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        mDeviceManager.setDevicePackage(device, packageName);
    }
    }

    public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
        synchronized (mLock) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        mDeviceManager.setAccessoryPackage(accessory, packageName);
    }
    }

    public void grantDevicePermission(UsbDevice device, int uid) {
        synchronized (mLock) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        mDeviceManager.grantDevicePermission(device, uid);
    }
    }

    public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
        synchronized (mLock) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        mDeviceManager.grantAccessoryPermission(accessory, uid);
    }
    }

    public boolean hasDefaults(String packageName, int uid) {
        synchronized (mLock) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        return mDeviceManager.hasDefaults(packageName, uid);
    }
    }

    public void clearDefaults(String packageName, int uid) {
        synchronized (mLock) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        mDeviceManager.clearDefaults(packageName, uid);
    }
    }

    /*
     * This handler is for deferred handling of events related to device mode and accessories.