| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.usb; |
| |
| import android.annotation.NonNull; |
| import android.app.PendingIntent; |
| import android.content.ActivityNotFoundException; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| import android.hardware.usb.UsbAccessory; |
| import android.hardware.usb.UsbDevice; |
| import android.hardware.usb.UsbManager; |
| import android.os.Binder; |
| import android.os.Process; |
| import android.os.UserHandle; |
| import android.util.Slog; |
| import android.util.SparseBooleanArray; |
| import com.android.internal.util.IndentingPrintWriter; |
| |
| import java.util.HashMap; |
| |
| class UsbUserSettingsManager { |
| private static final String TAG = "UsbUserSettingsManager"; |
| private static final boolean DEBUG = false; |
| |
| private final UserHandle mUser; |
| private final boolean mDisablePermissionDialogs; |
| |
| private final Context mUserContext; |
| private final PackageManager mPackageManager; |
| |
| // Temporary mapping USB device name to list of UIDs with permissions for the device |
| private final HashMap<String, SparseBooleanArray> mDevicePermissionMap = |
| new HashMap<String, SparseBooleanArray>(); |
| // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory |
| private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap = |
| new HashMap<UsbAccessory, SparseBooleanArray>(); |
| |
| private final Object mLock = new Object(); |
| |
| public UsbUserSettingsManager(Context context, UserHandle user) { |
| if (DEBUG) Slog.v(TAG, "Creating settings for " + user); |
| |
| try { |
| mUserContext = context.createPackageContextAsUser("android", 0, user); |
| } catch (NameNotFoundException e) { |
| throw new RuntimeException("Missing android package"); |
| } |
| |
| mPackageManager = mUserContext.getPackageManager(); |
| |
| mUser = user; |
| |
| mDisablePermissionDialogs = context.getResources().getBoolean( |
| com.android.internal.R.bool.config_disableUsbPermissionDialogs); |
| } |
| |
| /** |
| * Remove all access permission for a device. |
| * |
| * @param device The device the permissions are for |
| */ |
| void removeDevicePermissions(@NonNull UsbDevice device) { |
| synchronized (mLock) { |
| mDevicePermissionMap.remove(device.getDeviceName()); |
| } |
| } |
| |
| /** |
| * Remove all access permission for a accessory. |
| * |
| * @param accessory The accessory the permissions are for |
| */ |
| void removeAccessoryPermissions(@NonNull UsbAccessory accessory) { |
| synchronized (mLock) { |
| mAccessoryPermissionMap.remove(accessory); |
| } |
| } |
| |
| |
| public boolean hasPermission(UsbDevice device) { |
| synchronized (mLock) { |
| int uid = Binder.getCallingUid(); |
| if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { |
| return true; |
| } |
| SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName()); |
| if (uidList == null) { |
| return false; |
| } |
| return uidList.get(uid); |
| } |
| } |
| |
| public boolean hasPermission(UsbAccessory accessory) { |
| synchronized (mLock) { |
| int uid = Binder.getCallingUid(); |
| if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { |
| return true; |
| } |
| SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); |
| if (uidList == null) { |
| return false; |
| } |
| return uidList.get(uid); |
| } |
| } |
| |
| public void checkPermission(UsbDevice device) { |
| if (!hasPermission(device)) { |
| throw new SecurityException("User has not given permission to device " + device); |
| } |
| } |
| |
| public void checkPermission(UsbAccessory accessory) { |
| if (!hasPermission(accessory)) { |
| throw new SecurityException("User has not given permission to accessory " + accessory); |
| } |
| } |
| |
| private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) { |
| final int uid = Binder.getCallingUid(); |
| |
| // compare uid with packageName to foil apps pretending to be someone else |
| try { |
| ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0); |
| if (aInfo.uid != uid) { |
| throw new IllegalArgumentException("package " + packageName + |
| " does not match caller's uid " + uid); |
| } |
| } catch (PackageManager.NameNotFoundException e) { |
| throw new IllegalArgumentException("package " + packageName + " not found"); |
| } |
| |
| long identity = Binder.clearCallingIdentity(); |
| intent.setClassName("com.android.systemui", |
| "com.android.systemui.usb.UsbPermissionActivity"); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| intent.putExtra(Intent.EXTRA_INTENT, pi); |
| intent.putExtra("package", packageName); |
| intent.putExtra(Intent.EXTRA_UID, uid); |
| try { |
| mUserContext.startActivityAsUser(intent, mUser); |
| } catch (ActivityNotFoundException e) { |
| Slog.e(TAG, "unable to start UsbPermissionActivity"); |
| } finally { |
| Binder.restoreCallingIdentity(identity); |
| } |
| } |
| |
| public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) { |
| Intent intent = new Intent(); |
| |
| // respond immediately if permission has already been granted |
| if (hasPermission(device)) { |
| intent.putExtra(UsbManager.EXTRA_DEVICE, device); |
| intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); |
| try { |
| pi.send(mUserContext, 0, intent); |
| } catch (PendingIntent.CanceledException e) { |
| if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled"); |
| } |
| return; |
| } |
| |
| // start UsbPermissionActivity so user can choose an activity |
| intent.putExtra(UsbManager.EXTRA_DEVICE, device); |
| requestPermissionDialog(intent, packageName, pi); |
| } |
| |
| public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) { |
| Intent intent = new Intent(); |
| |
| // respond immediately if permission has already been granted |
| if (hasPermission(accessory)) { |
| intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); |
| intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); |
| try { |
| pi.send(mUserContext, 0, intent); |
| } catch (PendingIntent.CanceledException e) { |
| if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled"); |
| } |
| return; |
| } |
| |
| intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); |
| requestPermissionDialog(intent, packageName, pi); |
| } |
| |
| public void grantDevicePermission(UsbDevice device, int uid) { |
| synchronized (mLock) { |
| String deviceName = device.getDeviceName(); |
| SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName); |
| if (uidList == null) { |
| uidList = new SparseBooleanArray(1); |
| mDevicePermissionMap.put(deviceName, uidList); |
| } |
| uidList.put(uid, true); |
| } |
| } |
| |
| public void grantAccessoryPermission(UsbAccessory accessory, int uid) { |
| synchronized (mLock) { |
| SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); |
| if (uidList == null) { |
| uidList = new SparseBooleanArray(1); |
| mAccessoryPermissionMap.put(accessory, uidList); |
| } |
| uidList.put(uid, true); |
| } |
| } |
| |
| public void dump(IndentingPrintWriter pw) { |
| synchronized (mLock) { |
| pw.println("Device permissions:"); |
| for (String deviceName : mDevicePermissionMap.keySet()) { |
| pw.print(" " + deviceName + ": "); |
| SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName); |
| int count = uidList.size(); |
| for (int i = 0; i < count; i++) { |
| pw.print(Integer.toString(uidList.keyAt(i)) + " "); |
| } |
| pw.println(); |
| } |
| pw.println("Accessory permissions:"); |
| for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) { |
| pw.print(" " + accessory + ": "); |
| SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); |
| int count = uidList.size(); |
| for (int i = 0; i < count; i++) { |
| pw.print(Integer.toString(uidList.keyAt(i)) + " "); |
| } |
| pw.println(); |
| } |
| } |
| } |
| } |