summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2011-02-28 17:04:23 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-02-28 17:04:23 -0800
commitfae640b174f0a720690bab31a31dfd2693c67c63 (patch)
treee558c98eea382ab59eb1355c6da58456cf530e4e /services
parenta8049111ffdef6b58c32121d4d9d306fa7df3897 (diff)
parent02eb8746de2d60563ec2751a34d20923192e4293 (diff)
downloadframeworks_base-fae640b174f0a720690bab31a31dfd2693c67c63.zip
frameworks_base-fae640b174f0a720690bab31a31dfd2693c67c63.tar.gz
frameworks_base-fae640b174f0a720690bab31a31dfd2693c67c63.tar.bz2
Merge "UsbManager: Enhancements for managing USB devices and accessories"
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/SystemServer.java1
-rw-r--r--services/java/com/android/server/usb/UsbDeviceSettingsManager.java861
-rw-r--r--services/java/com/android/server/usb/UsbResolverActivity.java102
-rw-r--r--services/java/com/android/server/usb/UsbService.java (renamed from services/java/com/android/server/UsbService.java)160
-rw-r--r--services/jni/com_android_server_UsbService.cpp7
5 files changed, 1091 insertions, 40 deletions
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 52c47e1..d160963 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,7 @@
package com.android.server;
import com.android.server.am.ActivityManagerService;
+import com.android.server.usb.UsbService;
import com.android.server.wm.WindowManagerService;
import com.android.internal.app.ShutdownThread;
import com.android.internal.os.BinderInternal;
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
new file mode 100644
index 0000000..21eb7dc
--- /dev/null
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -0,0 +1,861 @@
+/*
+ * 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.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.XmlResourceParser;
+import android.hardware.UsbAccessory;
+import android.hardware.UsbDevice;
+import android.hardware.UsbInterface;
+import android.hardware.UsbManager;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.os.Process;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+class UsbDeviceSettingsManager {
+
+ private static final String TAG = "UsbDeviceSettingsManager";
+ private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
+
+ private final Context mContext;
+
+ // maps UID to user approved USB devices
+ final SparseArray<ArrayList<DeviceFilter>> mDevicePermissionMap =
+ new SparseArray<ArrayList<DeviceFilter>>();
+ // maps UID to user approved USB accessories
+ final SparseArray<ArrayList<AccessoryFilter>> mAccessoryPermissionMap =
+ new SparseArray<ArrayList<AccessoryFilter>>();
+ // Maps DeviceFilter to user preferred application package
+ final HashMap<DeviceFilter, String> mDevicePreferenceMap =
+ new HashMap<DeviceFilter, String>();
+ // Maps DeviceFilter to user preferred application package
+ final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
+ new HashMap<AccessoryFilter, String>();
+
+ // This class is used to describe a USB device.
+ // When used in HashMaps all values must be specified,
+ // but wildcards can be used for any of the fields in
+ // the package meta-data.
+ private static class DeviceFilter {
+ // USB Vendor ID (or -1 for unspecified)
+ public final int mVendorId;
+ // USB Product ID (or -1 for unspecified)
+ public final int mProductId;
+ // USB device or interface class (or -1 for unspecified)
+ public final int mClass;
+ // USB device subclass (or -1 for unspecified)
+ public final int mSubclass;
+ // USB device protocol (or -1 for unspecified)
+ public final int mProtocol;
+
+ public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol) {
+ mVendorId = vid;
+ mProductId = pid;
+ mClass = clasz;
+ mSubclass = subclass;
+ mProtocol = protocol;
+ }
+
+ public DeviceFilter(UsbDevice device) {
+ mVendorId = device.getVendorId();
+ mProductId = device.getProductId();
+ mClass = device.getDeviceClass();
+ mSubclass = device.getDeviceSubclass();
+ mProtocol = device.getDeviceProtocol();
+ }
+
+ public static DeviceFilter read(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int vendorId = -1;
+ int productId = -1;
+ int deviceClass = -1;
+ int deviceSubclass = -1;
+ int deviceProtocol = -1;
+
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ String name = parser.getAttributeName(i);
+ // All attribute values are ints
+ int value = Integer.parseInt(parser.getAttributeValue(i));
+
+ if ("vendor-id".equals(name)) {
+ vendorId = value;
+ } else if ("product-id".equals(name)) {
+ productId = value;
+ } else if ("class".equals(name)) {
+ deviceClass = value;
+ } else if ("subclass".equals(name)) {
+ deviceSubclass = value;
+ } else if ("protocol".equals(name)) {
+ deviceProtocol = value;
+ }
+ }
+ return new DeviceFilter(vendorId, productId,
+ deviceClass, deviceSubclass, deviceProtocol);
+ }
+
+ public void write(XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, "usb-device");
+ if (mVendorId != -1) {
+ serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
+ }
+ if (mProductId != -1) {
+ serializer.attribute(null, "product-id", Integer.toString(mProductId));
+ }
+ if (mClass != -1) {
+ serializer.attribute(null, "class", Integer.toString(mClass));
+ }
+ if (mSubclass != -1) {
+ serializer.attribute(null, "subclass", Integer.toString(mSubclass));
+ }
+ if (mProtocol != -1) {
+ serializer.attribute(null, "protocol", Integer.toString(mProtocol));
+ }
+ serializer.endTag(null, "usb-device");
+ }
+
+ private boolean matches(int clasz, int subclass, int protocol) {
+ return ((mClass == -1 || clasz == mClass) &&
+ (mSubclass == -1 || subclass == mSubclass) &&
+ (mProtocol == -1 || protocol == mProtocol));
+ }
+
+ public boolean matches(UsbDevice device) {
+ if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
+ if (mProductId != -1 && device.getProductId() != mProductId) return false;
+
+ // check device class/subclass/protocol
+ if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
+ device.getDeviceProtocol())) return true;
+
+ // if device doesn't match, check the interfaces
+ int count = device.getInterfaceCount();
+ for (int i = 0; i < count; i++) {
+ UsbInterface intf = device.getInterface(i);
+ if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
+ intf.getInterfaceProtocol())) return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // can't compare if we have wildcard strings
+ if (mVendorId == -1 || mProductId == -1 ||
+ mClass == -1 || mSubclass == -1 || mProtocol == -1) {
+ return false;
+ }
+ if (obj instanceof DeviceFilter) {
+ DeviceFilter filter = (DeviceFilter)obj;
+ return (filter.mVendorId == mVendorId &&
+ filter.mProductId == mProductId &&
+ filter.mClass == mClass &&
+ filter.mSubclass == mSubclass &&
+ filter.mProtocol == mProtocol);
+ }
+ if (obj instanceof UsbDevice) {
+ UsbDevice device = (UsbDevice)obj;
+ return (device.getVendorId() == mVendorId &&
+ device.getProductId() == mProductId &&
+ device.getDeviceClass() == mClass &&
+ device.getDeviceSubclass() == mSubclass &&
+ device.getDeviceProtocol() == mProtocol);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return (((mVendorId << 16) | mProductId) ^
+ ((mClass << 16) | (mSubclass << 8) | mProtocol));
+ }
+
+ @Override
+ public String toString() {
+ return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
+ ",mClass=" + mClass + ",mSubclass=" + mSubclass +
+ ",mProtocol=" + mProtocol + "]";
+ }
+ }
+
+ // This class is used to describe a USB accessory.
+ // When used in HashMaps all values must be specified,
+ // but wildcards can be used for any of the fields in
+ // the package meta-data.
+ private static class AccessoryFilter {
+ // USB accessory manufacturer (or null for unspecified)
+ public final String mManufacturer;
+ // USB accessory model (or null for unspecified)
+ public final String mModel;
+ // USB accessory type (or null for unspecified)
+ public final String mType;
+ // USB accessory version (or null for unspecified)
+ public final String mVersion;
+
+ public AccessoryFilter(String manufacturer, String model, String type, String version) {
+ mManufacturer = manufacturer;
+ mModel = model;
+ mType = type;
+ mVersion = version;
+ }
+
+ public AccessoryFilter(UsbAccessory accessory) {
+ mManufacturer = accessory.getManufacturer();
+ mModel = accessory.getModel();
+ mType = accessory.getType();
+ mVersion = accessory.getVersion();
+ }
+
+ public static AccessoryFilter read(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String manufacturer = null;
+ String model = null;
+ String type = null;
+ String version = null;
+
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+
+ if ("manufacturer".equals(name)) {
+ manufacturer = value;
+ } else if ("model".equals(name)) {
+ model = value;
+ } else if ("type".equals(name)) {
+ type = value;
+ } else if ("version".equals(name)) {
+ version = value;
+ }
+ }
+ return new AccessoryFilter(manufacturer, model, type, version);
+ }
+
+ public void write(XmlSerializer serializer)throws IOException {
+ serializer.startTag(null, "usb-accessory");
+ if (mManufacturer != null) {
+ serializer.attribute(null, "manufacturer", mManufacturer);
+ }
+ if (mModel != null) {
+ serializer.attribute(null, "model", mModel);
+ }
+ if (mType != null) {
+ serializer.attribute(null, "type", mType);
+ }
+ if (mVersion != null) {
+ serializer.attribute(null, "version", mVersion);
+ }
+ serializer.endTag(null, "usb-accessory");
+ }
+
+ public boolean matches(UsbAccessory acc) {
+ if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
+ if (mModel != null && !acc.getModel().equals(mModel)) return false;
+ if (mType != null && !acc.getType().equals(mType)) return false;
+ if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // can't compare if we have wildcard strings
+ if (mManufacturer == null || mModel == null || mType == null || mVersion == null) {
+ return false;
+ }
+ if (obj instanceof AccessoryFilter) {
+ AccessoryFilter filter = (AccessoryFilter)obj;
+ return (mManufacturer.equals(filter.mManufacturer) &&
+ mModel.equals(filter.mModel) &&
+ mType.equals(filter.mType) &&
+ mVersion.equals(filter.mVersion));
+ }
+ if (obj instanceof UsbAccessory) {
+ UsbAccessory accessory = (UsbAccessory)obj;
+ return (mManufacturer.equals(accessory.getManufacturer()) &&
+ mModel.equals(accessory.getModel()) &&
+ mType.equals(accessory.getType()) &&
+ mVersion.equals(accessory.getVersion()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mType == null ? 0 : mType.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()));
+ }
+
+ @Override
+ public String toString() {
+ return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
+ "\", mModel=\"" + mModel +
+ "\", mType=\"" + mType +
+ "\", mVersion=\"" + mVersion + "\"]";
+ }
+ }
+
+ private class MyPackageMonitor extends PackageMonitor {
+ public void onPackageRemoved(String packageName, int uid) {
+ // clear all activity preferences for the package
+ if (clearPackageDefaults(packageName)) {
+ writeSettings();
+ }
+ }
+
+ public void onUidRemoved(int uid) {
+ // clear all permissions for the UID
+ if (clearUidDefaults(uid)) {
+ writeSettings();
+ }
+ }
+ }
+ MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+
+ public UsbDeviceSettingsManager(Context context) {
+ mContext = context;
+ readSettings();
+ mPackageMonitor.register(context, true);
+ }
+
+ private void readDevicePermission(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int uid = -1;
+ ArrayList<DeviceFilter> filters = new ArrayList<DeviceFilter>();
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ if ("uid".equals(parser.getAttributeName(i))) {
+ uid = Integer.parseInt(parser.getAttributeValue(i));
+ break;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ while ("usb-device".equals(parser.getName())) {
+ filters.add(DeviceFilter.read(parser));
+ XmlUtils.nextElement(parser);
+ }
+ mDevicePermissionMap.put(uid, filters);
+ }
+
+ private void readAccessoryPermission(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int uid = -1;
+ ArrayList<AccessoryFilter> filters = new ArrayList<AccessoryFilter>();
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ if ("uid".equals(parser.getAttributeName(i))) {
+ uid = Integer.parseInt(parser.getAttributeValue(i));
+ break;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ while ("usb-accessory".equals(parser.getName())) {
+ filters.add(AccessoryFilter.read(parser));
+ XmlUtils.nextElement(parser);
+ }
+ mAccessoryPermissionMap.put(uid, filters);
+ }
+
+ private void readPreference(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String packageName = null;
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ if ("package".equals(parser.getAttributeName(i))) {
+ packageName = parser.getAttributeValue(i);
+ break;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ if ("usb-device".equals(parser.getName())) {
+ DeviceFilter filter = DeviceFilter.read(parser);
+ mDevicePreferenceMap.put(filter, packageName);
+ } else if ("usb-accessory".equals(parser.getName())) {
+ AccessoryFilter filter = AccessoryFilter.read(parser);
+ mAccessoryPreferenceMap.put(filter, packageName);
+ }
+ XmlUtils.nextElement(parser);
+ }
+
+ private void readSettings() {
+ FileInputStream stream = null;
+ try {
+ stream = new FileInputStream(sSettingsFile);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ String tagName = parser.getName();
+ if ("device-permission".equals(tagName)) {
+ readDevicePermission(parser);
+ } else if ("accessory-permission".equals(tagName)) {
+ readAccessoryPermission(parser);
+ } else if ("preference".equals(tagName)) {
+ readPreference(parser);
+ } else {
+ XmlUtils.nextElement(parser);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "settings file not found");
+ } catch (Exception e) {
+ Log.e(TAG, "error reading settings file, deleting to start fresh", e);
+ sSettingsFile.delete();
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void writeSettings() {
+ FileOutputStream fos = null;
+ try {
+ FileOutputStream fstr = new FileOutputStream(sSettingsFile);
+ Log.d(TAG, "writing settings to " + fstr);
+ BufferedOutputStream str = new BufferedOutputStream(fstr);
+ FastXmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startTag(null, "settings");
+
+ int count = mDevicePermissionMap.size();
+ for (int i = 0; i < count; i++) {
+ int uid = mDevicePermissionMap.keyAt(i);
+ ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
+ serializer.startTag(null, "device-permission");
+ serializer.attribute(null, "uid", Integer.toString(uid));
+ int filterCount = filters.size();
+ for (int j = 0; j < filterCount; j++) {
+ filters.get(j).write(serializer);
+ }
+ serializer.endTag(null, "device-permission");
+ }
+
+ count = mAccessoryPermissionMap.size();
+ for (int i = 0; i < count; i++) {
+ int uid = mAccessoryPermissionMap.keyAt(i);
+ ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
+ serializer.startTag(null, "accessory-permission");
+ serializer.attribute(null, "uid", Integer.toString(uid));
+ int filterCount = filters.size();
+ for (int j = 0; j < filterCount; j++) {
+ filters.get(j).write(serializer);
+ }
+ serializer.endTag(null, "accessory-permission");
+ }
+
+ for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
+ serializer.startTag(null, "preference");
+ serializer.attribute(null, "package", mDevicePreferenceMap.get(filter));
+ filter.write(serializer);
+ serializer.endTag(null, "preference");
+ }
+
+ for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
+ serializer.startTag(null, "preference");
+ serializer.attribute(null, "package", mAccessoryPreferenceMap.get(filter));
+ filter.write(serializer);
+ serializer.endTag(null, "preference");
+ }
+
+ serializer.endTag(null, "settings");
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+ } catch (Exception e) {
+ Log.e(TAG, "error writing settings file, deleting to start fresh", e);
+ sSettingsFile.delete();
+ }
+ }
+
+ // Checks to see if a package matches a device or accessory.
+ // Only one of device and accessory should be non-null.
+ private boolean packageMatches(ResolveInfo info, String metaDataName,
+ UsbDevice device, UsbAccessory accessory) {
+ ActivityInfo ai = info.activityInfo;
+ PackageManager pm = mContext.getPackageManager();
+
+ XmlResourceParser parser = null;
+ try {
+ parser = ai.loadXmlMetaData(pm, metaDataName);
+ if (parser == null) {
+ Log.w(TAG, "no meta-data for " + info);
+ return false;
+ }
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ String tagName = parser.getName();
+ if (device != null && "usb-device".equals(tagName)) {
+ DeviceFilter filter = DeviceFilter.read(parser);
+ if (filter.matches(device)) {
+ return true;
+ }
+ }
+ else if (accessory != null && "usb-accessory".equals(tagName)) {
+ AccessoryFilter filter = AccessoryFilter.read(parser);
+ if (filter.matches(accessory)) {
+ return true;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load component info " + info.toString(), e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return false;
+ }
+
+ private final ArrayList<ResolveInfo> getDeviceMatches(UsbDevice device, Intent intent) {
+ ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
+ PackageManager.GET_META_DATA);
+ int count = resolveInfos.size();
+ for (int i = 0; i < count; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+ if (packageMatches(resolveInfo, intent.getAction(), device, null)) {
+ matches.add(resolveInfo);
+ }
+ }
+ return matches;
+ }
+
+ private final ArrayList<ResolveInfo> getAccessoryMatches(UsbAccessory accessory, Intent intent) {
+ ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
+ PackageManager.GET_META_DATA);
+ int count = resolveInfos.size();
+ for (int i = 0; i < count; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+ if (packageMatches(resolveInfo, intent.getAction(), null, accessory)) {
+ matches.add(resolveInfo);
+ }
+ }
+ return matches;
+ }
+
+ public void deviceAttached(UsbDevice device) {
+ Intent deviceIntent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+ deviceIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ deviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ ArrayList<ResolveInfo> matches = getDeviceMatches(device, deviceIntent);
+ // Launch our default activity directly, if we have one.
+ // Otherwise we will start the UsbResolverActivity to allow the user to choose.
+ String defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
+ if (defaultPackage != null) {
+ int count = matches.size();
+ for (int i = 0; i < count; i++) {
+ ResolveInfo rInfo = matches.get(i);
+ if (rInfo.activityInfo != null &&
+ defaultPackage.equals(rInfo.activityInfo.packageName)) {
+ try {
+ deviceIntent.setComponent(new ComponentName(
+ defaultPackage, rInfo.activityInfo.name));
+ mContext.startActivity(deviceIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed", e);
+ }
+ return;
+ }
+ }
+ }
+
+ Intent intent = new Intent(mContext, UsbResolverActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ intent.putExtra(Intent.EXTRA_INTENT, deviceIntent);
+ intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS,
+ matches);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "unable to start UsbResolverActivity");
+ }
+ }
+
+ public void deviceDetached(UsbDevice device) {
+ Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
+ intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ Log.d(TAG, "usbDeviceRemoved, sending " + intent);
+ mContext.sendBroadcast(intent);
+ }
+
+ public void accessoryAttached(UsbAccessory accessory) {
+ Intent accessoryIntent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+ accessoryIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ accessoryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ ArrayList<ResolveInfo> matches = getAccessoryMatches(accessory, accessoryIntent);
+ // Launch our default activity directly, if we have one.
+ // Otherwise we will start the UsbResolverActivity to allow the user to choose.
+ String defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
+ if (defaultPackage != null) {
+ int count = matches.size();
+ for (int i = 0; i < count; i++) {
+ ResolveInfo rInfo = matches.get(i);
+ if (rInfo.activityInfo != null &&
+ defaultPackage.equals(rInfo.activityInfo.packageName)) {
+ try {
+ accessoryIntent.setComponent(new ComponentName(
+ defaultPackage, rInfo.activityInfo.name));
+ mContext.startActivity(accessoryIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed", e);
+ }
+ return;
+ }
+ }
+ }
+
+ Intent intent = new Intent(mContext, UsbResolverActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ intent.putExtra(Intent.EXTRA_INTENT, accessoryIntent);
+ intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS,
+ matches);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "unable to start UsbResolverActivity");
+ }
+ }
+
+ public void accessoryDetached(UsbAccessory accessory) {
+ Intent intent = new Intent(
+ UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ mContext.sendBroadcast(intent);
+ }
+
+ public void checkPermission(UsbDevice device) {
+ if (device == null) return;
+ ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(Binder.getCallingUid());
+ if (filterList != null) {
+ int count = filterList.size();
+ for (int i = 0; i < count; i++) {
+ DeviceFilter filter = filterList.get(i);
+ if (filter.equals(device)) {
+ // permission allowed
+ return;
+ }
+ }
+ }
+ throw new SecurityException("User has not given permission to device " + device);
+ }
+
+ public void checkPermission(UsbAccessory accessory) {
+ if (accessory == null) return;
+ ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(Binder.getCallingUid());
+ if (filterList != null) {
+ int count = filterList.size();
+ for (int i = 0; i < count; i++) {
+ AccessoryFilter filter = filterList.get(i);
+ if (filter.equals(accessory)) {
+ // permission allowed
+ return;
+ }
+ }
+ }
+ throw new SecurityException("User has not given permission to accessory " + accessory);
+ }
+
+ public void setDevicePackage(UsbDevice device, String packageName) {
+ DeviceFilter filter = new DeviceFilter(device);
+ if (packageName == null) {
+ mDevicePreferenceMap.remove(filter);
+ } else {
+ mDevicePreferenceMap.put(filter, packageName);
+ }
+ // FIXME - only if changed
+ writeSettings();
+ }
+
+ public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
+ AccessoryFilter filter = new AccessoryFilter(accessory);
+ if (packageName == null) {
+ mAccessoryPreferenceMap.remove(filter);
+ } else {
+ mAccessoryPreferenceMap.put(filter, packageName);
+ }
+ // FIXME - only if changed
+ writeSettings();
+ }
+
+ public void grantDevicePermission(UsbDevice device, int uid) {
+ ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(uid);
+ if (filterList == null) {
+ filterList = new ArrayList<DeviceFilter>();
+ mDevicePermissionMap.put(uid, filterList);
+ } else {
+ int count = filterList.size();
+ for (int i = 0; i < count; i++) {
+ if (filterList.get(i).equals(device)) return;
+ }
+ }
+ filterList.add(new DeviceFilter(device));
+ writeSettings();
+ }
+
+ public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
+ ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(uid);
+ if (filterList == null) {
+ filterList = new ArrayList<AccessoryFilter>();
+ mAccessoryPermissionMap.put(uid, filterList);
+ } else {
+ int count = filterList.size();
+ for (int i = 0; i < count; i++) {
+ if (filterList.get(i).equals(accessory)) return;
+ }
+ }
+ filterList.add(new AccessoryFilter(accessory));
+ writeSettings();
+ }
+
+ public boolean hasDefaults(String packageName, int uid) {
+ if (mDevicePermissionMap.get(uid) != null) return true;
+ if (mAccessoryPermissionMap.get(uid) != null) return true;
+ if (mDevicePreferenceMap.values().contains(packageName)) return true;
+ if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
+ return false;
+ }
+
+ public void clearDefaults(String packageName, int uid) {
+ boolean packageCleared = clearPackageDefaults(packageName);
+ boolean uidCleared = clearUidDefaults(uid);
+ if (packageCleared || uidCleared) {
+ writeSettings();
+ }
+ }
+
+ private boolean clearUidDefaults(int uid) {
+ boolean cleared = false;
+ int index = mDevicePermissionMap.indexOfKey(uid);
+ if (index >= 0) {
+ mDevicePermissionMap.removeAt(index);
+ cleared = true;
+ }
+ index = mAccessoryPermissionMap.indexOfKey(uid);
+ if (index >= 0) {
+ mAccessoryPermissionMap.removeAt(index);
+ cleared = true;
+ }
+ return cleared;
+ }
+
+ private boolean clearPackageDefaults(String packageName) {
+ boolean cleared = false;
+ if (mDevicePreferenceMap.containsValue(packageName)) {
+ // make a copy of the key set to avoid ConcurrentModificationException
+ Object[] keys = mDevicePreferenceMap.keySet().toArray();
+ for (int i = 0; i < keys.length; i++) {
+ Object key = keys[i];
+ if (packageName.equals(mDevicePreferenceMap.get(key))) {
+ mDevicePreferenceMap.remove(key);
+ cleared = true;
+ }
+ }
+ }
+ if (mAccessoryPreferenceMap.containsValue(packageName)) {
+ // make a copy of the key set to avoid ConcurrentModificationException
+ Object[] keys = mAccessoryPreferenceMap.keySet().toArray();
+ for (int i = 0; i < keys.length; i++) {
+ Object key = keys[i];
+ if (packageName.equals(mAccessoryPreferenceMap.get(key))) {
+ mAccessoryPreferenceMap.remove(key);
+ cleared = true;
+ }
+ }
+ }
+ return cleared;
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw) {
+ pw.println(" Device permissions:");
+ int count = mDevicePermissionMap.size();
+ for (int i = 0; i < count; i++) {
+ int uid = mDevicePermissionMap.keyAt(i);
+ pw.println(" " + "uid " + uid + ":");
+ ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
+ for (DeviceFilter filter : filters) {
+ pw.println(" " + filter);
+ }
+ }
+ pw.println(" Accessory permissions:");
+ count = mAccessoryPermissionMap.size();
+ for (int i = 0; i < count; i++) {
+ int uid = mAccessoryPermissionMap.keyAt(i);
+ pw.println(" " + "uid " + uid + ":");
+ ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
+ for (AccessoryFilter filter : filters) {
+ pw.println(" " + filter);
+ }
+ }
+ pw.println(" Device preferences:");
+ for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
+ pw.println(" " + filter + ": " + mDevicePreferenceMap.get(filter));
+ }
+ pw.println(" Accessory preferences:");
+ for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
+ pw.println(" " + filter + ": " + mAccessoryPreferenceMap.get(filter));
+ }
+ }
+}
diff --git a/services/java/com/android/server/usb/UsbResolverActivity.java b/services/java/com/android/server/usb/UsbResolverActivity.java
new file mode 100644
index 0000000..1bb3c21
--- /dev/null
+++ b/services/java/com/android/server/usb/UsbResolverActivity.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.android.internal.app.ResolverActivity;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.hardware.IUsbManager;
+import android.hardware.UsbAccessory;
+import android.hardware.UsbDevice;
+import android.hardware.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/* Activity for choosing an application for a USB device or accessory */
+public class UsbResolverActivity extends ResolverActivity {
+ public static final String TAG = "UsbResolverActivity";
+ public static final String EXTRA_RESOLVE_INFOS = "rlist";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Intent intent = getIntent();
+ Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ if (!(targetParcelable instanceof Intent)) {
+ Log.w("UsbResolverActivity", "Target is not an intent: " + targetParcelable);
+ finish();
+ return;
+ }
+ Intent target = (Intent)targetParcelable;
+ ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
+ Log.d(TAG, "rList.size() " + rList.size());
+ CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
+ super.onCreate(savedInstanceState, target, title, null, rList,
+ true, /* Set alwaysUseOption to true to enable "always use this app" checkbox. */
+ true /* Set alwaysChoose to display activity when only one choice is available.
+ This is necessary because this activity is needed for the user to allow
+ the application permission to access the device */
+ );
+ }
+
+ protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
+ try {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ IUsbManager service = IUsbManager.Stub.asInterface(b);
+ int uid = ri.activityInfo.applicationInfo.uid;
+ String action = intent.getAction();
+
+ if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
+ UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ // grant permission for the device
+ service.grantDevicePermission(device, uid);
+ // set or clear default setting
+ if (alwaysCheck) {
+ service.setDevicePackage(device, ri.activityInfo.packageName);
+ } else {
+ service.setDevicePackage(device, null);
+ }
+ } else if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
+ UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(
+ UsbManager.EXTRA_ACCESSORY);
+ // grant permission for the accessory
+ service.grantAccessoryPermission(accessory, uid);
+ // set or clear default setting
+ if (alwaysCheck) {
+ service.setAccessoryPackage(accessory, ri.activityInfo.packageName);
+ } else {
+ service.setAccessoryPackage(accessory, null);
+ }
+ }
+
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed", e);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "onIntentSelected failed", e);
+ }
+ }
+}
diff --git a/services/java/com/android/server/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 2f84713..de4ac03 100644
--- a/services/java/com/android/server/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.usb;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.hardware.IUsbManager;
import android.hardware.UsbAccessory;
import android.hardware.UsbConstants;
@@ -27,6 +28,7 @@ import android.hardware.UsbEndpoint;
import android.hardware.UsbInterface;
import android.hardware.UsbManager;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -38,10 +40,13 @@ import android.util.Log;
import android.util.Slog;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileReader;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* UsbService monitors for changes to USB state.
@@ -50,7 +55,7 @@ import java.util.HashMap;
* Accessory mode is a special case of USB device mode, where the android device is
* connected to a USB host that supports the android accessory protocol.
*/
-class UsbService extends IUsbManager.Stub {
+public class UsbService extends IUsbManager.Stub {
private static final String TAG = UsbService.class.getSimpleName();
private static final boolean LOG = false;
@@ -102,6 +107,7 @@ class UsbService extends IUsbManager.Stub {
private final Context mContext;
private final Object mLock = new Object();
+ private final UsbDeviceSettingsManager mDeviceManager;
/*
* Handles USB function enable/disable events (device mode)
@@ -139,11 +145,9 @@ class UsbService extends IUsbManager.Stub {
if (enteringAccessoryMode) {
String[] strings = nativeGetAccessoryStrings();
if (strings != null) {
- Log.d(TAG, "entering USB accessory mode");
mCurrentAccessory = new UsbAccessory(strings);
- Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
- intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory);
- mContext.sendBroadcast(intent);
+ Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
+ mDeviceManager.accessoryAttached(mCurrentAccessory);
} else {
Log.e(TAG, "nativeGetAccessoryStrings failed");
}
@@ -170,7 +174,7 @@ class UsbService extends IUsbManager.Stub {
mConnected = intState;
// trigger an Intent broadcast
if (mSystemReady) {
- // debounce disconnects
+ // debounce disconnects to avoid problems bringing up USB tethering
update(mConnected == 0);
}
} else if ("usb_configuration".equals(name)) {
@@ -202,6 +206,8 @@ class UsbService extends IUsbManager.Stub {
public UsbService(Context context) {
mContext = context;
+ mDeviceManager = new UsbDeviceSettingsManager(context);
+
mHostBlacklist = context.getResources().getStringArray(
com.android.internal.R.array.config_usbHostBlacklist);
@@ -345,11 +351,7 @@ class UsbService extends IUsbManager.Stub {
UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
deviceClass, deviceSubclass, deviceProtocol, interfaces);
mDevices.put(deviceName, device);
-
- Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
- intent.putExtra(UsbManager.EXTRA_DEVICE, device);
- Log.d(TAG, "usbDeviceAdded, sending " + intent);
- mContext.sendBroadcast(intent);
+ mDeviceManager.deviceAttached(device);
}
}
@@ -358,10 +360,7 @@ class UsbService extends IUsbManager.Stub {
synchronized (mLock) {
UsbDevice device = mDevices.remove(deviceName);
if (device != null) {
- Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
- intent.putExtra(UsbManager.EXTRA_DEVICE, device);
- Log.d(TAG, "usbDeviceRemoved, sending " + intent);
- mContext.sendBroadcast(intent);
+ mDeviceManager.deviceDetached(device);
}
}
}
@@ -377,7 +376,7 @@ class UsbService extends IUsbManager.Stub {
new Thread(null, runnable, "UsbService host thread").start();
}
- void systemReady() {
+ public void systemReady() {
synchronized (mLock) {
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_hasUsbHostSupport)) {
@@ -402,7 +401,6 @@ class UsbService extends IUsbManager.Stub {
/* Returns a list of all currently attached USB devices (host mdoe) */
public void getDeviceList(Bundle devices) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
synchronized (mLock) {
for (String name : mDevices.keySet()) {
devices.putParcelable(name, mDevices.get(name));
@@ -412,28 +410,85 @@ class UsbService extends IUsbManager.Stub {
/* Opens the specified USB device (host mode) */
public ParcelFileDescriptor openDevice(String deviceName) {
- if (isBlackListed(deviceName)) {
- throw new SecurityException("USB device is on a restricted bus");
- }
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
- if (mDevices.get(deviceName) == null) {
- // if it is not in mDevices, it either does not exist or is blacklisted
- throw new IllegalArgumentException(
- "device " + deviceName + " does not exist or is restricted");
+ synchronized (mLock) {
+ if (isBlackListed(deviceName)) {
+ throw new SecurityException("USB device is on a restricted bus");
+ }
+ UsbDevice device = mDevices.get(deviceName);
+ if (device == null) {
+ // if it is not in mDevices, it either does not exist or is blacklisted
+ throw new IllegalArgumentException(
+ "device " + deviceName + " does not exist or is restricted");
+ }
+ mDeviceManager.checkPermission(device);
+ return nativeOpenDevice(deviceName);
}
- return nativeOpenDevice(deviceName);
}
/* returns the currently attached USB accessory (device mode) */
public UsbAccessory getCurrentAccessory() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
- return mCurrentAccessory;
+ synchronized (mLock) {
+ mDeviceManager.checkPermission(mCurrentAccessory);
+ return mCurrentAccessory;
+ }
}
/* opens the currently attached USB accessory (device mode) */
- public ParcelFileDescriptor openAccessory() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
- return nativeOpenAccessory();
+ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+ synchronized (mLock) {
+ if (mCurrentAccessory == null) {
+ throw new IllegalArgumentException("no accessory attached");
+ }
+ if (!mCurrentAccessory.equals(accessory)) {
+ Log.e(TAG, accessory.toString() + " does not match current accessory "
+ + mCurrentAccessory);
+ throw new IllegalArgumentException("accessory not attached");
+ }
+ mDeviceManager.checkPermission(mCurrentAccessory);
+ return nativeOpenAccessory();
+ }
+ }
+
+ public void setDevicePackage(UsbDevice device, String packageName) {
+ synchronized (mLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.setDevicePackage(device, packageName);
+ }
+ }
+
+ public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
+ synchronized (mLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.setAccessoryPackage(accessory, packageName);
+ }
+ }
+
+ public void grantDevicePermission(UsbDevice device, int uid) {
+ synchronized (mLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.grantDevicePermission(device, uid);
+ }
+ }
+
+ public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
+ synchronized (mLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.grantAccessoryPermission(accessory, uid);
+ }
+ }
+
+ public boolean hasDefaults(String packageName, int uid) {
+ synchronized (mLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ return mDeviceManager.hasDefaults(packageName, uid);
+ }
+ }
+
+ public void clearDefaults(String packageName, int uid) {
+ synchronized (mLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.clearDefaults(packageName, uid);
+ }
}
/*
@@ -470,10 +525,7 @@ class UsbService extends IUsbManager.Stub {
}
mAccessoryRestoreFunctions.clear();
- Intent intent = new Intent(
- UsbManager.ACTION_USB_ACCESSORY_DETACHED);
- intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory);
- mContext.sendBroadcast(intent);
+ mDeviceManager.accessoryDetached(mCurrentAccessory);
mCurrentAccessory = null;
// this will cause an immediate reset of the USB bus,
@@ -513,6 +565,42 @@ class UsbService extends IUsbManager.Stub {
}
};
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump UsbManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mLock) {
+ pw.println("USB Manager State:");
+
+ pw.println(" USB Device State:");
+ pw.print(" Enabled Functions: ");
+ for (int i = 0; i < mEnabledFunctions.size(); i++) {
+ pw.print(mEnabledFunctions.get(i) + " ");
+ }
+ pw.println("");
+ pw.print(" Disabled Functions: ");
+ for (int i = 0; i < mDisabledFunctions.size(); i++) {
+ pw.print(mDisabledFunctions.get(i) + " ");
+ }
+ pw.println("");
+ pw.println(" mConnected: " + mConnected + ", mConfiguration: " + mConfiguration);
+
+ pw.println(" USB Host State:");
+ for (String name : mDevices.keySet()) {
+ pw.println(" " + name + ": " + mDevices.get(name));
+ }
+ pw.println(" mCurrentAccessory: " + mCurrentAccessory);
+
+ mDeviceManager.dump(fd, pw);
+ }
+ }
+
// host support
private native void monitorUsbHostBus();
private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
index 192daaf..3c49e54 100644
--- a/services/jni/com_android_server_UsbService.cpp
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -177,7 +177,6 @@ static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strA
buffer[0] = 0;
int length = ioctl(fd, cmd, buffer);
- LOGD("ioctl returned %d", length);
if (buffer[0]) {
jstring obj = env->NewStringUTF(buffer);
env->SetObjectArrayElement(strArray, index, obj);
@@ -236,9 +235,9 @@ static JNINativeMethod method_table[] = {
int register_android_server_UsbService(JNIEnv *env)
{
- jclass clazz = env->FindClass("com/android/server/UsbService");
+ jclass clazz = env->FindClass("com/android/server/usb/UsbService");
if (clazz == NULL) {
- LOGE("Can't find com/android/server/UsbService");
+ LOGE("Can't find com/android/server/usb/UsbService");
return -1;
}
method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIII[I[I)V");
@@ -267,7 +266,7 @@ int register_android_server_UsbService(JNIEnv *env)
LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
"Unable to find constructor for android.os.ParcelFileDescriptor");
- return jniRegisterNativeMethods(env, "com/android/server/UsbService",
+ return jniRegisterNativeMethods(env, "com/android/server/usb/UsbService",
method_table, NELEM(method_table));
}