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