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 android.annotation.NonNull;
20 import android.annotation.UserIdInt;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.UserInfo;
24 import android.hardware.usb.UsbAccessory;
25 import android.hardware.usb.UsbDevice;
26 import android.hardware.usb.UsbManager;
27 import android.os.UserHandle;
28 import android.os.UserManager;
29 import android.service.usb.UsbSettingsManagerProto;
30 import android.util.Slog;
31 import android.util.SparseArray;
32 
33 import com.android.internal.annotations.GuardedBy;
34 import com.android.internal.util.dump.DualDumpOutputStream;
35 
36 /**
37  * Maintains all {@link UsbUserSettingsManager} for all users.
38  */
39 class UsbSettingsManager {
40     private static final String LOG_TAG = UsbSettingsManager.class.getSimpleName();
41     private static final boolean DEBUG = false;
42 
43     /** Context to be used by this module */
44     private final @NonNull Context mContext;
45 
46     /** Map from user id to {@link UsbUserSettingsManager} for the user */
47     @GuardedBy("mSettingsByUser")
48     private final SparseArray<UsbUserSettingsManager> mSettingsByUser = new SparseArray<>();
49 
50     /**
51      * Map from the parent profile's user id to {@link UsbProfileGroupSettingsManager} for the
52      * group.
53      */
54     @GuardedBy("mSettingsByProfileGroup")
55     private final SparseArray<UsbProfileGroupSettingsManager> mSettingsByProfileGroup
56             = new SparseArray<>();
57     private UserManager mUserManager;
58 
UsbSettingsManager(@onNull Context context)59     public UsbSettingsManager(@NonNull Context context) {
60         mContext = context;
61         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
62     }
63 
64     /**
65      * Get the {@link UsbUserSettingsManager} for a user.
66      *
67      * @param userId The id of the user
68      *
69      * @return The settings for the user
70      */
getSettingsForUser(@serIdInt int userId)71     @NonNull UsbUserSettingsManager getSettingsForUser(@UserIdInt int userId) {
72         synchronized (mSettingsByUser) {
73             UsbUserSettingsManager settings = mSettingsByUser.get(userId);
74             if (settings == null) {
75                 settings = new UsbUserSettingsManager(mContext, new UserHandle(userId));
76                 mSettingsByUser.put(userId, settings);
77             }
78             return settings;
79         }
80     }
81 
82     /**
83      * Get the {@link UsbProfileGroupSettingsManager} for a user.
84      *
85      * @param user Any user of the profile group
86      *
87      * @return The settings for the profile group
88      */
getSettingsForProfileGroup(@onNull UserHandle user)89     @NonNull UsbProfileGroupSettingsManager getSettingsForProfileGroup(@NonNull UserHandle user) {
90         UserHandle parentUser;
91 
92         UserInfo parentUserInfo = mUserManager.getProfileParent(user.getIdentifier());
93         if (parentUserInfo != null) {
94             parentUser = parentUserInfo.getUserHandle();
95         } else {
96             parentUser = user;
97         }
98 
99         synchronized (mSettingsByProfileGroup) {
100             UsbProfileGroupSettingsManager settings = mSettingsByProfileGroup.get(
101                     parentUser.getIdentifier());
102             if (settings == null) {
103                 settings = new UsbProfileGroupSettingsManager(mContext, parentUser, this);
104                 mSettingsByProfileGroup.put(parentUser.getIdentifier(), settings);
105             }
106             return settings;
107         }
108     }
109 
110     /**
111      * Remove the settings for a user.
112      *
113      * @param userToRemove The user to remove
114      */
remove(@onNull UserHandle userToRemove)115     void remove(@NonNull UserHandle userToRemove) {
116         synchronized (mSettingsByUser) {
117             mSettingsByUser.remove(userToRemove.getIdentifier());
118         }
119 
120         synchronized (mSettingsByProfileGroup) {
121             if (mSettingsByProfileGroup.indexOfKey(userToRemove.getIdentifier()) >= 0) {
122                 // The user to remove is the parent user of the group. The parent is the last user
123                 // that gets removed. All state will be removed with the user
124                 mSettingsByProfileGroup.remove(userToRemove.getIdentifier());
125             } else {
126                 // We cannot find the parent user of the user that is removed, hence try to remove
127                 // it from all profile groups.
128                 int numProfileGroups = mSettingsByProfileGroup.size();
129                 for (int i = 0; i < numProfileGroups; i++) {
130                     mSettingsByProfileGroup.valueAt(i).removeAllDefaultsForUser(userToRemove);
131                 }
132             }
133         }
134     }
135 
136     /**
137      * Dump all settings of all users.
138      */
dump(@onNull DualDumpOutputStream dump, String idName, long id)139     void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
140         long token = dump.start(idName, id);
141 
142         synchronized (mSettingsByUser) {
143             int numUsers = mSettingsByUser.size();
144             for (int i = 0; i < numUsers; i++) {
145                 mSettingsByUser.valueAt(i).dump(dump, "user_settings",
146                         UsbSettingsManagerProto.USER_SETTINGS);
147             }
148         }
149 
150         synchronized (mSettingsByProfileGroup) {
151             int numProfileGroups = mSettingsByProfileGroup.size();
152             for (int i = 0; i < numProfileGroups; i++) {
153                 mSettingsByProfileGroup.valueAt(i).dump(dump, "profile_group_settings",
154                         UsbSettingsManagerProto.PROFILE_GROUP_SETTINGS);
155             }
156         }
157 
158         dump.end(token);
159     }
160 
161     /**
162      * Remove temporary access permission and broadcast that a device was removed.
163      *
164      * @param device The device that is removed
165      */
usbDeviceRemoved(@onNull UsbDevice device)166     void usbDeviceRemoved(@NonNull UsbDevice device) {
167         synchronized (mSettingsByUser) {
168             for (int i = 0; i < mSettingsByUser.size(); i++) {
169                 // clear temporary permissions for the device
170                 mSettingsByUser.valueAt(i).removeDevicePermissions(device);
171             }
172         }
173 
174         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
175         intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
176         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
177 
178         if (DEBUG) {
179             Slog.d(LOG_TAG, "usbDeviceRemoved, sending " + intent);
180         }
181         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
182     }
183 
184     /**
185      * Remove temporary access permission and broadcast that a accessory was removed.
186      *
187      * @param accessory The accessory that is removed
188      */
usbAccessoryRemoved(@onNull UsbAccessory accessory)189     void usbAccessoryRemoved(@NonNull UsbAccessory accessory) {
190         synchronized (mSettingsByUser) {
191             for (int i = 0; i < mSettingsByUser.size(); i++) {
192                 // clear temporary permissions for the accessory
193                 mSettingsByUser.valueAt(i).removeAccessoryPermissions(accessory);
194             }
195         }
196 
197         Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
198         intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
199         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
200         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
201     }
202 }
203