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