Home | History | Annotate | Download | only in usb
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.usb;
     18 
     19 import android.app.PendingIntent;
     20 import android.content.ActivityNotFoundException;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.pm.ActivityInfo;
     25 import android.content.pm.ApplicationInfo;
     26 import android.content.pm.PackageInfo;
     27 import android.content.pm.PackageManager;
     28 import android.content.pm.PackageManager.NameNotFoundException;
     29 import android.content.pm.ResolveInfo;
     30 import android.content.res.XmlResourceParser;
     31 import android.hardware.usb.UsbAccessory;
     32 import android.hardware.usb.UsbDevice;
     33 import android.hardware.usb.UsbInterface;
     34 import android.hardware.usb.UsbManager;
     35 import android.os.Binder;
     36 import android.os.Environment;
     37 import android.os.Process;
     38 import android.os.UserHandle;
     39 import android.util.AtomicFile;
     40 import android.util.Log;
     41 import android.util.Slog;
     42 import android.util.SparseBooleanArray;
     43 import android.util.Xml;
     44 
     45 import com.android.internal.content.PackageMonitor;
     46 import com.android.internal.util.FastXmlSerializer;
     47 import com.android.internal.util.IndentingPrintWriter;
     48 import com.android.internal.util.XmlUtils;
     49 
     50 import org.xmlpull.v1.XmlPullParser;
     51 import org.xmlpull.v1.XmlPullParserException;
     52 import org.xmlpull.v1.XmlSerializer;
     53 
     54 import java.io.File;
     55 import java.io.FileInputStream;
     56 import java.io.FileNotFoundException;
     57 import java.io.FileOutputStream;
     58 import java.io.IOException;
     59 import java.nio.charset.StandardCharsets;
     60 import java.util.ArrayList;
     61 import java.util.HashMap;
     62 import java.util.List;
     63 
     64 import libcore.io.IoUtils;
     65 
     66 class UsbSettingsManager {
     67     private static final String TAG = "UsbSettingsManager";
     68     private static final boolean DEBUG = false;
     69 
     70     /** Legacy settings file, before multi-user */
     71     private static final File sSingleUserSettingsFile = new File(
     72             "/data/system/usb_device_manager.xml");
     73 
     74     private final UserHandle mUser;
     75     private final AtomicFile mSettingsFile;
     76     private final boolean mDisablePermissionDialogs;
     77 
     78     private final Context mContext;
     79     private final Context mUserContext;
     80     private final PackageManager mPackageManager;
     81 
     82     // Temporary mapping USB device name to list of UIDs with permissions for the device
     83     private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
     84             new HashMap<String, SparseBooleanArray>();
     85     // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
     86     private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
     87             new HashMap<UsbAccessory, SparseBooleanArray>();
     88     // Maps DeviceFilter to user preferred application package
     89     private final HashMap<DeviceFilter, String> mDevicePreferenceMap =
     90             new HashMap<DeviceFilter, String>();
     91     // Maps AccessoryFilter to user preferred application package
     92     private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
     93             new HashMap<AccessoryFilter, String>();
     94 
     95     private final Object mLock = new Object();
     96 
     97     // This class is used to describe a USB device.
     98     // When used in HashMaps all values must be specified,
     99     // but wildcards can be used for any of the fields in
    100     // the package meta-data.
    101     private static class DeviceFilter {
    102         // USB Vendor ID (or -1 for unspecified)
    103         public final int mVendorId;
    104         // USB Product ID (or -1 for unspecified)
    105         public final int mProductId;
    106         // USB device or interface class (or -1 for unspecified)
    107         public final int mClass;
    108         // USB device subclass (or -1 for unspecified)
    109         public final int mSubclass;
    110         // USB device protocol (or -1 for unspecified)
    111         public final int mProtocol;
    112         // USB device manufacturer name string (or null for unspecified)
    113         public final String mManufacturerName;
    114         // USB device product name string (or null for unspecified)
    115         public final String mProductName;
    116         // USB device serial number string (or null for unspecified)
    117         public final String mSerialNumber;
    118 
    119         public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
    120                             String manufacturer, String product, String serialnum) {
    121             mVendorId = vid;
    122             mProductId = pid;
    123             mClass = clasz;
    124             mSubclass = subclass;
    125             mProtocol = protocol;
    126             mManufacturerName = manufacturer;
    127             mProductName = product;
    128             mSerialNumber = serialnum;
    129         }
    130 
    131         public DeviceFilter(UsbDevice device) {
    132             mVendorId = device.getVendorId();
    133             mProductId = device.getProductId();
    134             mClass = device.getDeviceClass();
    135             mSubclass = device.getDeviceSubclass();
    136             mProtocol = device.getDeviceProtocol();
    137             mManufacturerName = device.getManufacturerName();
    138             mProductName = device.getProductName();
    139             mSerialNumber = device.getSerialNumber();
    140         }
    141 
    142         public static DeviceFilter read(XmlPullParser parser)
    143                 throws XmlPullParserException, IOException {
    144             int vendorId = -1;
    145             int productId = -1;
    146             int deviceClass = -1;
    147             int deviceSubclass = -1;
    148             int deviceProtocol = -1;
    149             String manufacturerName = null;
    150             String productName = null;
    151             String serialNumber = null;
    152 
    153             int count = parser.getAttributeCount();
    154             for (int i = 0; i < count; i++) {
    155                 String name = parser.getAttributeName(i);
    156                 String value = parser.getAttributeValue(i);
    157                 // Attribute values are ints or strings
    158                 if ("manufacturer-name".equals(name)) {
    159                     manufacturerName = value;
    160                 } else if ("product-name".equals(name)) {
    161                     productName = value;
    162                 } else if ("serial-number".equals(name)) {
    163                     serialNumber = value;
    164                 } else {
    165                     int intValue = -1;
    166                     int radix = 10;
    167                     if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
    168                         (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
    169                         // allow hex values starting with 0x or 0X
    170                         radix = 16;
    171                         value = value.substring(2);
    172                     }
    173                     try {
    174                         intValue = Integer.parseInt(value, radix);
    175                     } catch (NumberFormatException e) {
    176                         Slog.e(TAG, "invalid number for field " + name, e);
    177                         continue;
    178                     }
    179                     if ("vendor-id".equals(name)) {
    180                         vendorId = intValue;
    181                     } else if ("product-id".equals(name)) {
    182                         productId = intValue;
    183                     } else if ("class".equals(name)) {
    184                         deviceClass = intValue;
    185                     } else if ("subclass".equals(name)) {
    186                         deviceSubclass = intValue;
    187                     } else if ("protocol".equals(name)) {
    188                         deviceProtocol = intValue;
    189                     }
    190                 }
    191             }
    192             return new DeviceFilter(vendorId, productId,
    193                     deviceClass, deviceSubclass, deviceProtocol,
    194                     manufacturerName, productName, serialNumber);
    195         }
    196 
    197         public void write(XmlSerializer serializer) throws IOException {
    198             serializer.startTag(null, "usb-device");
    199             if (mVendorId != -1) {
    200                 serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
    201             }
    202             if (mProductId != -1) {
    203                 serializer.attribute(null, "product-id", Integer.toString(mProductId));
    204             }
    205             if (mClass != -1) {
    206                 serializer.attribute(null, "class", Integer.toString(mClass));
    207             }
    208             if (mSubclass != -1) {
    209                 serializer.attribute(null, "subclass", Integer.toString(mSubclass));
    210             }
    211             if (mProtocol != -1) {
    212                 serializer.attribute(null, "protocol", Integer.toString(mProtocol));
    213             }
    214             if (mManufacturerName != null) {
    215                 serializer.attribute(null, "manufacturer-name", mManufacturerName);
    216             }
    217             if (mProductName != null) {
    218                 serializer.attribute(null, "product-name", mProductName);
    219             }
    220             if (mSerialNumber != null) {
    221                 serializer.attribute(null, "serial-number", mSerialNumber);
    222             }
    223             serializer.endTag(null, "usb-device");
    224         }
    225 
    226         private boolean matches(int clasz, int subclass, int protocol) {
    227             return ((mClass == -1 || clasz == mClass) &&
    228                     (mSubclass == -1 || subclass == mSubclass) &&
    229                     (mProtocol == -1 || protocol == mProtocol));
    230         }
    231 
    232         public boolean matches(UsbDevice device) {
    233             if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
    234             if (mProductId != -1 && device.getProductId() != mProductId) return false;
    235             if (mManufacturerName != null && device.getManufacturerName() == null) return false;
    236             if (mProductName != null && device.getProductName() == null) return false;
    237             if (mSerialNumber != null && device.getSerialNumber() == null) return false;
    238             if (mManufacturerName != null && device.getManufacturerName() != null &&
    239                 !mManufacturerName.equals(device.getManufacturerName())) return false;
    240             if (mProductName != null && device.getProductName() != null &&
    241                 !mProductName.equals(device.getProductName())) return false;
    242             if (mSerialNumber != null && device.getSerialNumber() != null &&
    243                 !mSerialNumber.equals(device.getSerialNumber())) return false;
    244 
    245             // check device class/subclass/protocol
    246             if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
    247                     device.getDeviceProtocol())) return true;
    248 
    249             // if device doesn't match, check the interfaces
    250             int count = device.getInterfaceCount();
    251             for (int i = 0; i < count; i++) {
    252                 UsbInterface intf = device.getInterface(i);
    253                  if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
    254                         intf.getInterfaceProtocol())) return true;
    255             }
    256 
    257             return false;
    258         }
    259 
    260         public boolean matches(DeviceFilter f) {
    261             if (mVendorId != -1 && f.mVendorId != mVendorId) return false;
    262             if (mProductId != -1 && f.mProductId != mProductId) return false;
    263             if (f.mManufacturerName != null && mManufacturerName == null) return false;
    264             if (f.mProductName != null && mProductName == null) return false;
    265             if (f.mSerialNumber != null && mSerialNumber == null) return false;
    266             if (mManufacturerName != null && f.mManufacturerName != null &&
    267                 !mManufacturerName.equals(f.mManufacturerName)) return false;
    268             if (mProductName != null && f.mProductName != null &&
    269                 !mProductName.equals(f.mProductName)) return false;
    270             if (mSerialNumber != null && f.mSerialNumber != null &&
    271                 !mSerialNumber.equals(f.mSerialNumber)) return false;
    272 
    273             // check device class/subclass/protocol
    274             return matches(f.mClass, f.mSubclass, f.mProtocol);
    275         }
    276 
    277         @Override
    278         public boolean equals(Object obj) {
    279             // can't compare if we have wildcard strings
    280             if (mVendorId == -1 || mProductId == -1 ||
    281                     mClass == -1 || mSubclass == -1 || mProtocol == -1) {
    282                 return false;
    283             }
    284             if (obj instanceof DeviceFilter) {
    285                 DeviceFilter filter = (DeviceFilter)obj;
    286 
    287                 if (filter.mVendorId != mVendorId ||
    288                         filter.mProductId != mProductId ||
    289                         filter.mClass != mClass ||
    290                         filter.mSubclass != mSubclass ||
    291                         filter.mProtocol != mProtocol) {
    292                     return(false);
    293                 }
    294                 if ((filter.mManufacturerName != null &&
    295                         mManufacturerName == null) ||
    296                     (filter.mManufacturerName == null &&
    297                         mManufacturerName != null) ||
    298                     (filter.mProductName != null &&
    299                         mProductName == null)  ||
    300                     (filter.mProductName == null &&
    301                         mProductName != null) ||
    302                     (filter.mSerialNumber != null &&
    303                         mSerialNumber == null)  ||
    304                     (filter.mSerialNumber == null &&
    305                         mSerialNumber != null)) {
    306                     return(false);
    307                 }
    308                 if  ((filter.mManufacturerName != null &&
    309                         mManufacturerName != null &&
    310                         !mManufacturerName.equals(filter.mManufacturerName)) ||
    311                      (filter.mProductName != null &&
    312                         mProductName != null &&
    313                         !mProductName.equals(filter.mProductName)) ||
    314                      (filter.mSerialNumber != null &&
    315                         mSerialNumber != null &&
    316                         !mSerialNumber.equals(filter.mSerialNumber))) {
    317                     return(false);
    318                 }
    319                 return(true);
    320             }
    321             if (obj instanceof UsbDevice) {
    322                 UsbDevice device = (UsbDevice)obj;
    323                 if (device.getVendorId() != mVendorId ||
    324                         device.getProductId() != mProductId ||
    325                         device.getDeviceClass() != mClass ||
    326                         device.getDeviceSubclass() != mSubclass ||
    327                         device.getDeviceProtocol() != mProtocol) {
    328                     return(false);
    329                 }
    330                 if ((mManufacturerName != null && device.getManufacturerName() == null) ||
    331                         (mManufacturerName == null && device.getManufacturerName() != null) ||
    332                         (mProductName != null && device.getProductName() == null) ||
    333                         (mProductName == null && device.getProductName() != null) ||
    334                         (mSerialNumber != null && device.getSerialNumber() == null) ||
    335                         (mSerialNumber == null && device.getSerialNumber() != null)) {
    336                     return(false);
    337                 }
    338                 if ((device.getManufacturerName() != null &&
    339                         !mManufacturerName.equals(device.getManufacturerName())) ||
    340                         (device.getProductName() != null &&
    341                             !mProductName.equals(device.getProductName())) ||
    342                         (device.getSerialNumber() != null &&
    343                             !mSerialNumber.equals(device.getSerialNumber()))) {
    344                     return(false);
    345                 }
    346                 return true;
    347             }
    348             return false;
    349         }
    350 
    351         @Override
    352         public int hashCode() {
    353             return (((mVendorId << 16) | mProductId) ^
    354                     ((mClass << 16) | (mSubclass << 8) | mProtocol));
    355         }
    356 
    357         @Override
    358         public String toString() {
    359             return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
    360                     ",mClass=" + mClass + ",mSubclass=" + mSubclass +
    361                     ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
    362                     ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
    363                     "]";
    364         }
    365     }
    366 
    367     // This class is used to describe a USB accessory.
    368     // When used in HashMaps all values must be specified,
    369     // but wildcards can be used for any of the fields in
    370     // the package meta-data.
    371     private static class AccessoryFilter {
    372         // USB accessory manufacturer (or null for unspecified)
    373         public final String mManufacturer;
    374         // USB accessory model (or null for unspecified)
    375         public final String mModel;
    376         // USB accessory version (or null for unspecified)
    377         public final String mVersion;
    378 
    379         public AccessoryFilter(String manufacturer, String model, String version) {
    380             mManufacturer = manufacturer;
    381             mModel = model;
    382             mVersion = version;
    383         }
    384 
    385         public AccessoryFilter(UsbAccessory accessory) {
    386             mManufacturer = accessory.getManufacturer();
    387             mModel = accessory.getModel();
    388             mVersion = accessory.getVersion();
    389         }
    390 
    391         public static AccessoryFilter read(XmlPullParser parser)
    392                 throws XmlPullParserException, IOException {
    393             String manufacturer = null;
    394             String model = null;
    395             String version = null;
    396 
    397             int count = parser.getAttributeCount();
    398             for (int i = 0; i < count; i++) {
    399                 String name = parser.getAttributeName(i);
    400                 String value = parser.getAttributeValue(i);
    401 
    402                 if ("manufacturer".equals(name)) {
    403                     manufacturer = value;
    404                 } else if ("model".equals(name)) {
    405                     model = value;
    406                 } else if ("version".equals(name)) {
    407                     version = value;
    408                 }
    409              }
    410              return new AccessoryFilter(manufacturer, model, version);
    411         }
    412 
    413         public void write(XmlSerializer serializer)throws IOException {
    414             serializer.startTag(null, "usb-accessory");
    415             if (mManufacturer != null) {
    416                 serializer.attribute(null, "manufacturer", mManufacturer);
    417             }
    418             if (mModel != null) {
    419                 serializer.attribute(null, "model", mModel);
    420             }
    421             if (mVersion != null) {
    422                 serializer.attribute(null, "version", mVersion);
    423             }
    424             serializer.endTag(null, "usb-accessory");
    425         }
    426 
    427         public boolean matches(UsbAccessory acc) {
    428             if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
    429             if (mModel != null && !acc.getModel().equals(mModel)) return false;
    430             if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
    431             return true;
    432         }
    433 
    434         public boolean matches(AccessoryFilter f) {
    435             if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false;
    436             if (mModel != null && !f.mModel.equals(mModel)) return false;
    437             if (mVersion != null && !f.mVersion.equals(mVersion)) return false;
    438             return true;
    439         }
    440 
    441         @Override
    442         public boolean equals(Object obj) {
    443             // can't compare if we have wildcard strings
    444             if (mManufacturer == null || mModel == null || mVersion == null) {
    445                 return false;
    446             }
    447             if (obj instanceof AccessoryFilter) {
    448                 AccessoryFilter filter = (AccessoryFilter)obj;
    449                 return (mManufacturer.equals(filter.mManufacturer) &&
    450                         mModel.equals(filter.mModel) &&
    451                         mVersion.equals(filter.mVersion));
    452             }
    453             if (obj instanceof UsbAccessory) {
    454                 UsbAccessory accessory = (UsbAccessory)obj;
    455                 return (mManufacturer.equals(accessory.getManufacturer()) &&
    456                         mModel.equals(accessory.getModel()) &&
    457                         mVersion.equals(accessory.getVersion()));
    458             }
    459             return false;
    460         }
    461 
    462         @Override
    463         public int hashCode() {
    464             return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
    465                     (mModel == null ? 0 : mModel.hashCode()) ^
    466                     (mVersion == null ? 0 : mVersion.hashCode()));
    467         }
    468 
    469         @Override
    470         public String toString() {
    471             return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
    472                                 "\", mModel=\"" + mModel +
    473                                 "\", mVersion=\"" + mVersion + "\"]";
    474         }
    475     }
    476 
    477     private class MyPackageMonitor extends PackageMonitor {
    478         @Override
    479         public void onPackageAdded(String packageName, int uid) {
    480             handlePackageUpdate(packageName);
    481         }
    482 
    483         @Override
    484         public boolean onPackageChanged(String packageName, int uid, String[] components) {
    485             handlePackageUpdate(packageName);
    486             return false;
    487         }
    488 
    489         @Override
    490         public void onPackageRemoved(String packageName, int uid) {
    491             clearDefaults(packageName);
    492         }
    493     }
    494 
    495     MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
    496 
    497     private final MtpNotificationManager mMtpNotificationManager;
    498 
    499     public UsbSettingsManager(Context context, UserHandle user) {
    500         if (DEBUG) Slog.v(TAG, "Creating settings for " + user);
    501 
    502         try {
    503             mUserContext = context.createPackageContextAsUser("android", 0, user);
    504         } catch (NameNotFoundException e) {
    505             throw new RuntimeException("Missing android package");
    506         }
    507 
    508         mContext = context;
    509         mPackageManager = mUserContext.getPackageManager();
    510 
    511         mUser = user;
    512         mSettingsFile = new AtomicFile(new File(
    513                 Environment.getUserSystemDirectory(user.getIdentifier()),
    514                 "usb_device_manager.xml"));
    515 
    516         mDisablePermissionDialogs = context.getResources().getBoolean(
    517                 com.android.internal.R.bool.config_disableUsbPermissionDialogs);
    518 
    519         synchronized (mLock) {
    520             if (UserHandle.SYSTEM.equals(user)) {
    521                 upgradeSingleUserLocked();
    522             }
    523             readSettingsLocked();
    524         }
    525 
    526         mPackageMonitor.register(mUserContext, null, true);
    527         mMtpNotificationManager = new MtpNotificationManager(
    528                 context,
    529                 new MtpNotificationManager.OnOpenInAppListener() {
    530                     @Override
    531                     public void onOpenInApp(UsbDevice device) {
    532                         resolveActivity(createDeviceAttachedIntent(device), device);
    533                     }
    534                 });
    535     }
    536 
    537     private void readPreference(XmlPullParser parser)
    538             throws XmlPullParserException, IOException {
    539         String packageName = null;
    540         int count = parser.getAttributeCount();
    541         for (int i = 0; i < count; i++) {
    542             if ("package".equals(parser.getAttributeName(i))) {
    543                 packageName = parser.getAttributeValue(i);
    544                 break;
    545             }
    546         }
    547         XmlUtils.nextElement(parser);
    548         if ("usb-device".equals(parser.getName())) {
    549             DeviceFilter filter = DeviceFilter.read(parser);
    550             mDevicePreferenceMap.put(filter, packageName);
    551         } else if ("usb-accessory".equals(parser.getName())) {
    552             AccessoryFilter filter = AccessoryFilter.read(parser);
    553             mAccessoryPreferenceMap.put(filter, packageName);
    554         }
    555         XmlUtils.nextElement(parser);
    556     }
    557 
    558     /**
    559      * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
    560      * Should only by called by owner.
    561      */
    562     private void upgradeSingleUserLocked() {
    563         if (sSingleUserSettingsFile.exists()) {
    564             mDevicePreferenceMap.clear();
    565             mAccessoryPreferenceMap.clear();
    566 
    567             FileInputStream fis = null;
    568             try {
    569                 fis = new FileInputStream(sSingleUserSettingsFile);
    570                 XmlPullParser parser = Xml.newPullParser();
    571                 parser.setInput(fis, StandardCharsets.UTF_8.name());
    572 
    573                 XmlUtils.nextElement(parser);
    574                 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
    575                     final String tagName = parser.getName();
    576                     if ("preference".equals(tagName)) {
    577                         readPreference(parser);
    578                     } else {
    579                         XmlUtils.nextElement(parser);
    580                     }
    581                 }
    582             } catch (IOException e) {
    583                 Log.wtf(TAG, "Failed to read single-user settings", e);
    584             } catch (XmlPullParserException e) {
    585                 Log.wtf(TAG, "Failed to read single-user settings", e);
    586             } finally {
    587                 IoUtils.closeQuietly(fis);
    588             }
    589 
    590             writeSettingsLocked();
    591 
    592             // Success or failure, we delete single-user file
    593             sSingleUserSettingsFile.delete();
    594         }
    595     }
    596 
    597     private void readSettingsLocked() {
    598         if (DEBUG) Slog.v(TAG, "readSettingsLocked()");
    599 
    600         mDevicePreferenceMap.clear();
    601         mAccessoryPreferenceMap.clear();
    602 
    603         FileInputStream stream = null;
    604         try {
    605             stream = mSettingsFile.openRead();
    606             XmlPullParser parser = Xml.newPullParser();
    607             parser.setInput(stream, StandardCharsets.UTF_8.name());
    608 
    609             XmlUtils.nextElement(parser);
    610             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
    611                 String tagName = parser.getName();
    612                 if ("preference".equals(tagName)) {
    613                     readPreference(parser);
    614                 } else {
    615                     XmlUtils.nextElement(parser);
    616                 }
    617             }
    618         } catch (FileNotFoundException e) {
    619             if (DEBUG) Slog.d(TAG, "settings file not found");
    620         } catch (Exception e) {
    621             Slog.e(TAG, "error reading settings file, deleting to start fresh", e);
    622             mSettingsFile.delete();
    623         } finally {
    624             IoUtils.closeQuietly(stream);
    625         }
    626     }
    627 
    628     private void writeSettingsLocked() {
    629         if (DEBUG) Slog.v(TAG, "writeSettingsLocked()");
    630 
    631         FileOutputStream fos = null;
    632         try {
    633             fos = mSettingsFile.startWrite();
    634 
    635             FastXmlSerializer serializer = new FastXmlSerializer();
    636             serializer.setOutput(fos, StandardCharsets.UTF_8.name());
    637             serializer.startDocument(null, true);
    638             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
    639             serializer.startTag(null, "settings");
    640 
    641             for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
    642                 serializer.startTag(null, "preference");
    643                 serializer.attribute(null, "package", mDevicePreferenceMap.get(filter));
    644                 filter.write(serializer);
    645                 serializer.endTag(null, "preference");
    646             }
    647 
    648             for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
    649                 serializer.startTag(null, "preference");
    650                 serializer.attribute(null, "package", mAccessoryPreferenceMap.get(filter));
    651                 filter.write(serializer);
    652                 serializer.endTag(null, "preference");
    653             }
    654 
    655             serializer.endTag(null, "settings");
    656             serializer.endDocument();
    657 
    658             mSettingsFile.finishWrite(fos);
    659         } catch (IOException e) {
    660             Slog.e(TAG, "Failed to write settings", e);
    661             if (fos != null) {
    662                 mSettingsFile.failWrite(fos);
    663             }
    664         }
    665     }
    666 
    667     // Checks to see if a package matches a device or accessory.
    668     // Only one of device and accessory should be non-null.
    669     private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
    670             UsbDevice device, UsbAccessory accessory) {
    671         ActivityInfo ai = info.activityInfo;
    672 
    673         XmlResourceParser parser = null;
    674         try {
    675             parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
    676             if (parser == null) {
    677                 Slog.w(TAG, "no meta-data for " + info);
    678                 return false;
    679             }
    680 
    681             XmlUtils.nextElement(parser);
    682             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
    683                 String tagName = parser.getName();
    684                 if (device != null && "usb-device".equals(tagName)) {
    685                     DeviceFilter filter = DeviceFilter.read(parser);
    686                     if (filter.matches(device)) {
    687                         return true;
    688                     }
    689                 }
    690                 else if (accessory != null && "usb-accessory".equals(tagName)) {
    691                     AccessoryFilter filter = AccessoryFilter.read(parser);
    692                     if (filter.matches(accessory)) {
    693                         return true;
    694                     }
    695                 }
    696                 XmlUtils.nextElement(parser);
    697             }
    698         } catch (Exception e) {
    699             Slog.w(TAG, "Unable to load component info " + info.toString(), e);
    700         } finally {
    701             if (parser != null) parser.close();
    702         }
    703         return false;
    704     }
    705 
    706     private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
    707         ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
    708         List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
    709                 PackageManager.GET_META_DATA);
    710         int count = resolveInfos.size();
    711         for (int i = 0; i < count; i++) {
    712             ResolveInfo resolveInfo = resolveInfos.get(i);
    713             if (packageMatchesLocked(resolveInfo, intent.getAction(), device, null)) {
    714                 matches.add(resolveInfo);
    715             }
    716         }
    717         return matches;
    718     }
    719 
    720     private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
    721             UsbAccessory accessory, Intent intent) {
    722         ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
    723         List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
    724                 PackageManager.GET_META_DATA);
    725         int count = resolveInfos.size();
    726         for (int i = 0; i < count; i++) {
    727             ResolveInfo resolveInfo = resolveInfos.get(i);
    728             if (packageMatchesLocked(resolveInfo, intent.getAction(), null, accessory)) {
    729                 matches.add(resolveInfo);
    730             }
    731         }
    732         return matches;
    733     }
    734 
    735     public void deviceAttached(UsbDevice device) {
    736         final Intent intent = createDeviceAttachedIntent(device);
    737 
    738         // Send broadcast to running activity with registered intent
    739         mUserContext.sendBroadcast(intent);
    740 
    741         if (MtpNotificationManager.shouldShowNotification(mPackageManager, device)) {
    742             // Show notification if the device is MTP storage.
    743             mMtpNotificationManager.showNotification(device);
    744         } else {
    745             resolveActivity(intent, device);
    746         }
    747     }
    748 
    749     private void resolveActivity(Intent intent, UsbDevice device) {
    750         ArrayList<ResolveInfo> matches;
    751         String defaultPackage;
    752         synchronized (mLock) {
    753             matches = getDeviceMatchesLocked(device, intent);
    754             // Launch our default activity directly, if we have one.
    755             // Otherwise we will start the UsbResolverActivity to allow the user to choose.
    756             defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
    757         }
    758 
    759         // Start activity with registered intent
    760         resolveActivity(intent, matches, defaultPackage, device, null);
    761     }
    762 
    763     public void deviceDetached(UsbDevice device) {
    764         // clear temporary permissions for the device
    765         mDevicePermissionMap.remove(device.getDeviceName());
    766 
    767         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
    768         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
    769         if (DEBUG) Slog.d(TAG, "usbDeviceRemoved, sending " + intent);
    770         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    771 
    772         mMtpNotificationManager.hideNotification(device.getDeviceId());
    773     }
    774 
    775     public void accessoryAttached(UsbAccessory accessory) {
    776         Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
    777         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
    778         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    779 
    780         ArrayList<ResolveInfo> matches;
    781         String defaultPackage;
    782         synchronized (mLock) {
    783             matches = getAccessoryMatchesLocked(accessory, intent);
    784             // Launch our default activity directly, if we have one.
    785             // Otherwise we will start the UsbResolverActivity to allow the user to choose.
    786             defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
    787         }
    788 
    789         resolveActivity(intent, matches, defaultPackage, null, accessory);
    790     }
    791 
    792     public void accessoryDetached(UsbAccessory accessory) {
    793         // clear temporary permissions for the accessory
    794         mAccessoryPermissionMap.remove(accessory);
    795 
    796         Intent intent = new Intent(
    797                 UsbManager.ACTION_USB_ACCESSORY_DETACHED);
    798         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
    799         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    800     }
    801 
    802     private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
    803             String defaultPackage, UsbDevice device, UsbAccessory accessory) {
    804         int count = matches.size();
    805 
    806         // don't show the resolver activity if there are no choices available
    807         if (count == 0) {
    808             if (accessory != null) {
    809                 String uri = accessory.getUri();
    810                 if (uri != null && uri.length() > 0) {
    811                     // display URI to user
    812                     // start UsbResolverActivity so user can choose an activity
    813                     Intent dialogIntent = new Intent();
    814                     dialogIntent.setClassName("com.android.systemui",
    815                             "com.android.systemui.usb.UsbAccessoryUriActivity");
    816                     dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    817                     dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
    818                     dialogIntent.putExtra("uri", uri);
    819                     try {
    820                         mUserContext.startActivityAsUser(dialogIntent, mUser);
    821                     } catch (ActivityNotFoundException e) {
    822                         Slog.e(TAG, "unable to start UsbAccessoryUriActivity");
    823                     }
    824                 }
    825             }
    826 
    827             // do nothing
    828             return;
    829         }
    830 
    831         ResolveInfo defaultRI = null;
    832         if (count == 1 && defaultPackage == null) {
    833             // Check to see if our single choice is on the system partition.
    834             // If so, treat it as our default without calling UsbResolverActivity
    835             ResolveInfo rInfo = matches.get(0);
    836             if (rInfo.activityInfo != null &&
    837                     rInfo.activityInfo.applicationInfo != null &&
    838                     (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
    839                 defaultRI = rInfo;
    840             }
    841 
    842             if (mDisablePermissionDialogs) {
    843                 // bypass dialog and launch the only matching activity
    844                 rInfo = matches.get(0);
    845                 if (rInfo.activityInfo != null) {
    846                     defaultPackage = rInfo.activityInfo.packageName;
    847                 }
    848             }
    849         }
    850 
    851         if (defaultRI == null && defaultPackage != null) {
    852             // look for default activity
    853             for (int i = 0; i < count; i++) {
    854                 ResolveInfo rInfo = matches.get(i);
    855                 if (rInfo.activityInfo != null &&
    856                         defaultPackage.equals(rInfo.activityInfo.packageName)) {
    857                     defaultRI = rInfo;
    858                     break;
    859                 }
    860             }
    861         }
    862 
    863         if (defaultRI != null) {
    864             // grant permission for default activity
    865             if (device != null) {
    866                 grantDevicePermission(device, defaultRI.activityInfo.applicationInfo.uid);
    867             } else if (accessory != null) {
    868                 grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid);
    869             }
    870 
    871             // start default activity directly
    872             try {
    873                 intent.setComponent(
    874                         new ComponentName(defaultRI.activityInfo.packageName,
    875                                 defaultRI.activityInfo.name));
    876                 mUserContext.startActivityAsUser(intent, mUser);
    877             } catch (ActivityNotFoundException e) {
    878                 Slog.e(TAG, "startActivity failed", e);
    879             }
    880         } else {
    881             Intent resolverIntent = new Intent();
    882             resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    883 
    884             if (count == 1) {
    885                 // start UsbConfirmActivity if there is only one choice
    886                 resolverIntent.setClassName("com.android.systemui",
    887                         "com.android.systemui.usb.UsbConfirmActivity");
    888                 resolverIntent.putExtra("rinfo", matches.get(0));
    889 
    890                 if (device != null) {
    891                     resolverIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
    892                 } else {
    893                     resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
    894                 }
    895             } else {
    896                 // start UsbResolverActivity so user can choose an activity
    897                 resolverIntent.setClassName("com.android.systemui",
    898                         "com.android.systemui.usb.UsbResolverActivity");
    899                 resolverIntent.putParcelableArrayListExtra("rlist", matches);
    900                 resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
    901             }
    902             try {
    903                 mUserContext.startActivityAsUser(resolverIntent, mUser);
    904             } catch (ActivityNotFoundException e) {
    905                 Slog.e(TAG, "unable to start activity " + resolverIntent);
    906             }
    907         }
    908     }
    909 
    910     private boolean clearCompatibleMatchesLocked(String packageName, DeviceFilter filter) {
    911         boolean changed = false;
    912         for (DeviceFilter test : mDevicePreferenceMap.keySet()) {
    913             if (filter.matches(test)) {
    914                 mDevicePreferenceMap.remove(test);
    915                 changed = true;
    916             }
    917         }
    918         return changed;
    919     }
    920 
    921     private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) {
    922         boolean changed = false;
    923         for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) {
    924             if (filter.matches(test)) {
    925                 mAccessoryPreferenceMap.remove(test);
    926                 changed = true;
    927             }
    928         }
    929         return changed;
    930     }
    931 
    932     private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo,
    933             String metaDataName) {
    934         XmlResourceParser parser = null;
    935         boolean changed = false;
    936 
    937         try {
    938             parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
    939             if (parser == null) return false;
    940 
    941             XmlUtils.nextElement(parser);
    942             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
    943                 String tagName = parser.getName();
    944                 if ("usb-device".equals(tagName)) {
    945                     DeviceFilter filter = DeviceFilter.read(parser);
    946                     if (clearCompatibleMatchesLocked(packageName, filter)) {
    947                         changed = true;
    948                     }
    949                 }
    950                 else if ("usb-accessory".equals(tagName)) {
    951                     AccessoryFilter filter = AccessoryFilter.read(parser);
    952                     if (clearCompatibleMatchesLocked(packageName, filter)) {
    953                         changed = true;
    954                     }
    955                 }
    956                 XmlUtils.nextElement(parser);
    957             }
    958         } catch (Exception e) {
    959             Slog.w(TAG, "Unable to load component info " + aInfo.toString(), e);
    960         } finally {
    961             if (parser != null) parser.close();
    962         }
    963         return changed;
    964     }
    965 
    966     // Check to see if the package supports any USB devices or accessories.
    967     // If so, clear any non-matching preferences for matching devices/accessories.
    968     private void handlePackageUpdate(String packageName) {
    969         synchronized (mLock) {
    970             PackageInfo info;
    971             boolean changed = false;
    972 
    973             try {
    974                 info = mPackageManager.getPackageInfo(packageName,
    975                         PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
    976             } catch (NameNotFoundException e) {
    977                 Slog.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
    978                 return;
    979             }
    980 
    981             ActivityInfo[] activities = info.activities;
    982             if (activities == null) return;
    983             for (int i = 0; i < activities.length; i++) {
    984                 // check for meta-data, both for devices and accessories
    985                 if (handlePackageUpdateLocked(packageName, activities[i],
    986                         UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
    987                     changed = true;
    988                 }
    989                 if (handlePackageUpdateLocked(packageName, activities[i],
    990                         UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
    991                     changed = true;
    992                 }
    993             }
    994 
    995             if (changed) {
    996                 writeSettingsLocked();
    997             }
    998         }
    999     }
   1000 
   1001     public boolean hasPermission(UsbDevice device) {
   1002         synchronized (mLock) {
   1003             int uid = Binder.getCallingUid();
   1004             if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
   1005                 return true;
   1006             }
   1007             SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
   1008             if (uidList == null) {
   1009                 return false;
   1010             }
   1011             return uidList.get(uid);
   1012         }
   1013     }
   1014 
   1015     public boolean hasPermission(UsbAccessory accessory) {
   1016         synchronized (mLock) {
   1017             int uid = Binder.getCallingUid();
   1018             if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
   1019                 return true;
   1020             }
   1021             SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
   1022             if (uidList == null) {
   1023                 return false;
   1024             }
   1025             return uidList.get(uid);
   1026         }
   1027     }
   1028 
   1029     public void checkPermission(UsbDevice device) {
   1030         if (!hasPermission(device)) {
   1031             throw new SecurityException("User has not given permission to device " + device);
   1032         }
   1033     }
   1034 
   1035     public void checkPermission(UsbAccessory accessory) {
   1036         if (!hasPermission(accessory)) {
   1037             throw new SecurityException("User has not given permission to accessory " + accessory);
   1038         }
   1039     }
   1040 
   1041     private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
   1042         final int uid = Binder.getCallingUid();
   1043 
   1044         // compare uid with packageName to foil apps pretending to be someone else
   1045         try {
   1046             ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
   1047             if (aInfo.uid != uid) {
   1048                 throw new IllegalArgumentException("package " + packageName +
   1049                         " does not match caller's uid " + uid);
   1050             }
   1051         } catch (PackageManager.NameNotFoundException e) {
   1052             throw new IllegalArgumentException("package " + packageName + " not found");
   1053         }
   1054 
   1055         long identity = Binder.clearCallingIdentity();
   1056         intent.setClassName("com.android.systemui",
   1057                 "com.android.systemui.usb.UsbPermissionActivity");
   1058         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   1059         intent.putExtra(Intent.EXTRA_INTENT, pi);
   1060         intent.putExtra("package", packageName);
   1061         intent.putExtra(Intent.EXTRA_UID, uid);
   1062         try {
   1063             mUserContext.startActivityAsUser(intent, mUser);
   1064         } catch (ActivityNotFoundException e) {
   1065             Slog.e(TAG, "unable to start UsbPermissionActivity");
   1066         } finally {
   1067             Binder.restoreCallingIdentity(identity);
   1068         }
   1069     }
   1070 
   1071     public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {
   1072       Intent intent = new Intent();
   1073 
   1074         // respond immediately if permission has already been granted
   1075       if (hasPermission(device)) {
   1076             intent.putExtra(UsbManager.EXTRA_DEVICE, device);
   1077             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
   1078             try {
   1079                 pi.send(mUserContext, 0, intent);
   1080             } catch (PendingIntent.CanceledException e) {
   1081                 if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
   1082             }
   1083             return;
   1084         }
   1085 
   1086         // start UsbPermissionActivity so user can choose an activity
   1087         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
   1088         requestPermissionDialog(intent, packageName, pi);
   1089     }
   1090 
   1091     public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
   1092         Intent intent = new Intent();
   1093 
   1094         // respond immediately if permission has already been granted
   1095         if (hasPermission(accessory)) {
   1096             intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
   1097             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
   1098             try {
   1099                 pi.send(mUserContext, 0, intent);
   1100             } catch (PendingIntent.CanceledException e) {
   1101                 if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
   1102             }
   1103             return;
   1104         }
   1105 
   1106         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
   1107         requestPermissionDialog(intent, packageName, pi);
   1108     }
   1109 
   1110     public void setDevicePackage(UsbDevice device, String packageName) {
   1111         DeviceFilter filter = new DeviceFilter(device);
   1112         boolean changed = false;
   1113         synchronized (mLock) {
   1114             if (packageName == null) {
   1115                 changed = (mDevicePreferenceMap.remove(filter) != null);
   1116             } else {
   1117                 changed = !packageName.equals(mDevicePreferenceMap.get(filter));
   1118                 if (changed) {
   1119                     mDevicePreferenceMap.put(filter, packageName);
   1120                 }
   1121             }
   1122             if (changed) {
   1123                 writeSettingsLocked();
   1124             }
   1125         }
   1126     }
   1127 
   1128     public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
   1129         AccessoryFilter filter = new AccessoryFilter(accessory);
   1130         boolean changed = false;
   1131         synchronized (mLock) {
   1132             if (packageName == null) {
   1133                 changed = (mAccessoryPreferenceMap.remove(filter) != null);
   1134             } else {
   1135                 changed = !packageName.equals(mAccessoryPreferenceMap.get(filter));
   1136                 if (changed) {
   1137                     mAccessoryPreferenceMap.put(filter, packageName);
   1138                 }
   1139             }
   1140             if (changed) {
   1141                 writeSettingsLocked();
   1142             }
   1143         }
   1144     }
   1145 
   1146     public void grantDevicePermission(UsbDevice device, int uid) {
   1147         synchronized (mLock) {
   1148             String deviceName = device.getDeviceName();
   1149             SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
   1150             if (uidList == null) {
   1151                 uidList = new SparseBooleanArray(1);
   1152                 mDevicePermissionMap.put(deviceName, uidList);
   1153             }
   1154             uidList.put(uid, true);
   1155         }
   1156     }
   1157 
   1158     public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
   1159         synchronized (mLock) {
   1160             SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
   1161             if (uidList == null) {
   1162                 uidList = new SparseBooleanArray(1);
   1163                 mAccessoryPermissionMap.put(accessory, uidList);
   1164             }
   1165             uidList.put(uid, true);
   1166         }
   1167     }
   1168 
   1169     public boolean hasDefaults(String packageName) {
   1170         synchronized (mLock) {
   1171             if (mDevicePreferenceMap.values().contains(packageName)) return true;
   1172             if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
   1173             return false;
   1174         }
   1175     }
   1176 
   1177     public void clearDefaults(String packageName) {
   1178         synchronized (mLock) {
   1179             if (clearPackageDefaultsLocked(packageName)) {
   1180                 writeSettingsLocked();
   1181             }
   1182         }
   1183     }
   1184 
   1185     private boolean clearPackageDefaultsLocked(String packageName) {
   1186         boolean cleared = false;
   1187         synchronized (mLock) {
   1188             if (mDevicePreferenceMap.containsValue(packageName)) {
   1189                 // make a copy of the key set to avoid ConcurrentModificationException
   1190                 Object[] keys = mDevicePreferenceMap.keySet().toArray();
   1191                 for (int i = 0; i < keys.length; i++) {
   1192                     Object key = keys[i];
   1193                     if (packageName.equals(mDevicePreferenceMap.get(key))) {
   1194                         mDevicePreferenceMap.remove(key);
   1195                         cleared = true;
   1196                     }
   1197                 }
   1198             }
   1199             if (mAccessoryPreferenceMap.containsValue(packageName)) {
   1200                 // make a copy of the key set to avoid ConcurrentModificationException
   1201                 Object[] keys = mAccessoryPreferenceMap.keySet().toArray();
   1202                 for (int i = 0; i < keys.length; i++) {
   1203                     Object key = keys[i];
   1204                     if (packageName.equals(mAccessoryPreferenceMap.get(key))) {
   1205                         mAccessoryPreferenceMap.remove(key);
   1206                         cleared = true;
   1207                     }
   1208                 }
   1209             }
   1210             return cleared;
   1211         }
   1212     }
   1213 
   1214     public void dump(IndentingPrintWriter pw) {
   1215         synchronized (mLock) {
   1216             pw.println("Device permissions:");
   1217             for (String deviceName : mDevicePermissionMap.keySet()) {
   1218                 pw.print("  " + deviceName + ": ");
   1219                 SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
   1220                 int count = uidList.size();
   1221                 for (int i = 0; i < count; i++) {
   1222                     pw.print(Integer.toString(uidList.keyAt(i)) + " ");
   1223                 }
   1224                 pw.println();
   1225             }
   1226             pw.println("Accessory permissions:");
   1227             for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
   1228                 pw.print("  " + accessory + ": ");
   1229                 SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
   1230                 int count = uidList.size();
   1231                 for (int i = 0; i < count; i++) {
   1232                     pw.print(Integer.toString(uidList.keyAt(i)) + " ");
   1233                 }
   1234                 pw.println();
   1235             }
   1236             pw.println("Device preferences:");
   1237             for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
   1238                 pw.println("  " + filter + ": " + mDevicePreferenceMap.get(filter));
   1239             }
   1240             pw.println("Accessory preferences:");
   1241             for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
   1242                 pw.println("  " + filter + ": " + mAccessoryPreferenceMap.get(filter));
   1243             }
   1244         }
   1245     }
   1246 
   1247     private static Intent createDeviceAttachedIntent(UsbDevice device) {
   1248         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
   1249         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
   1250         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   1251         return intent;
   1252     }
   1253 }
   1254