1 /*
2  * Copyright (C) 2016 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 static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
20 
21 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
22 
23 import android.Manifest;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.app.ActivityManager;
27 import android.content.ActivityNotFoundException;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.pm.ActivityInfo;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.PackageInfo;
34 import android.content.pm.PackageManager;
35 import android.content.pm.PackageManager.NameNotFoundException;
36 import android.content.pm.ResolveInfo;
37 import android.content.pm.UserInfo;
38 import android.content.res.XmlResourceParser;
39 import android.hardware.usb.AccessoryFilter;
40 import android.hardware.usb.DeviceFilter;
41 import android.hardware.usb.UsbAccessory;
42 import android.hardware.usb.UsbDevice;
43 import android.hardware.usb.UsbManager;
44 import android.os.AsyncTask;
45 import android.os.Environment;
46 import android.os.UserHandle;
47 import android.os.UserManager;
48 import android.provider.Settings;
49 import android.service.usb.UsbProfileGroupSettingsManagerProto;
50 import android.service.usb.UsbSettingsAccessoryPreferenceProto;
51 import android.service.usb.UsbSettingsDevicePreferenceProto;
52 import android.service.usb.UserPackageProto;
53 import android.util.ArrayMap;
54 import android.util.ArraySet;
55 import android.util.AtomicFile;
56 import android.util.Log;
57 import android.util.Slog;
58 import android.util.SparseArray;
59 import android.util.SparseIntArray;
60 import android.util.Xml;
61 
62 import com.android.internal.annotations.GuardedBy;
63 import com.android.internal.annotations.Immutable;
64 import com.android.internal.content.PackageMonitor;
65 import com.android.internal.util.XmlUtils;
66 import com.android.internal.util.dump.DualDumpOutputStream;
67 import com.android.modules.utils.TypedXmlPullParser;
68 import com.android.modules.utils.TypedXmlSerializer;
69 import com.android.server.usb.flags.Flags;
70 import com.android.server.utils.EventLogger;
71 
72 import libcore.io.IoUtils;
73 
74 import org.xmlpull.v1.XmlPullParser;
75 import org.xmlpull.v1.XmlPullParserException;
76 
77 import java.io.File;
78 import java.io.FileInputStream;
79 import java.io.FileNotFoundException;
80 import java.io.FileOutputStream;
81 import java.io.IOException;
82 import java.net.ProtocolException;
83 import java.util.ArrayList;
84 import java.util.HashMap;
85 import java.util.Iterator;
86 import java.util.List;
87 import java.util.Map;
88 import java.util.stream.Collectors;
89 
90 public class UsbProfileGroupSettingsManager {
91     /**
92      * <application> level property that an app can specify to restrict any overlaying of
93      * activities when usb device is attached.
94      *
95      *
96      * <p>This should only be set by privileged apps having {@link Manifest.permission#MANAGE_USB}
97      * permission.
98      * @hide
99      */
100     public static final String PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES =
101             "android.app.PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES";
102     private static final String TAG = UsbProfileGroupSettingsManager.class.getSimpleName();
103     private static final boolean DEBUG = false;
104 
105     private static final int DUMPSYS_LOG_BUFFER = 200;
106 
107     /** Legacy settings file, before multi-user */
108     private static final File sSingleUserSettingsFile = new File(
109             "/data/system/usb_device_manager.xml");
110 
111     /** The parent user (main user of the profile group) */
112     private final UserHandle mParentUser;
113 
114     private final AtomicFile mSettingsFile;
115     private final boolean mDisablePermissionDialogs;
116 
117     private final Context mContext;
118 
119     private final PackageManager mPackageManager;
120 
121     private final ActivityManager mActivityManager;
122 
123     private final UserManager mUserManager;
124     private final @NonNull UsbSettingsManager mSettingsManager;
125 
126     /** Maps DeviceFilter to user preferred application package */
127     @GuardedBy("mLock")
128     private final HashMap<DeviceFilter, UserPackage> mDevicePreferenceMap = new HashMap<>();
129 
130     /** Maps DeviceFilter to set of UserPackages not to ask for launch preference anymore */
131     @GuardedBy("mLock")
132     private final ArrayMap<DeviceFilter, ArraySet<UserPackage>> mDevicePreferenceDeniedMap =
133             new ArrayMap<>();
134 
135     /** Maps AccessoryFilter to user preferred application package */
136     @GuardedBy("mLock")
137     private final HashMap<AccessoryFilter, UserPackage> mAccessoryPreferenceMap = new HashMap<>();
138 
139     /** Maps AccessoryFilter to set of UserPackages not to ask for launch preference anymore */
140     @GuardedBy("mLock")
141     private final ArrayMap<AccessoryFilter, ArraySet<UserPackage>> mAccessoryPreferenceDeniedMap =
142             new ArrayMap<>();
143 
144     private final Object mLock = new Object();
145 
146     /**
147      * If a async task to persist the mDevicePreferenceMap and mAccessoryPreferenceMap is currently
148      * scheduled.
149      */
150     @GuardedBy("mLock")
151     private boolean mIsWriteSettingsScheduled;
152 
153     private static EventLogger sEventLogger;
154 
155     /**
156      * A package of a user.
157      */
158     @Immutable
159     private static class UserPackage {
160         /** User */
161         final @NonNull UserHandle user;
162 
163         /** Package name */
164         final @NonNull String packageName;
165 
166         /**
167          * Create a description of a per user package.
168          *
169          * @param packageName The name of the package
170          * @param user The user
171          */
UserPackage(@onNull String packageName, @NonNull UserHandle user)172         private UserPackage(@NonNull String packageName, @NonNull UserHandle user) {
173             this.packageName = packageName;
174             this.user = user;
175         }
176 
177         @Override
equals(Object obj)178         public boolean equals(Object obj) {
179             if (!(obj instanceof UserPackage)) {
180                 return false;
181             } else {
182                 UserPackage other = (UserPackage)obj;
183 
184                 return user.equals(other.user) && packageName.equals(other.packageName);
185             }
186         }
187 
188         @Override
hashCode()189         public int hashCode() {
190             int result = user.hashCode();
191             result = 31 * result + packageName.hashCode();
192             return result;
193         }
194 
195         @Override
toString()196         public String toString() {
197             return user.getIdentifier() + "/" + packageName;
198         }
199 
dump(DualDumpOutputStream dump, String idName, long id)200         public void dump(DualDumpOutputStream dump, String idName, long id) {
201             long token = dump.start(idName, id);
202 
203             dump.write("user_id", UserPackageProto.USER_ID, user.getIdentifier());
204             dump.write("package_name", UserPackageProto.PACKAGE_NAME, packageName);
205 
206             dump.end(token);
207         }
208     }
209 
210     private class MyPackageMonitor extends PackageMonitor {
211         @Override
onPackageAdded(String packageName, int uid)212         public void onPackageAdded(String packageName, int uid) {
213             if (!mUserManager.isSameProfileGroup(mParentUser.getIdentifier(),
214                     UserHandle.getUserId(uid))) {
215                 return;
216             }
217 
218             handlePackageAdded(new UserPackage(packageName, UserHandle.getUserHandleForUid(uid)));
219         }
220 
221         @Override
onPackageRemoved(String packageName, int uid)222         public void onPackageRemoved(String packageName, int uid) {
223             if (!mUserManager.isSameProfileGroup(mParentUser.getIdentifier(),
224                     UserHandle.getUserId(uid))) {
225                 return;
226             }
227 
228             clearDefaults(packageName, UserHandle.getUserHandleForUid(uid));
229         }
230     }
231 
232     MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
233 
234     private final UsbHandlerManager mUsbHandlerManager;
235 
236     private final MtpNotificationManager mMtpNotificationManager;
237 
238     /**
239      * Create new settings manager for a profile group.
240      *
241      * @param context The context of the service
242      * @param user The parent profile
243      * @param settingsManager The settings manager of the service
244      * @param usbResolveActivityManager The resovle activity manager of the service
245      */
UsbProfileGroupSettingsManager(@onNull Context context, @NonNull UserHandle user, @NonNull UsbSettingsManager settingsManager, @NonNull UsbHandlerManager usbResolveActivityManager)246     public UsbProfileGroupSettingsManager(@NonNull Context context, @NonNull UserHandle user,
247             @NonNull UsbSettingsManager settingsManager,
248             @NonNull UsbHandlerManager usbResolveActivityManager) {
249         if (DEBUG) Slog.v(TAG, "Creating settings for " + user);
250 
251         Context parentUserContext;
252         try {
253             parentUserContext = context.createPackageContextAsUser("android", 0, user);
254         } catch (NameNotFoundException e) {
255             throw new RuntimeException("Missing android package");
256         }
257 
258         mContext = context;
259         mPackageManager = context.getPackageManager();
260         mActivityManager = context.getSystemService(ActivityManager.class);
261         mSettingsManager = settingsManager;
262         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
263 
264         mParentUser = user;
265         mSettingsFile = new AtomicFile(new File(
266                 Environment.getUserSystemDirectory(user.getIdentifier()),
267                 "usb_device_manager.xml"), "usb-state");
268 
269         mDisablePermissionDialogs = context.getResources().getBoolean(
270                 com.android.internal.R.bool.config_disableUsbPermissionDialogs);
271 
272         synchronized (mLock) {
273             if (UserHandle.SYSTEM.equals(user)) {
274                 upgradeSingleUserLocked();
275             }
276             readSettingsLocked();
277         }
278 
279         mPackageMonitor.register(context, null, UserHandle.ALL, true);
280         mMtpNotificationManager = new MtpNotificationManager(
281                 parentUserContext,
282                 device -> resolveActivity(createDeviceAttachedIntent(device),
283                         device, false /* showMtpNotification */));
284 
285         mUsbHandlerManager = usbResolveActivityManager;
286 
287         sEventLogger = new EventLogger(DUMPSYS_LOG_BUFFER,
288                 "UsbProfileGroupSettingsManager activity");
289     }
290 
291     /**
292      * Unregister all broadcast receivers. Must be called explicitly before
293      * object deletion.
294      */
unregisterReceivers()295     public void unregisterReceivers() {
296         mPackageMonitor.unregister();
297         mMtpNotificationManager.unregister();
298     }
299 
300     /**
301      * Remove all defaults and denied packages for a user.
302      *
303      * @param userToRemove The user
304      */
removeUser(@onNull UserHandle userToRemove)305     void removeUser(@NonNull UserHandle userToRemove) {
306         synchronized (mLock) {
307             boolean needToPersist = false;
308             Iterator<Map.Entry<DeviceFilter, UserPackage>> devicePreferenceIt = mDevicePreferenceMap
309                     .entrySet().iterator();
310             while (devicePreferenceIt.hasNext()) {
311                 Map.Entry<DeviceFilter, UserPackage> entry = devicePreferenceIt.next();
312 
313                 if (entry.getValue().user.equals(userToRemove)) {
314                     devicePreferenceIt.remove();
315                     needToPersist = true;
316                 }
317             }
318 
319             Iterator<Map.Entry<AccessoryFilter, UserPackage>> accessoryPreferenceIt =
320                     mAccessoryPreferenceMap.entrySet().iterator();
321             while (accessoryPreferenceIt.hasNext()) {
322                 Map.Entry<AccessoryFilter, UserPackage> entry = accessoryPreferenceIt.next();
323 
324                 if (entry.getValue().user.equals(userToRemove)) {
325                     accessoryPreferenceIt.remove();
326                     needToPersist = true;
327                 }
328             }
329 
330             int numEntries = mDevicePreferenceDeniedMap.size();
331             for (int i = 0; i < numEntries; i++) {
332                 ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.valueAt(i);
333                 for (int j = userPackages.size() - 1; j >= 0; j--) {
334                     if (userPackages.valueAt(j).user.equals(userToRemove)) {
335                         userPackages.removeAt(j);
336                         needToPersist = true;
337                     }
338                 }
339             }
340 
341             numEntries = mAccessoryPreferenceDeniedMap.size();
342             for (int i = 0; i < numEntries; i++) {
343                 ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.valueAt(i);
344                 for (int j = userPackages.size() - 1; j >= 0; j--) {
345                     if (userPackages.valueAt(j).user.equals(userToRemove)) {
346                         userPackages.removeAt(j);
347                         needToPersist = true;
348                     }
349                 }
350             }
351 
352             if (needToPersist) {
353                 scheduleWriteSettingsLocked();
354             }
355         }
356     }
357 
readPreference(XmlPullParser parser)358     private void readPreference(XmlPullParser parser)
359             throws IOException, XmlPullParserException {
360         String packageName = null;
361 
362         // If not set, assume it to be the parent profile
363         UserHandle user = mParentUser;
364 
365         int count = parser.getAttributeCount();
366         for (int i = 0; i < count; i++) {
367             if ("package".equals(parser.getAttributeName(i))) {
368                 packageName = parser.getAttributeValue(i);
369             }
370             if ("user".equals(parser.getAttributeName(i))) {
371                 // Might return null if user is not known anymore
372                 user = mUserManager
373                         .getUserForSerialNumber(Integer.parseInt(parser.getAttributeValue(i)));
374             }
375         }
376 
377         XmlUtils.nextElement(parser);
378         if ("usb-device".equals(parser.getName())) {
379             DeviceFilter filter = DeviceFilter.read(parser);
380             if (user != null) {
381                 mDevicePreferenceMap.put(filter, new UserPackage(packageName, user));
382             }
383         } else if ("usb-accessory".equals(parser.getName())) {
384             AccessoryFilter filter = AccessoryFilter.read(parser);
385             if (user != null) {
386                 mAccessoryPreferenceMap.put(filter, new UserPackage(packageName, user));
387             }
388         }
389         XmlUtils.nextElement(parser);
390     }
391 
readPreferenceDeniedList(@onNull XmlPullParser parser)392     private void readPreferenceDeniedList(@NonNull XmlPullParser parser)
393             throws IOException, XmlPullParserException {
394         int outerDepth = parser.getDepth();
395         if (!XmlUtils.nextElementWithin(parser, outerDepth)) {
396             return;
397         }
398 
399         if ("usb-device".equals(parser.getName())) {
400             DeviceFilter filter = DeviceFilter.read(parser);
401             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
402                 if ("user-package".equals(parser.getName())) {
403                     try {
404                         int userId = XmlUtils.readIntAttribute(parser, "user");
405 
406                         String packageName = XmlUtils.readStringAttribute(parser, "package");
407                         if (packageName == null) {
408                             Slog.e(TAG, "Unable to parse package name");
409                         }
410 
411                         ArraySet<UserPackage> set = mDevicePreferenceDeniedMap.get(filter);
412                         if (set == null) {
413                             set = new ArraySet<>();
414                             mDevicePreferenceDeniedMap.put(filter, set);
415                         }
416                         set.add(new UserPackage(packageName, UserHandle.of(userId)));
417                     } catch (ProtocolException e) {
418                         Slog.e(TAG, "Unable to parse user id", e);
419                     }
420                 }
421             }
422         } else if ("usb-accessory".equals(parser.getName())) {
423             AccessoryFilter filter = AccessoryFilter.read(parser);
424 
425             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
426                 if ("user-package".equals(parser.getName())) {
427                     try {
428                         int userId = XmlUtils.readIntAttribute(parser, "user");
429 
430                         String packageName = XmlUtils.readStringAttribute(parser, "package");
431                         if (packageName == null) {
432                             Slog.e(TAG, "Unable to parse package name");
433                         }
434 
435                         ArraySet<UserPackage> set = mAccessoryPreferenceDeniedMap.get(filter);
436                         if (set == null) {
437                             set = new ArraySet<>();
438                             mAccessoryPreferenceDeniedMap.put(filter, set);
439                         }
440                         set.add(new UserPackage(packageName, UserHandle.of(userId)));
441                     } catch (ProtocolException e) {
442                         Slog.e(TAG, "Unable to parse user id", e);
443                     }
444                 }
445             }
446         }
447 
448         while (parser.getDepth() > outerDepth) {
449             parser.nextTag(); // ignore unknown tags
450         }
451     }
452 
453     /**
454      * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
455      * Should only be called by owner.
456      */
457     @GuardedBy("mLock")
upgradeSingleUserLocked()458     private void upgradeSingleUserLocked() {
459         if (sSingleUserSettingsFile.exists()) {
460             mDevicePreferenceMap.clear();
461             mAccessoryPreferenceMap.clear();
462 
463             FileInputStream fis = null;
464             try {
465                 fis = new FileInputStream(sSingleUserSettingsFile);
466                 TypedXmlPullParser parser = Xml.resolvePullParser(fis);
467 
468                 XmlUtils.nextElement(parser);
469                 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
470                     final String tagName = parser.getName();
471                     if ("preference".equals(tagName)) {
472                         readPreference(parser);
473                     } else {
474                         XmlUtils.nextElement(parser);
475                     }
476                 }
477             } catch (IOException | XmlPullParserException e) {
478                 Log.wtf(TAG, "Failed to read single-user settings", e);
479             } finally {
480                 IoUtils.closeQuietly(fis);
481             }
482 
483             scheduleWriteSettingsLocked();
484 
485             // Success or failure, we delete single-user file
486             sSingleUserSettingsFile.delete();
487         }
488     }
489 
490     @GuardedBy("mLock")
readSettingsLocked()491     private void readSettingsLocked() {
492         if (DEBUG) Slog.v(TAG, "readSettingsLocked()");
493 
494         mDevicePreferenceMap.clear();
495         mAccessoryPreferenceMap.clear();
496 
497         FileInputStream stream = null;
498         try {
499             stream = mSettingsFile.openRead();
500             TypedXmlPullParser parser = Xml.resolvePullParser(stream);
501 
502             XmlUtils.nextElement(parser);
503             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
504                 String tagName = parser.getName();
505                 if ("preference".equals(tagName)) {
506                     readPreference(parser);
507                 } else if ("preference-denied-list".equals(tagName)) {
508                     readPreferenceDeniedList(parser);
509                 } else {
510                     XmlUtils.nextElement(parser);
511                 }
512             }
513         } catch (FileNotFoundException e) {
514             if (DEBUG) Slog.d(TAG, "settings file not found");
515         } catch (Exception e) {
516             Slog.e(TAG, "error reading settings file, deleting to start fresh", e);
517             mSettingsFile.delete();
518         } finally {
519             IoUtils.closeQuietly(stream);
520         }
521     }
522 
523     /**
524      * Schedule a async task to persist {@link #mDevicePreferenceMap} and
525      * {@link #mAccessoryPreferenceMap}. If a task is already scheduled but not completed, do
526      * nothing as the currently scheduled one will do the work.
527      * <p>Called with {@link #mLock} held.</p>
528      * <p>In the uncommon case that the system crashes in between the scheduling and the write the
529      * update is lost.</p>
530      */
531     @GuardedBy("mLock")
scheduleWriteSettingsLocked()532     private void scheduleWriteSettingsLocked() {
533         if (mIsWriteSettingsScheduled) {
534             return;
535         } else {
536             mIsWriteSettingsScheduled = true;
537         }
538 
539         AsyncTask.execute(() -> {
540             synchronized (mLock) {
541                 FileOutputStream fos = null;
542                 try {
543                     fos = mSettingsFile.startWrite();
544 
545                     TypedXmlSerializer serializer = Xml.resolveSerializer(fos);
546                     serializer.startDocument(null, true);
547                     serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
548                                     true);
549                     serializer.startTag(null, "settings");
550 
551                     for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
552                         serializer.startTag(null, "preference");
553                         serializer.attribute(null, "package",
554                                 mDevicePreferenceMap.get(filter).packageName);
555                         serializer.attribute(null, "user",
556                                 String.valueOf(getSerial(mDevicePreferenceMap.get(filter).user)));
557                         filter.write(serializer);
558                         serializer.endTag(null, "preference");
559                     }
560 
561                     for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
562                         serializer.startTag(null, "preference");
563                         serializer.attribute(null, "package",
564                                 mAccessoryPreferenceMap.get(filter).packageName);
565                         serializer.attribute(null, "user", String.valueOf(
566                                         getSerial(mAccessoryPreferenceMap.get(filter).user)));
567                         filter.write(serializer);
568                         serializer.endTag(null, "preference");
569                     }
570 
571                     int numEntries = mDevicePreferenceDeniedMap.size();
572                     for (int i = 0; i < numEntries; i++) {
573                         DeviceFilter filter = mDevicePreferenceDeniedMap.keyAt(i);
574                         ArraySet<UserPackage> userPackageSet = mDevicePreferenceDeniedMap
575                                 .valueAt(i);
576                         serializer.startTag(null, "preference-denied-list");
577                         filter.write(serializer);
578 
579                         int numUserPackages = userPackageSet.size();
580                         for (int j = 0; j < numUserPackages; j++) {
581                             UserPackage userPackage = userPackageSet.valueAt(j);
582                             serializer.startTag(null, "user-package");
583                             serializer.attribute(null, "user",
584                                     String.valueOf(getSerial(userPackage.user)));
585                             serializer.attribute(null, "package", userPackage.packageName);
586                             serializer.endTag(null, "user-package");
587                         }
588                         serializer.endTag(null, "preference-denied-list");
589                     }
590 
591                     numEntries = mAccessoryPreferenceDeniedMap.size();
592                     for (int i = 0; i < numEntries; i++) {
593                         AccessoryFilter filter = mAccessoryPreferenceDeniedMap.keyAt(i);
594                         ArraySet<UserPackage> userPackageSet =
595                                 mAccessoryPreferenceDeniedMap.valueAt(i);
596                         serializer.startTag(null, "preference-denied-list");
597                         filter.write(serializer);
598 
599                         int numUserPackages = userPackageSet.size();
600                         for (int j = 0; j < numUserPackages; j++) {
601                             UserPackage userPackage = userPackageSet.valueAt(j);
602                             serializer.startTag(null, "user-package");
603                             serializer.attribute(null, "user",
604                                     String.valueOf(getSerial(userPackage.user)));
605                             serializer.attribute(null, "package", userPackage.packageName);
606                             serializer.endTag(null, "user-package");
607                         }
608                         serializer.endTag(null, "preference-denied-list");
609                     }
610 
611                     serializer.endTag(null, "settings");
612                     serializer.endDocument();
613 
614                     mSettingsFile.finishWrite(fos);
615                 } catch (IOException e) {
616                     Slog.e(TAG, "Failed to write settings", e);
617                     if (fos != null) {
618                         mSettingsFile.failWrite(fos);
619                     }
620                 }
621 
622                 mIsWriteSettingsScheduled = false;
623             }
624         });
625     }
626 
627     /**
628      * Get {@link DeviceFilter} for all devices an activity should be launched for.
629      *
630      * @param pm The package manager used to get the device filter files
631      * @param info The {@link ResolveInfo} for the activity that can handle usb device attached
632      *             events
633      *
634      * @return The list of {@link DeviceFilter} the activity should be called for or {@code null} if
635      *         none
636      */
637     @Nullable
getDeviceFilters(@onNull PackageManager pm, @NonNull ResolveInfo info)638     static ArrayList<DeviceFilter> getDeviceFilters(@NonNull PackageManager pm,
639             @NonNull ResolveInfo info) {
640         ArrayList<DeviceFilter> filters = null;
641         ActivityInfo ai = info.activityInfo;
642 
643         XmlResourceParser parser = null;
644         try {
645             parser = ai.loadXmlMetaData(pm, UsbManager.ACTION_USB_DEVICE_ATTACHED);
646             if (parser == null) {
647                 Slog.w(TAG, "no meta-data for " + info);
648                 return null;
649             }
650 
651             XmlUtils.nextElement(parser);
652             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
653                 String tagName = parser.getName();
654                 if ("usb-device".equals(tagName)) {
655                     if (filters == null) {
656                         filters = new ArrayList<>(1);
657                     }
658                     filters.add(DeviceFilter.read(parser));
659                 }
660                 XmlUtils.nextElement(parser);
661             }
662         } catch (Exception e) {
663             Slog.w(TAG, "Unable to load component info " + info.toString(), e);
664         } finally {
665             if (parser != null) parser.close();
666         }
667         return filters;
668     }
669 
670     /**
671      * Get {@link AccessoryFilter} for all accessories an activity should be launched for.
672      *
673      * @param pm The package manager used to get the accessory filter files
674      * @param info The {@link ResolveInfo} for the activity that can handle usb accessory attached
675      *             events
676      *
677      * @return The list of {@link AccessoryFilter} the activity should be called for or {@code null}
678      *         if none
679      */
getAccessoryFilters(@onNull PackageManager pm, @NonNull ResolveInfo info)680     static @Nullable ArrayList<AccessoryFilter> getAccessoryFilters(@NonNull PackageManager pm,
681             @NonNull ResolveInfo info) {
682         ArrayList<AccessoryFilter> filters = null;
683         ActivityInfo ai = info.activityInfo;
684 
685         XmlResourceParser parser = null;
686         try {
687             parser = ai.loadXmlMetaData(pm, UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
688             if (parser == null) {
689                 Slog.w(TAG, "no meta-data for " + info);
690                 return null;
691             }
692 
693             XmlUtils.nextElement(parser);
694             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
695                 String tagName = parser.getName();
696                 if ("usb-accessory".equals(tagName)) {
697                     if (filters == null) {
698                         filters = new ArrayList<>(1);
699                     }
700                     filters.add(AccessoryFilter.read(parser));
701                 }
702                 XmlUtils.nextElement(parser);
703             }
704         } catch (Exception e) {
705             Slog.w(TAG, "Unable to load component info " + info.toString(), e);
706         } finally {
707             if (parser != null) parser.close();
708         }
709         return filters;
710     }
711 
712     // Checks to see if a package matches a device or accessory.
713     // Only one of device and accessory should be non-null.
packageMatchesLocked(ResolveInfo info, UsbDevice device, UsbAccessory accessory)714     private boolean packageMatchesLocked(ResolveInfo info, UsbDevice device,
715             UsbAccessory accessory) {
716         if (isForwardMatch(info)) {
717             return true;
718         }
719 
720         if (device != null) {
721             ArrayList<DeviceFilter> deviceFilters = getDeviceFilters(mPackageManager, info);
722             if (deviceFilters != null) {
723                 int numDeviceFilters = deviceFilters.size();
724                 for (int i = 0; i < numDeviceFilters; i++) {
725                     if (deviceFilters.get(i).matches(device)) {
726                         return true;
727                     }
728                 }
729             }
730         }
731 
732         if (accessory != null) {
733             ArrayList<AccessoryFilter> accessoryFilters = getAccessoryFilters(mPackageManager,
734                     info);
735             if (accessoryFilters != null) {
736                 int numAccessoryFilters = accessoryFilters.size();
737                 for (int i = 0; i < numAccessoryFilters; i++) {
738                     if (accessoryFilters.get(i).matches(accessory)) {
739                         return true;
740                     }
741                 }
742             }
743         }
744 
745         return false;
746     }
747 
748     /**
749      * Resolve all activities that match an intent for all profiles of this group.
750      *
751      * @param intent The intent to resolve
752      *
753      * @return The {@link ResolveInfo}s for all profiles of the group
754      */
queryIntentActivitiesForAllProfiles( @onNull Intent intent)755     private @NonNull ArrayList<ResolveInfo> queryIntentActivitiesForAllProfiles(
756             @NonNull Intent intent) {
757         List<UserInfo> profiles = mUserManager.getEnabledProfiles(mParentUser.getIdentifier());
758 
759         ArrayList<ResolveInfo> resolveInfos = new ArrayList<>();
760         int numProfiles = profiles.size();
761         for (int i = 0; i < numProfiles; i++) {
762             resolveInfos.addAll(mSettingsManager.getSettingsForUser(profiles.get(i).id)
763                     .queryIntentActivities(intent));
764         }
765 
766         return resolveInfos;
767     }
768 
769     /**
770      * If this match used to forward the intent to another profile?
771      *
772      * @param match The match
773      *
774      * @return {@code true} iff this is such a forward match
775      */
isForwardMatch(@onNull ResolveInfo match)776     private boolean isForwardMatch(@NonNull ResolveInfo match) {
777         return match.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE);
778     }
779 
780     /**
781      * Only return those matches with the highest priority.
782      *
783      * @param matches All matches, some might have lower priority
784      *
785      * @return The matches with the highest priority
786      */
787     @NonNull
preferHighPriority(@onNull ArrayList<ResolveInfo> matches)788     private ArrayList<ResolveInfo> preferHighPriority(@NonNull ArrayList<ResolveInfo> matches) {
789         SparseArray<ArrayList<ResolveInfo>> highestPriorityMatchesByUserId = new SparseArray<>();
790         SparseIntArray highestPriorityByUserId = new SparseIntArray();
791         ArrayList<ResolveInfo> forwardMatches = new ArrayList<>();
792 
793         // Create list of highest priority matches per user in highestPriorityMatchesByUserId
794         int numMatches = matches.size();
795         for (int matchNum = 0; matchNum < numMatches; matchNum++) {
796             ResolveInfo match = matches.get(matchNum);
797 
798             // Unnecessary forward matches are filtered out later, hence collect them all to add
799             // them below
800             if (isForwardMatch(match)) {
801                 forwardMatches.add(match);
802                 continue;
803             }
804 
805             // If this a previously unknown user?
806             if (highestPriorityByUserId.indexOfKey(match.targetUserId) < 0) {
807                 highestPriorityByUserId.put(match.targetUserId, Integer.MIN_VALUE);
808                 highestPriorityMatchesByUserId.put(match.targetUserId, new ArrayList<>());
809             }
810 
811             // Find current highest priority matches for the current user
812             int highestPriority = highestPriorityByUserId.get(match.targetUserId);
813             ArrayList<ResolveInfo> highestPriorityMatches = highestPriorityMatchesByUserId.get(
814                     match.targetUserId);
815 
816             if (match.priority == highestPriority) {
817                 highestPriorityMatches.add(match);
818             } else if (match.priority > highestPriority) {
819                 highestPriorityByUserId.put(match.targetUserId, match.priority);
820 
821                 highestPriorityMatches.clear();
822                 highestPriorityMatches.add(match);
823             }
824         }
825 
826         // Combine all users (+ forward matches) back together. This means that all non-forward
827         // matches have the same priority for a user. Matches for different users might have
828         // different priority.
829         ArrayList<ResolveInfo> combinedMatches = new ArrayList<>(forwardMatches);
830         int numMatchArrays = highestPriorityMatchesByUserId.size();
831         for (int matchArrayNum = 0; matchArrayNum < numMatchArrays; matchArrayNum++) {
832             combinedMatches.addAll(highestPriorityMatchesByUserId.valueAt(matchArrayNum));
833         }
834 
835         return combinedMatches;
836     }
837 
838     /**
839      * If there are no matches for a profile, remove the forward intent to this profile.
840      *
841      * @param rawMatches The matches that contain all forward intents
842      *
843      * @return The matches with the unnecessary forward intents removed
844      */
removeForwardIntentIfNotNeeded( @onNull ArrayList<ResolveInfo> rawMatches)845     @NonNull private ArrayList<ResolveInfo> removeForwardIntentIfNotNeeded(
846             @NonNull ArrayList<ResolveInfo> rawMatches) {
847         final int numRawMatches = rawMatches.size();
848 
849         // The raw matches contain the activities that can be started but also the intents to
850         // forward the intent to the other profile
851         int numParentActivityMatches = 0;
852         int numNonParentActivityMatches = 0;
853         for (int i = 0; i < numRawMatches; i++) {
854             final ResolveInfo rawMatch = rawMatches.get(i);
855             if (!isForwardMatch(rawMatch)) {
856                 if (UserHandle.getUserHandleForUid(
857                         rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) {
858                     numParentActivityMatches++;
859                 } else {
860                     numNonParentActivityMatches++;
861                 }
862             }
863         }
864 
865         // If only one profile has activity matches, we need to remove all switch intents
866         if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) {
867             ArrayList<ResolveInfo> matches = new ArrayList<>(
868                     numParentActivityMatches + numNonParentActivityMatches);
869 
870             for (int i = 0; i < numRawMatches; i++) {
871                 ResolveInfo rawMatch = rawMatches.get(i);
872                 if (!isForwardMatch(rawMatch)) {
873                     matches.add(rawMatch);
874                 }
875             }
876             return matches;
877 
878         } else {
879             return rawMatches;
880         }
881     }
882 
getDeviceMatchesLocked(UsbDevice device, Intent intent)883     private ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
884         ArrayList<ResolveInfo> matches = new ArrayList<>();
885         List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent);
886         int count = resolveInfos.size();
887         for (int i = 0; i < count; i++) {
888             ResolveInfo resolveInfo = resolveInfos.get(i);
889             if (packageMatchesLocked(resolveInfo, device, null)) {
890                 matches.add(resolveInfo);
891             }
892         }
893 
894         return removeForwardIntentIfNotNeeded(preferHighPriority(matches));
895     }
896 
getAccessoryMatchesLocked( UsbAccessory accessory, Intent intent)897     private ArrayList<ResolveInfo> getAccessoryMatchesLocked(
898             UsbAccessory accessory, Intent intent) {
899         ArrayList<ResolveInfo> matches = new ArrayList<>();
900         List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent);
901         int count = resolveInfos.size();
902         for (int i = 0; i < count; i++) {
903             ResolveInfo resolveInfo = resolveInfos.get(i);
904             if (packageMatchesLocked(resolveInfo, null, accessory)) {
905                 matches.add(resolveInfo);
906             }
907         }
908 
909         return removeForwardIntentIfNotNeeded(preferHighPriority(matches));
910     }
911 
deviceAttached(UsbDevice device)912     public void deviceAttached(UsbDevice device) {
913         final Intent intent = createDeviceAttachedIntent(device);
914 
915         // Send broadcast to running activities with registered intent
916         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
917 
918         //resolving activities only if there is no foreground activity restricting it.
919         if (!shouldRestrictOverlayActivities()) {
920             resolveActivity(intent, device, true /* showMtpNotification */);
921         }
922     }
923 
resolveActivity(Intent intent, UsbDevice device, boolean showMtpNotification)924     private void resolveActivity(Intent intent, UsbDevice device, boolean showMtpNotification) {
925         final ArrayList<ResolveInfo> matches;
926         final ActivityInfo defaultActivity;
927         synchronized (mLock) {
928             matches = getDeviceMatchesLocked(device, intent);
929             defaultActivity = getDefaultActivityLocked(
930                     matches, mDevicePreferenceMap.get(new DeviceFilter(device)));
931         }
932 
933         if (showMtpNotification && MtpNotificationManager.shouldShowNotification(
934                 mPackageManager, device) && defaultActivity == null) {
935             // Show notification if the device is MTP storage.
936             mMtpNotificationManager.showNotification(device);
937             return;
938         }
939 
940         // Start activity with registered intent
941         resolveActivity(intent, matches, defaultActivity, device, null);
942     }
943 
944     /**
945      * @return true if the user has not finished the setup process or if there are any
946      * foreground applications with MANAGE_USB permission and restrict_usb_overlay_activities
947      * enabled in the manifest file.
948      */
shouldRestrictOverlayActivities()949     private boolean shouldRestrictOverlayActivities() {
950 
951         if (!Flags.allowRestrictionOfOverlayActivities()) return false;
952 
953         if (Settings.Secure.getIntForUser(
954                 mContext.getContentResolver(),
955                 USER_SETUP_COMPLETE,
956                 /* defaultValue= */ 1,
957                 UserHandle.CURRENT.getIdentifier())
958                 == 0) {
959             Slog.d(TAG, "restricting usb overlay activities as setup is not complete");
960             return true;
961         }
962 
963         List<ActivityManager.RunningAppProcessInfo> appProcessInfos = mActivityManager
964                 .getRunningAppProcesses();
965 
966         List<String> filteredAppProcessInfos = new ArrayList<>();
967         boolean shouldRestrictOverlayActivities;
968 
969         //filtering out applications in foreground.
970         for (ActivityManager.RunningAppProcessInfo processInfo : appProcessInfos) {
971             if (processInfo.importance <= ActivityManager
972                     .RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
973                 filteredAppProcessInfos.addAll(List.of(processInfo.pkgList));
974             }
975         }
976 
977         if (DEBUG) Slog.d(TAG, "packages in foreground : " + filteredAppProcessInfos);
978 
979         List<String> packagesHoldingManageUsbPermission =
980                 mPackageManager.getPackagesHoldingPermissions(
981                         new String[]{android.Manifest.permission.MANAGE_USB},
982                         PackageManager.MATCH_SYSTEM_ONLY).stream()
983                         .map(packageInfo -> packageInfo.packageName).collect(Collectors.toList());
984 
985         //retaining only packages that hold the required permission
986         filteredAppProcessInfos.retainAll(packagesHoldingManageUsbPermission);
987 
988         if (DEBUG) {
989             Slog.d(TAG, "packages in foreground with required permission : "
990                     + filteredAppProcessInfos);
991         }
992 
993         shouldRestrictOverlayActivities = filteredAppProcessInfos.stream().anyMatch(pkg -> {
994             try {
995                 boolean restrictUsbOverlayActivitiesForPackage = mPackageManager
996                         .getProperty(PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES, pkg).getBoolean();
997 
998                 if (restrictUsbOverlayActivitiesForPackage) {
999                     Slog.d(TAG, "restricting usb overlay activities as package " + pkg
1000                             + " is in foreground");
1001                 }
1002                 return restrictUsbOverlayActivitiesForPackage;
1003             } catch (NameNotFoundException e) {
1004                 if (DEBUG) {
1005                     Slog.d(TAG, "property PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES "
1006                             + "not present for " + pkg);
1007                 }
1008                 return false;
1009             }
1010         });
1011 
1012         if (!shouldRestrictOverlayActivities) {
1013             Slog.d(TAG, "starting of usb overlay activities");
1014         }
1015         return shouldRestrictOverlayActivities;
1016     }
1017 
deviceAttachedForFixedHandler(UsbDevice device, ComponentName component)1018     public void deviceAttachedForFixedHandler(UsbDevice device, ComponentName component) {
1019         final Intent intent = createDeviceAttachedIntent(device);
1020 
1021         // Send broadcast to running activity with registered intent
1022         mContext.sendBroadcastAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
1023 
1024         ApplicationInfo appInfo;
1025         try {
1026             // Fixed handlers are always for parent user
1027             appInfo = mPackageManager.getApplicationInfoAsUser(component.getPackageName(), 0,
1028                     mParentUser.getIdentifier());
1029         } catch (NameNotFoundException e) {
1030             Slog.e(TAG, "Default USB handling package (" + component.getPackageName()
1031                     + ") not found  for user " + mParentUser);
1032             return;
1033         }
1034 
1035         mSettingsManager.mUsbService.getPermissionsForUser(UserHandle.getUserId(appInfo.uid))
1036                 .grantDevicePermission(device, appInfo.uid);
1037 
1038         Intent activityIntent = new Intent(intent);
1039         activityIntent.setComponent(component);
1040         try {
1041             mContext.startActivityAsUser(activityIntent, mParentUser);
1042         } catch (ActivityNotFoundException e) {
1043             Slog.e(TAG, "unable to start activity " + activityIntent);
1044         }
1045     }
1046 
1047     /**
1048      * Remove notifications for a usb device.
1049      *
1050      * @param device The device the notifications are for.
1051      */
usbDeviceRemoved(@onNull UsbDevice device)1052     void usbDeviceRemoved(@NonNull UsbDevice device) {
1053         mMtpNotificationManager.hideNotification(device.getDeviceId());
1054     }
1055 
accessoryAttached(UsbAccessory accessory)1056     public void accessoryAttached(UsbAccessory accessory) {
1057         Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
1058         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
1059         intent.addFlags(
1060                 Intent.FLAG_ACTIVITY_NEW_TASK |
1061                 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1062 
1063         final ArrayList<ResolveInfo> matches;
1064         final ActivityInfo defaultActivity;
1065         synchronized (mLock) {
1066             matches = getAccessoryMatchesLocked(accessory, intent);
1067             defaultActivity = getDefaultActivityLocked(
1068                     matches, mAccessoryPreferenceMap.get(new AccessoryFilter(accessory)));
1069         }
1070 
1071         sEventLogger.enqueue(new EventLogger.StringEvent("accessoryAttached: " + intent));
1072         resolveActivity(intent, matches, defaultActivity, null, accessory);
1073     }
1074 
1075     /**
1076      * Start the appropriate package when an device/accessory got attached.
1077      *
1078      * @param intent The intent to start the package
1079      * @param matches The available resolutions of the intent
1080      * @param defaultActivity The default activity for the device (if set)
1081      * @param device The device if a device was attached
1082      * @param accessory The accessory if a device was attached
1083      */
resolveActivity(@onNull Intent intent, @NonNull ArrayList<ResolveInfo> matches, @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device, @Nullable UsbAccessory accessory)1084     private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches,
1085             @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device,
1086             @Nullable UsbAccessory accessory) {
1087         // Remove all matches which are on the denied list
1088         ArraySet deniedPackages = null;
1089         if (device != null) {
1090             deniedPackages = mDevicePreferenceDeniedMap.get(new DeviceFilter(device));
1091         } else if (accessory != null) {
1092             deniedPackages = mAccessoryPreferenceDeniedMap.get(new AccessoryFilter(accessory));
1093         }
1094         if (deniedPackages != null) {
1095             for (int i = matches.size() - 1; i >= 0; i--) {
1096                 ResolveInfo match = matches.get(i);
1097                 String packageName = match.activityInfo.packageName;
1098                 UserHandle user = UserHandle
1099                         .getUserHandleForUid(match.activityInfo.applicationInfo.uid);
1100                 if (deniedPackages.contains(new UserPackage(packageName, user))) {
1101                     matches.remove(i);
1102                 }
1103             }
1104         }
1105 
1106         // don't show the resolver activity if there are no choices available
1107         if (matches.size() == 0) {
1108             if (accessory != null) {
1109                 mUsbHandlerManager.showUsbAccessoryUriActivity(accessory, mParentUser);
1110             }
1111             // do nothing
1112             return;
1113         }
1114 
1115         if (defaultActivity != null) {
1116             UsbUserPermissionManager defaultRIUserPermissions =
1117                     mSettingsManager.mUsbService.getPermissionsForUser(
1118                             UserHandle.getUserId(defaultActivity.applicationInfo.uid));
1119             // grant permission for default activity
1120             if (device != null) {
1121                 defaultRIUserPermissions
1122                         .grantDevicePermission(device, defaultActivity.applicationInfo.uid);
1123             } else if (accessory != null) {
1124                 defaultRIUserPermissions.grantAccessoryPermission(accessory,
1125                         defaultActivity.applicationInfo.uid);
1126             }
1127 
1128             // start default activity directly
1129             try {
1130                 intent.setComponent(
1131                         new ComponentName(defaultActivity.packageName, defaultActivity.name));
1132 
1133                 UserHandle user = UserHandle.getUserHandleForUid(
1134                         defaultActivity.applicationInfo.uid);
1135                 mContext.startActivityAsUser(intent, user);
1136             } catch (ActivityNotFoundException e) {
1137                 Slog.e(TAG, "startActivity failed", e);
1138             }
1139         } else {
1140             if (matches.size() == 1) {
1141                 mUsbHandlerManager.confirmUsbHandler(matches.get(0), device, accessory);
1142             } else {
1143                 mUsbHandlerManager.selectUsbHandler(matches, mParentUser, intent);
1144             }
1145         }
1146     }
1147 
1148     /**
1149      * Returns a default activity for matched ResolveInfo.
1150      * @param matches Resolved activities matched with connected device/accesary.
1151      * @param userPackage Default activity choosed by a user before. Should be null if no activity
1152      *     is choosed by a user.
1153      * @return Default activity
1154      */
getDefaultActivityLocked( @onNull ArrayList<ResolveInfo> matches, @Nullable UserPackage userPackage)1155     private @Nullable ActivityInfo getDefaultActivityLocked(
1156             @NonNull ArrayList<ResolveInfo> matches,
1157             @Nullable UserPackage userPackage) {
1158         if (userPackage != null) {
1159             // look for default activity
1160             for (final ResolveInfo info : matches) {
1161                 if (info.activityInfo != null && userPackage.equals(
1162                         new UserPackage(info.activityInfo.packageName,
1163                                 UserHandle.getUserHandleForUid(
1164                                         info.activityInfo.applicationInfo.uid)))) {
1165                     return info.activityInfo;
1166                 }
1167             }
1168         }
1169 
1170         if (matches.size() == 1) {
1171             final ActivityInfo activityInfo = matches.get(0).activityInfo;
1172             if (activityInfo != null) {
1173                 if (mDisablePermissionDialogs) {
1174                     return activityInfo;
1175                 }
1176                 // System apps are considered default unless there are other matches
1177                 if (activityInfo.applicationInfo != null
1178                         && (activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
1179                                 != 0) {
1180                     return activityInfo;
1181                 }
1182             }
1183         }
1184 
1185         return null;
1186     }
1187 
1188     @GuardedBy("mLock")
clearCompatibleMatchesLocked(@onNull UserPackage userPackage, @NonNull DeviceFilter filter)1189     private boolean clearCompatibleMatchesLocked(@NonNull UserPackage userPackage,
1190             @NonNull DeviceFilter filter) {
1191         ArrayList<DeviceFilter> keysToRemove = new ArrayList<>();
1192 
1193         // The keys in mDevicePreferenceMap are filters that match devices very narrowly
1194         for (DeviceFilter device : mDevicePreferenceMap.keySet()) {
1195             if (filter.contains(device)) {
1196                 UserPackage currentMatch = mDevicePreferenceMap.get(device);
1197                 if (!currentMatch.equals(userPackage)) {
1198                     keysToRemove.add(device);
1199                 }
1200             }
1201         }
1202 
1203         if (!keysToRemove.isEmpty()) {
1204             for (DeviceFilter keyToRemove : keysToRemove) {
1205                 mDevicePreferenceMap.remove(keyToRemove);
1206             }
1207         }
1208 
1209         return !keysToRemove.isEmpty();
1210     }
1211 
1212     @GuardedBy("mLock")
clearCompatibleMatchesLocked(@onNull UserPackage userPackage, @NonNull AccessoryFilter filter)1213     private boolean clearCompatibleMatchesLocked(@NonNull UserPackage userPackage,
1214             @NonNull AccessoryFilter filter) {
1215         ArrayList<AccessoryFilter> keysToRemove = new ArrayList<>();
1216 
1217         // The keys in mAccessoryPreferenceMap are filters that match accessories very narrowly
1218         for (AccessoryFilter accessory : mAccessoryPreferenceMap.keySet()) {
1219             if (filter.contains(accessory)) {
1220                 UserPackage currentMatch = mAccessoryPreferenceMap.get(accessory);
1221                 if (!currentMatch.equals(userPackage)) {
1222                     keysToRemove.add(accessory);
1223                 }
1224             }
1225         }
1226 
1227         if (!keysToRemove.isEmpty()) {
1228             for (AccessoryFilter keyToRemove : keysToRemove) {
1229                 mAccessoryPreferenceMap.remove(keyToRemove);
1230             }
1231         }
1232 
1233         return !keysToRemove.isEmpty();
1234     }
1235 
1236     @GuardedBy("mLock")
handlePackageAddedLocked(UserPackage userPackage, ActivityInfo aInfo, String metaDataName)1237     private boolean handlePackageAddedLocked(UserPackage userPackage, ActivityInfo aInfo,
1238             String metaDataName) {
1239         XmlResourceParser parser = null;
1240         boolean changed = false;
1241 
1242         try {
1243             parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
1244             if (parser == null) return false;
1245 
1246             XmlUtils.nextElement(parser);
1247             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
1248                 String tagName = parser.getName();
1249                 if ("usb-device".equals(tagName)) {
1250                     DeviceFilter filter = DeviceFilter.read(parser);
1251                     if (clearCompatibleMatchesLocked(userPackage, filter)) {
1252                         changed = true;
1253                     }
1254                 }
1255                 else if ("usb-accessory".equals(tagName)) {
1256                     AccessoryFilter filter = AccessoryFilter.read(parser);
1257                     if (clearCompatibleMatchesLocked(userPackage, filter)) {
1258                         changed = true;
1259                     }
1260                 }
1261                 XmlUtils.nextElement(parser);
1262             }
1263         } catch (Exception e) {
1264             Slog.w(TAG, "Unable to load component info " + aInfo.toString(), e);
1265         } finally {
1266             if (parser != null) parser.close();
1267         }
1268         return changed;
1269     }
1270 
1271     // Check to see if the package supports any USB devices or accessories.
1272     // If so, clear any preferences for matching devices/accessories.
handlePackageAdded(@onNull UserPackage userPackage)1273     private void handlePackageAdded(@NonNull UserPackage userPackage) {
1274         synchronized (mLock) {
1275             PackageInfo info;
1276             boolean changed = false;
1277 
1278             try {
1279                 info = mPackageManager.getPackageInfoAsUser(userPackage.packageName,
1280                         PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA,
1281                         userPackage.user.getIdentifier());
1282             } catch (NameNotFoundException e) {
1283                 Slog.e(TAG, "handlePackageUpdate could not find package " + userPackage, e);
1284                 return;
1285             }
1286 
1287             ActivityInfo[] activities = info.activities;
1288             if (activities == null) return;
1289             for (int i = 0; i < activities.length; i++) {
1290                 // check for meta-data, both for devices and accessories
1291                 if (handlePackageAddedLocked(userPackage, activities[i],
1292                         UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
1293                     changed = true;
1294                 }
1295 
1296                 if (handlePackageAddedLocked(userPackage, activities[i],
1297                         UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
1298                     changed = true;
1299                 }
1300             }
1301 
1302             if (changed) {
1303                 scheduleWriteSettingsLocked();
1304             }
1305         }
1306     }
1307 
1308     /**
1309      * Get the serial number for a user handle.
1310      *
1311      * @param user The user handle
1312      *
1313      * @return The serial number
1314      */
getSerial(@onNull UserHandle user)1315     private int getSerial(@NonNull UserHandle user) {
1316         return mUserManager.getUserSerialNumber(user.getIdentifier());
1317     }
1318 
1319     /**
1320      * Set a package as default handler for a device.
1321      *
1322      * @param device The device that should be handled by default
1323      * @param packageName The default handler package
1324      * @param user The user the package belongs to
1325      */
setDevicePackage(@onNull UsbDevice device, @Nullable String packageName, @NonNull UserHandle user)1326     void setDevicePackage(@NonNull UsbDevice device, @Nullable String packageName,
1327             @NonNull UserHandle user) {
1328         DeviceFilter filter = new DeviceFilter(device);
1329         boolean changed;
1330         synchronized (mLock) {
1331             if (packageName == null) {
1332                 changed = (mDevicePreferenceMap.remove(filter) != null);
1333             } else {
1334                 UserPackage userPackage = new UserPackage(packageName, user);
1335 
1336                 changed = !userPackage.equals(mDevicePreferenceMap.get(filter));
1337                 if (changed) {
1338                     mDevicePreferenceMap.put(filter, userPackage);
1339                 }
1340             }
1341             if (changed) {
1342                 scheduleWriteSettingsLocked();
1343             }
1344         }
1345     }
1346 
1347     /**
1348      * Add package to the denied for handling a device
1349      *
1350      * @param device the device to add to the denied
1351      * @param packageNames the packages to not become handler
1352      * @param user the user
1353      */
addDevicePackagesToDenied(@onNull UsbDevice device, @NonNull String[] packageNames, @NonNull UserHandle user)1354     void addDevicePackagesToDenied(@NonNull UsbDevice device, @NonNull String[] packageNames,
1355             @NonNull UserHandle user) {
1356         if (packageNames.length == 0) {
1357             return;
1358         }
1359         DeviceFilter filter = new DeviceFilter(device);
1360 
1361         synchronized (mLock) {
1362             ArraySet<UserPackage> userPackages;
1363             if (mDevicePreferenceDeniedMap.containsKey(filter)) {
1364                 userPackages = mDevicePreferenceDeniedMap.get(filter);
1365             } else {
1366                 userPackages = new ArraySet<>();
1367                 mDevicePreferenceDeniedMap.put(filter, userPackages);
1368             }
1369 
1370             boolean shouldWrite = false;
1371             for (String packageName : packageNames) {
1372                 UserPackage userPackage = new UserPackage(packageName, user);
1373                 if (!userPackages.contains(userPackage)) {
1374                     userPackages.add(userPackage);
1375                     shouldWrite = true;
1376                 }
1377             }
1378 
1379             if (shouldWrite) {
1380                 scheduleWriteSettingsLocked();
1381             }
1382         }
1383     }
1384 
1385     /**
1386      * Add package to the denied for handling a accessory
1387      *
1388      * @param accessory the accessory to add to the denied
1389      * @param packageNames the packages to not become handler
1390      * @param user the user
1391      */
addAccessoryPackagesToDenied(@onNull UsbAccessory accessory, @NonNull String[] packageNames, @NonNull UserHandle user)1392     void addAccessoryPackagesToDenied(@NonNull UsbAccessory accessory,
1393             @NonNull String[] packageNames, @NonNull UserHandle user) {
1394         if (packageNames.length == 0) {
1395             return;
1396         }
1397         AccessoryFilter filter = new AccessoryFilter(accessory);
1398 
1399         synchronized (mLock) {
1400             ArraySet<UserPackage> userPackages;
1401             if (mAccessoryPreferenceDeniedMap.containsKey(filter)) {
1402                 userPackages = mAccessoryPreferenceDeniedMap.get(filter);
1403             } else {
1404                 userPackages = new ArraySet<>();
1405                 mAccessoryPreferenceDeniedMap.put(filter, userPackages);
1406             }
1407 
1408             boolean shouldWrite = false;
1409             for (String packageName : packageNames) {
1410                 UserPackage userPackage = new UserPackage(packageName, user);
1411                 if (!userPackages.contains(userPackage)) {
1412                     userPackages.add(userPackage);
1413                     shouldWrite = true;
1414                 }
1415             }
1416 
1417             if (shouldWrite) {
1418                 scheduleWriteSettingsLocked();
1419             }
1420         }
1421     }
1422 
1423     /**
1424      * Remove UserPackage from the denied for handling a device
1425      *
1426      * @param device the device to remove denied packages from
1427      * @param packageName the packages to remove
1428      * @param user the user
1429      */
removeDevicePackagesFromDenied(@onNull UsbDevice device, @NonNull String[] packageNames, @NonNull UserHandle user)1430     void removeDevicePackagesFromDenied(@NonNull UsbDevice device, @NonNull String[] packageNames,
1431             @NonNull UserHandle user) {
1432         DeviceFilter filter = new DeviceFilter(device);
1433 
1434         synchronized (mLock) {
1435             ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.get(filter);
1436 
1437             if (userPackages != null) {
1438                 boolean shouldWrite = false;
1439                 for (String packageName : packageNames) {
1440                     UserPackage userPackage = new UserPackage(packageName, user);
1441 
1442                     if (userPackages.contains(userPackage)) {
1443                         userPackages.remove(userPackage);
1444                         shouldWrite = true;
1445 
1446                         if (userPackages.size() == 0) {
1447                             mDevicePreferenceDeniedMap.remove(filter);
1448                             break;
1449                         }
1450                     }
1451                 }
1452 
1453                 if (shouldWrite) {
1454                     scheduleWriteSettingsLocked();
1455                 }
1456             }
1457         }
1458     }
1459 
1460     /**
1461      * Remove UserPackage from the denied for handling a accessory
1462      *
1463      * @param accessory the accessory to remove denied packages from
1464      * @param packageName the packages to remove
1465      * @param user the user
1466      */
removeAccessoryPackagesFromDenied(@onNull UsbAccessory accessory, @NonNull String[] packageNames, @NonNull UserHandle user)1467     void removeAccessoryPackagesFromDenied(@NonNull UsbAccessory accessory,
1468             @NonNull String[] packageNames, @NonNull UserHandle user) {
1469         AccessoryFilter filter = new AccessoryFilter(accessory);
1470 
1471         synchronized (mLock) {
1472             ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.get(filter);
1473 
1474             if (userPackages != null) {
1475                 boolean shouldWrite = false;
1476                 for (String packageName : packageNames) {
1477                     UserPackage userPackage = new UserPackage(packageName, user);
1478 
1479                     if (userPackages.contains(userPackage)) {
1480                         userPackages.remove(userPackage);
1481                         shouldWrite = true;
1482 
1483                         if (userPackages.size() == 0) {
1484                             mAccessoryPreferenceDeniedMap.remove(filter);
1485                             break;
1486                         }
1487                     }
1488                 }
1489 
1490                 if (shouldWrite) {
1491                     scheduleWriteSettingsLocked();
1492                 }
1493             }
1494         }
1495     }
1496 
1497     /**
1498      * Set a package as default handler for a accessory.
1499      *
1500      * @param accessory The accessory that should be handled by default
1501      * @param packageName The default handler package
1502      * @param user The user the package belongs to
1503      */
setAccessoryPackage(@onNull UsbAccessory accessory, @Nullable String packageName, @NonNull UserHandle user)1504     void setAccessoryPackage(@NonNull UsbAccessory accessory, @Nullable String packageName,
1505             @NonNull UserHandle user) {
1506         AccessoryFilter filter = new AccessoryFilter(accessory);
1507         boolean changed;
1508         synchronized (mLock) {
1509             if (packageName == null) {
1510                 changed = (mAccessoryPreferenceMap.remove(filter) != null);
1511             } else {
1512                 UserPackage userPackage = new UserPackage(packageName, user);
1513 
1514                 changed = !userPackage.equals(mAccessoryPreferenceMap.get(filter));
1515                 if (changed) {
1516                     mAccessoryPreferenceMap.put(filter, userPackage);
1517                 }
1518             }
1519             if (changed) {
1520                 scheduleWriteSettingsLocked();
1521             }
1522         }
1523     }
1524 
1525     /**
1526      * Check if a package has is the default handler for any usb device or accessory.
1527      *
1528      * @param packageName The package name
1529      * @param user The user the package belongs to
1530      *
1531      * @return {@code true} iff the package is default for any usb device or accessory
1532      */
hasDefaults(@onNull String packageName, @NonNull UserHandle user)1533     boolean hasDefaults(@NonNull String packageName, @NonNull UserHandle user) {
1534         UserPackage userPackage = new UserPackage(packageName, user);
1535         synchronized (mLock) {
1536             if (mDevicePreferenceMap.values().contains(userPackage)) return true;
1537             return mAccessoryPreferenceMap.values().contains(userPackage);
1538         }
1539     }
1540 
1541     /**
1542      * Clear defaults for a package from any preference.
1543      *
1544      * @param packageName The package to remove
1545      * @param user The user the package belongs to
1546      */
clearDefaults(@onNull String packageName, @NonNull UserHandle user)1547     void clearDefaults(@NonNull String packageName, @NonNull UserHandle user) {
1548         UserPackage userPackage = new UserPackage(packageName, user);
1549 
1550         synchronized (mLock) {
1551             if (clearPackageDefaultsLocked(userPackage)) {
1552                 scheduleWriteSettingsLocked();
1553             }
1554         }
1555     }
1556 
1557     /**
1558      * Clear defaults for a package from any preference (does not persist).
1559      *
1560      * @param userPackage The package to remove
1561      *
1562      * @return {@code true} iff at least one preference was cleared
1563      */
clearPackageDefaultsLocked(@onNull UserPackage userPackage)1564     private boolean clearPackageDefaultsLocked(@NonNull UserPackage userPackage) {
1565         boolean cleared = false;
1566         synchronized (mLock) {
1567             if (mDevicePreferenceMap.containsValue(userPackage)) {
1568                 // make a copy of the key set to avoid ConcurrentModificationException
1569                 DeviceFilter[] keys = mDevicePreferenceMap.keySet().toArray(new DeviceFilter[0]);
1570                 for (int i = 0; i < keys.length; i++) {
1571                     DeviceFilter key = keys[i];
1572                     if (userPackage.equals(mDevicePreferenceMap.get(key))) {
1573                         mDevicePreferenceMap.remove(key);
1574                         cleared = true;
1575                     }
1576                 }
1577             }
1578             if (mAccessoryPreferenceMap.containsValue(userPackage)) {
1579                 // make a copy of the key set to avoid ConcurrentModificationException
1580                 AccessoryFilter[] keys =
1581                         mAccessoryPreferenceMap.keySet().toArray(new AccessoryFilter[0]);
1582                 for (int i = 0; i < keys.length; i++) {
1583                     AccessoryFilter key = keys[i];
1584                     if (userPackage.equals(mAccessoryPreferenceMap.get(key))) {
1585                         mAccessoryPreferenceMap.remove(key);
1586                         cleared = true;
1587                     }
1588                 }
1589             }
1590             return cleared;
1591         }
1592     }
1593 
dump(@onNull DualDumpOutputStream dump, @NonNull String idName, long id)1594     public void dump(@NonNull DualDumpOutputStream dump, @NonNull String idName, long id) {
1595         long token = dump.start(idName, id);
1596 
1597         synchronized (mLock) {
1598             dump.write("parent_user_id", UsbProfileGroupSettingsManagerProto.PARENT_USER_ID,
1599                     mParentUser.getIdentifier());
1600 
1601             for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
1602                 long devicePrefToken = dump.start("device_preferences",
1603                         UsbProfileGroupSettingsManagerProto.DEVICE_PREFERENCES);
1604 
1605                 filter.dump(dump, "filter", UsbSettingsDevicePreferenceProto.FILTER);
1606 
1607                 mDevicePreferenceMap.get(filter).dump(dump, "user_package",
1608                         UsbSettingsDevicePreferenceProto.USER_PACKAGE);
1609 
1610                 dump.end(devicePrefToken);
1611             }
1612             for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
1613                 long accessoryPrefToken = dump.start("accessory_preferences",
1614                         UsbProfileGroupSettingsManagerProto.ACCESSORY_PREFERENCES);
1615 
1616                 filter.dump(dump, "filter", UsbSettingsAccessoryPreferenceProto.FILTER);
1617 
1618                 mAccessoryPreferenceMap.get(filter).dump(dump, "user_package",
1619                         UsbSettingsAccessoryPreferenceProto.USER_PACKAGE);
1620 
1621                 dump.end(accessoryPrefToken);
1622             }
1623         }
1624 
1625         sEventLogger.dump(new DualOutputStreamDumpSink(dump,
1626                 UsbProfileGroupSettingsManagerProto.INTENT));
1627         dump.end(token);
1628     }
1629 
createDeviceAttachedIntent(UsbDevice device)1630     private static Intent createDeviceAttachedIntent(UsbDevice device) {
1631         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
1632         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
1633         intent.addFlags(
1634                 Intent.FLAG_ACTIVITY_NEW_TASK |
1635                 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1636         return intent;
1637     }
1638 }
1639