USB settings are now isolated per-user, since they revolve around installed packages. User-specific settings are returned based on calling user, or referenced by UserHandle passed to SystemUI. Each settings Context is wrapped as a specific user, so all broadcasts are sent correctly. Upgrades any existing USB settings to OWNER. Physical events, like new devices, are routed to the currently active user. Switch to using AtomicFile when persisting settings. Bug: 7244888 Change-Id: I8a723ad3d55ac1bff99276c5f3a3f5e8f013432f
282 lines
9.9 KiB
Java
282 lines
9.9 KiB
Java
/*
|
|
* Copyright (C) 2010 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 an
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.server.usb;
|
|
|
|
import android.app.PendingIntent;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.pm.PackageManager;
|
|
import android.hardware.usb.IUsbManager;
|
|
import android.hardware.usb.UsbAccessory;
|
|
import android.hardware.usb.UsbDevice;
|
|
import android.os.Bundle;
|
|
import android.os.ParcelFileDescriptor;
|
|
import android.os.UserHandle;
|
|
import android.util.SparseArray;
|
|
|
|
import com.android.internal.util.IndentingPrintWriter;
|
|
|
|
import java.io.File;
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
|
|
/**
|
|
* UsbService manages all USB related state, including both host and device support.
|
|
* Host related events and calls are delegated to UsbHostManager, and device related
|
|
* support is delegated to UsbDeviceManager.
|
|
*/
|
|
public class UsbService extends IUsbManager.Stub {
|
|
private static final String TAG = "UsbService";
|
|
|
|
private final Context mContext;
|
|
|
|
private UsbDeviceManager mDeviceManager;
|
|
private UsbHostManager mHostManager;
|
|
|
|
private final Object mLock = new Object();
|
|
|
|
/** Map from {@link UserHandle} to {@link UsbSettingsManager} */
|
|
// @GuardedBy("mLock")
|
|
private final SparseArray<UsbSettingsManager>
|
|
mSettingsByUser = new SparseArray<UsbSettingsManager>();
|
|
|
|
private UsbSettingsManager getSettingsForUser(int userId) {
|
|
synchronized (mLock) {
|
|
UsbSettingsManager settings = mSettingsByUser.get(userId);
|
|
if (settings == null) {
|
|
settings = new UsbSettingsManager(mContext, new UserHandle(userId));
|
|
mSettingsByUser.put(userId, settings);
|
|
}
|
|
return settings;
|
|
}
|
|
}
|
|
|
|
public UsbService(Context context) {
|
|
mContext = context;
|
|
|
|
final PackageManager pm = mContext.getPackageManager();
|
|
if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
|
|
mHostManager = new UsbHostManager(context);
|
|
}
|
|
if (new File("/sys/class/android_usb").exists()) {
|
|
mDeviceManager = new UsbDeviceManager(context);
|
|
}
|
|
|
|
setCurrentUser(UserHandle.USER_OWNER);
|
|
|
|
final IntentFilter userFilter = new IntentFilter();
|
|
userFilter.addAction(Intent.ACTION_USER_SWITCHED);
|
|
userFilter.addAction(Intent.ACTION_USER_STOPPED);
|
|
mContext.registerReceiver(mUserReceiver, userFilter, null, null);
|
|
}
|
|
|
|
private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
|
|
final String action = intent.getAction();
|
|
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
|
|
setCurrentUser(userId);
|
|
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
|
|
synchronized (mLock) {
|
|
mSettingsByUser.remove(userId);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
private void setCurrentUser(int userId) {
|
|
final UsbSettingsManager userSettings = getSettingsForUser(userId);
|
|
if (mHostManager != null) {
|
|
mHostManager.setCurrentSettings(userSettings);
|
|
}
|
|
if (mDeviceManager != null) {
|
|
mDeviceManager.setCurrentSettings(userSettings);
|
|
}
|
|
}
|
|
|
|
public void systemReady() {
|
|
if (mDeviceManager != null) {
|
|
mDeviceManager.systemReady();
|
|
}
|
|
if (mHostManager != null) {
|
|
mHostManager.systemReady();
|
|
}
|
|
}
|
|
|
|
/* Returns a list of all currently attached USB devices (host mdoe) */
|
|
@Override
|
|
public void getDeviceList(Bundle devices) {
|
|
if (mHostManager != null) {
|
|
mHostManager.getDeviceList(devices);
|
|
}
|
|
}
|
|
|
|
/* Opens the specified USB device (host mode) */
|
|
@Override
|
|
public ParcelFileDescriptor openDevice(String deviceName) {
|
|
if (mHostManager != null) {
|
|
return mHostManager.openDevice(deviceName);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/* returns the currently attached USB accessory (device mode) */
|
|
@Override
|
|
public UsbAccessory getCurrentAccessory() {
|
|
if (mDeviceManager != null) {
|
|
return mDeviceManager.getCurrentAccessory();
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/* opens the currently attached USB accessory (device mode) */
|
|
@Override
|
|
public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
|
|
if (mDeviceManager != null) {
|
|
return mDeviceManager.openAccessory(accessory);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setDevicePackage(UsbDevice device, String packageName, int userId) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
getSettingsForUser(userId).setDevicePackage(device, packageName);
|
|
}
|
|
|
|
@Override
|
|
public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
getSettingsForUser(userId).setAccessoryPackage(accessory, packageName);
|
|
}
|
|
|
|
@Override
|
|
public boolean hasDevicePermission(UsbDevice device) {
|
|
final int userId = UserHandle.getCallingUserId();
|
|
return getSettingsForUser(userId).hasPermission(device);
|
|
}
|
|
|
|
@Override
|
|
public boolean hasAccessoryPermission(UsbAccessory accessory) {
|
|
final int userId = UserHandle.getCallingUserId();
|
|
return getSettingsForUser(userId).hasPermission(accessory);
|
|
}
|
|
|
|
@Override
|
|
public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
|
|
final int userId = UserHandle.getCallingUserId();
|
|
getSettingsForUser(userId).requestPermission(device, packageName, pi);
|
|
}
|
|
|
|
@Override
|
|
public void requestAccessoryPermission(
|
|
UsbAccessory accessory, String packageName, PendingIntent pi) {
|
|
final int userId = UserHandle.getCallingUserId();
|
|
getSettingsForUser(userId).requestPermission(accessory, packageName, pi);
|
|
}
|
|
|
|
@Override
|
|
public void grantDevicePermission(UsbDevice device, int uid) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
final int userId = UserHandle.getUserId(uid);
|
|
getSettingsForUser(userId).grantDevicePermission(device, uid);
|
|
}
|
|
|
|
@Override
|
|
public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
final int userId = UserHandle.getUserId(uid);
|
|
getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
|
|
}
|
|
|
|
@Override
|
|
public boolean hasDefaults(String packageName, int userId) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
return getSettingsForUser(userId).hasDefaults(packageName);
|
|
}
|
|
|
|
@Override
|
|
public void clearDefaults(String packageName, int userId) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
getSettingsForUser(userId).clearDefaults(packageName);
|
|
}
|
|
|
|
@Override
|
|
public void setCurrentFunction(String function, boolean makeDefault) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
if (mDeviceManager != null) {
|
|
mDeviceManager.setCurrentFunctions(function, makeDefault);
|
|
} else {
|
|
throw new IllegalStateException("USB device mode not supported");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setMassStorageBackingFile(String path) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
if (mDeviceManager != null) {
|
|
mDeviceManager.setMassStorageBackingFile(path);
|
|
} else {
|
|
throw new IllegalStateException("USB device mode not supported");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
|
|
}
|
|
|
|
@Override
|
|
public void denyUsbDebugging() {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
|
mDeviceManager.denyUsbDebugging();
|
|
}
|
|
|
|
@Override
|
|
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
|
|
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
|
|
|
|
pw.println("USB Manager State:");
|
|
if (mDeviceManager != null) {
|
|
mDeviceManager.dump(fd, pw);
|
|
}
|
|
if (mHostManager != null) {
|
|
mHostManager.dump(fd, pw);
|
|
}
|
|
|
|
synchronized (mLock) {
|
|
for (int i = 0; i < mSettingsByUser.size(); i++) {
|
|
final int userId = mSettingsByUser.keyAt(i);
|
|
final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
|
|
pw.increaseIndent();
|
|
pw.println("Settings for user " + userId + ":");
|
|
settings.dump(fd, pw);
|
|
pw.decreaseIndent();
|
|
}
|
|
}
|
|
pw.decreaseIndent();
|
|
}
|
|
}
|