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