diff options
| -rw-r--r-- | api/system-current.txt | 30 | ||||
| -rw-r--r-- | core/java/android/hardware/usb/IUsbManager.aidl | 4 | ||||
| -rw-r--r-- | core/java/android/hardware/usb/ParcelableUsbPort.aidl (renamed from core/java/android/hardware/usb/UsbPort.aidl) | 4 | ||||
| -rw-r--r-- | core/java/android/hardware/usb/ParcelableUsbPort.java | 87 | ||||
| -rw-r--r-- | core/java/android/hardware/usb/UsbManager.java | 72 | ||||
| -rw-r--r-- | core/java/android/hardware/usb/UsbPort.java | 186 | ||||
| -rw-r--r-- | core/java/android/hardware/usb/UsbPortStatus.java | 165 | ||||
| -rw-r--r-- | core/java/com/android/internal/usb/DumpUtils.java | 12 | ||||
| -rw-r--r-- | services/usb/java/com/android/server/usb/UsbDeviceManager.java | 35 | ||||
| -rw-r--r-- | services/usb/java/com/android/server/usb/UsbPortManager.java | 56 | ||||
| -rw-r--r-- | services/usb/java/com/android/server/usb/UsbService.java | 54 |
11 files changed, 461 insertions, 244 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index fb9d951fb6dc..4278003f4601 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2534,7 +2534,37 @@ package android.hardware.usb { } public class UsbManager { + method public java.util.List<android.hardware.usb.UsbPort> getPorts(); method public void grantPermission(android.hardware.usb.UsbDevice, java.lang.String); + field public static final java.lang.String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED"; + } + + public final class UsbPort { + method public android.hardware.usb.UsbPortStatus getStatus(); + method public void setRoles(int, int); + } + + public final class UsbPortStatus implements android.os.Parcelable { + method public int describeContents(); + method public int getCurrentDataRole(); + method public int getCurrentMode(); + method public int getCurrentPowerRole(); + method public int getSupportedRoleCombinations(); + method public boolean isConnected(); + method public boolean isRoleCombinationSupported(int, int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbPortStatus> CREATOR; + field public static final int DATA_ROLE_DEVICE = 2; // 0x2 + field public static final int DATA_ROLE_HOST = 1; // 0x1 + field public static final int DATA_ROLE_NONE = 0; // 0x0 + field public static final int MODE_AUDIO_ACCESSORY = 4; // 0x4 + field public static final int MODE_DEBUG_ACCESSORY = 8; // 0x8 + field public static final int MODE_DFP = 2; // 0x2 + field public static final int MODE_NONE = 0; // 0x0 + field public static final int MODE_UFP = 1; // 0x1 + field public static final int POWER_ROLE_NONE = 0; // 0x0 + field public static final int POWER_ROLE_SINK = 2; // 0x2 + field public static final int POWER_ROLE_SOURCE = 1; // 0x1 } } diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index f4e776cdb4b9..edc3f9466efc 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -20,7 +20,7 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbPort; +import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.UsbPortStatus; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -112,7 +112,7 @@ interface IUsbManager ParcelFileDescriptor getControlFd(long function); /* Gets the list of USB ports. */ - UsbPort[] getPorts(); + List<ParcelableUsbPort> getPorts(); /* Gets the status of the specified USB port. */ UsbPortStatus getPortStatus(in String portId); diff --git a/core/java/android/hardware/usb/UsbPort.aidl b/core/java/android/hardware/usb/ParcelableUsbPort.aidl index b7a79202914e..4431551fec92 100644 --- a/core/java/android/hardware/usb/UsbPort.aidl +++ b/core/java/android/hardware/usb/ParcelableUsbPort.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015, The Android Open Source Project + * Copyright (C) 2018, 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. @@ -16,4 +16,4 @@ package android.hardware.usb; -parcelable UsbPort; +parcelable ParcelableUsbPort; diff --git a/core/java/android/hardware/usb/ParcelableUsbPort.java b/core/java/android/hardware/usb/ParcelableUsbPort.java new file mode 100644 index 000000000000..7f7ba96b40f2 --- /dev/null +++ b/core/java/android/hardware/usb/ParcelableUsbPort.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2018 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 android.hardware.usb; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.Immutable; + +/** + * A parcelable wrapper to send UsbPorts over binders. + * + * @hide + */ +@Immutable +public final class ParcelableUsbPort implements Parcelable { + private final @NonNull String mId; + private final int mSupportedModes; + + private ParcelableUsbPort(@NonNull String id, int supportedModes) { + mId = id; + mSupportedModes = supportedModes; + } + + /** + * Create the parcelable version of a {@link UsbPort}. + * + * @param port The port to create a parcealable version of + * + * @return The parcelable version of the port + */ + public static @NonNull ParcelableUsbPort of(@NonNull UsbPort port) { + return new ParcelableUsbPort(port.getId(), port.getSupportedModes()); + } + + /** + * Create a {@link UsbPort} from this object. + * + * @param usbManager A link to the usbManager in the current context + * + * @return The UsbPort for this object + */ + public @NonNull UsbPort getUsbPort(@NonNull UsbManager usbManager) { + return new UsbPort(usbManager, mId, mSupportedModes); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mId); + dest.writeInt(mSupportedModes); + } + + public static final Creator<ParcelableUsbPort> CREATOR = + new Creator<ParcelableUsbPort>() { + @Override + public ParcelableUsbPort createFromParcel(Parcel in) { + String id = in.readString(); + int supportedModes = in.readInt(); + return new ParcelableUsbPort(id, supportedModes); + } + + @Override + public ParcelableUsbPort[] newArray(int size) { + return new ParcelableUsbPort[size]; + } + }; +} diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 41119416e419..601447814952 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -18,6 +18,7 @@ package android.hardware.usb; import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; @@ -39,9 +40,10 @@ import android.os.Process; import android.os.RemoteException; import android.util.Log; -import com.android.internal.util.Preconditions; - +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.StringJoiner; @@ -97,15 +99,11 @@ public class UsbManager { * Broadcast Action: A broadcast for USB port changes. * * This intent is sent when a USB port is added, removed, or changes state. - * <ul> - * <li> {@link #EXTRA_PORT} containing the {@link android.hardware.usb.UsbPort} - * for the port. - * <li> {@link #EXTRA_PORT_STATUS} containing the {@link android.hardware.usb.UsbPortStatus} - * for the port, or null if the port has been removed - * </ul> * * @hide */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED"; @@ -796,34 +794,44 @@ public class UsbManager { * device class (which supports all types of ports despite its name). * </p> * - * @return The list of USB ports, or null if none. + * @return The list of USB ports * * @hide */ - @UnsupportedAppUsage - public UsbPort[] getPorts() { + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_USB) + public @NonNull List<UsbPort> getPorts() { if (mService == null) { - return null; + return Collections.emptyList(); } + + List<ParcelableUsbPort> parcelablePorts; try { - return mService.getPorts(); + parcelablePorts = mService.getPorts(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + + if (parcelablePorts == null) { + return Collections.emptyList(); + } else { + int numPorts = parcelablePorts.size(); + + ArrayList<UsbPort> ports = new ArrayList<>(numPorts); + for (int i = 0; i < numPorts; i++) { + ports.add(parcelablePorts.get(i).getUsbPort(this)); + } + + return ports; + } } /** - * Gets the status of the specified USB port. - * - * @param port The port to query. - * @return The status of the specified USB port, or null if unknown. + * Should only be called by {@link UsbPort#getStatus}. * * @hide */ - @UnsupportedAppUsage - public UsbPortStatus getPortStatus(UsbPort port) { - Preconditions.checkNotNull(port, "port must not be null"); - + UsbPortStatus getPortStatus(UsbPort port) { try { return mService.getPortStatus(port.getId()); } catch (RemoteException e) { @@ -832,29 +840,11 @@ public class UsbManager { } /** - * Sets the desired role combination of the port. - * <p> - * The supported role combinations depend on what is connected to the port and may be - * determined by consulting - * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}. - * </p><p> - * Note: This function is asynchronous and may fail silently without applying - * the requested changes. If this function does cause a status change to occur then - * a {@link #ACTION_USB_PORT_CHANGED} broadcast will be sent. - * </p> - * - * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE} - * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role. - * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST} - * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role. + * Should only be called by {@link UsbPort#setRoles}. * * @hide */ - @UnsupportedAppUsage - public void setPortRoles(UsbPort port, int powerRole, int dataRole) { - Preconditions.checkNotNull(port, "port must not be null"); - UsbPort.checkRoles(powerRole, dataRole); - + void setPortRoles(UsbPort port, int powerRole, int dataRole) { Log.d(TAG, "setPortRoles Package:" + mContext.getPackageName()); try { mService.setPortRoles(port.getId(), powerRole, dataRole); diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java index afdb202211dd..37154e4c81b2 100644 --- a/core/java/android/hardware/usb/UsbPort.java +++ b/core/java/android/hardware/usb/UsbPort.java @@ -16,104 +16,53 @@ package android.hardware.usb; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE; +import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY; +import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY; +import static android.hardware.usb.UsbPortStatus.MODE_DFP; +import static android.hardware.usb.UsbPortStatus.MODE_DUAL; +import static android.hardware.usb.UsbPortStatus.MODE_NONE; +import static android.hardware.usb.UsbPortStatus.MODE_UFP; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.hardware.usb.V1_0.Constants; -import android.os.Parcel; -import android.os.Parcelable; import com.android.internal.util.Preconditions; /** * Represents a physical USB port and describes its characteristics. - * <p> - * This object is immutable. - * </p> * * @hide */ -public final class UsbPort implements Parcelable { +@SystemApi +public final class UsbPort { private final String mId; private final int mSupportedModes; - - public static final int MODE_NONE = Constants.PortMode.NONE; - /** - * Mode bit: This USB port can act as a downstream facing port (host). - * <p> - * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST} - * combination of roles (and possibly others as well). - * </p> - */ - public static final int MODE_DFP = Constants.PortMode.DFP; - - /** - * Mode bit: This USB port can act as an upstream facing port (device). - * <p> - * Implies that the port supports the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE} - * combination of roles (and possibly others as well). - * </p> - */ - public static final int MODE_UFP = Constants.PortMode.UFP; - - /** - * Mode bit: This USB port can act either as an downstream facing port (host) or as - * an upstream facing port (device). - * <p> - * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST} - * combination of roles and the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE} - * combination of roles (and possibly others as well). - * </p> - */ - public static final int MODE_DUAL = Constants.PortMode.DRP; - - /** - * Mode bit: This USB port can support USB Type-C Audio accessory. - */ - public static final int MODE_AUDIO_ACCESSORY = - android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY; - - /** - * Mode bit: This USB port can support USB Type-C debug accessory. - */ - public static final int MODE_DEBUG_ACCESSORY = - android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY; - - /** - * Power role: This USB port does not have a power role. - */ - public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE; - - /** - * Power role: This USB port can act as a source (provide power). - */ - public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE; - - /** - * Power role: This USB port can act as a sink (receive power). - */ - public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK; - - /** - * Power role: This USB port does not have a data role. - */ - public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE; - - /** - * Data role: This USB port can act as a host (access data services). - */ - public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST; - - /** - * Data role: This USB port can act as a device (offer data services). - */ - public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE; + private final UsbManager mUsbManager; private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES; + /** * Points to the first power role in the IUsb HAL. */ private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE; /** @hide */ - public UsbPort(String id, int supportedModes) { + public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes) { + Preconditions.checkNotNull(id); + Preconditions.checkFlagsArgument(supportedModes, + MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY); + + mUsbManager = usbManager; mId = id; mSupportedModes = supportedModes; } @@ -122,6 +71,8 @@ public final class UsbPort implements Parcelable { * Gets the unique id of the port. * * @return The unique id of the port; not intended for display. + * + * @hide */ public String getId() { return mId; @@ -133,23 +84,62 @@ public final class UsbPort implements Parcelable { * The actual mode of the port may vary depending on what is plugged into it. * </p> * - * @return The supported modes: one of {@link #MODE_DFP}, {@link #MODE_UFP}, or - * {@link #MODE_DUAL}. + * @return The supported modes: one of {@link UsbPortStatus#MODE_DFP}, + * {@link UsbPortStatus#MODE_UFP}, or {@link UsbPortStatus#MODE_DUAL}. + * + * @hide */ public int getSupportedModes() { return mSupportedModes; } /** + * Gets the status of this USB port. + * + * @return The status of the this port, or {@code null} if port is unknown. + */ + @RequiresPermission(Manifest.permission.MANAGE_USB) + public @Nullable UsbPortStatus getStatus() { + return mUsbManager.getPortStatus(this); + } + + /** + * Sets the desired role combination of the port. + * <p> + * The supported role combinations depend on what is connected to the port and may be + * determined by consulting + * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}. + * </p><p> + * Note: This function is asynchronous and may fail silently without applying + * the requested changes. If this function does cause a status change to occur then + * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent. + * </p> + * + * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} or + * {@link UsbPortStatus#POWER_ROLE_SINK}, or + * {@link UsbPortStatus#POWER_ROLE_NONE} if no power role. + * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} or + * {@link UsbPortStatus#DATA_ROLE_DEVICE}, or + * {@link UsbPortStatus#DATA_ROLE_NONE} if no data role. + */ + @RequiresPermission(Manifest.permission.MANAGE_USB) + public void setRoles(@UsbPortStatus.UsbPowerRole int powerRole, + @UsbPortStatus.UsbDataRole int dataRole) { + UsbPort.checkRoles(powerRole, dataRole); + + mUsbManager.setPortRoles(this, powerRole, dataRole); + } + + /** * Combines one power and one data role together into a unique value with * exactly one bit set. This can be used to efficiently determine whether * a combination of roles is supported by testing whether that bit is present * in a bit-field. * - * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE} - * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role. - * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST} - * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role. + * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} + * or {@link UsbPortStatus#POWER_ROLE_SINK}, or 0 if no power role. + * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} + * or {@link UsbPortStatus#DATA_ROLE_DEVICE}, or 0 if no data role. * @hide */ public static int combineRolesAsBit(int powerRole, int dataRole) { @@ -276,30 +266,4 @@ public final class UsbPort implements Parcelable { public String toString() { return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) + "}"; } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mId); - dest.writeInt(mSupportedModes); - } - - public static final Parcelable.Creator<UsbPort> CREATOR = - new Parcelable.Creator<UsbPort>() { - @Override - public UsbPort createFromParcel(Parcel in) { - String id = in.readString(); - int supportedModes = in.readInt(); - return new UsbPort(id, supportedModes); - } - - @Override - public UsbPort[] newArray(int size) { - return new UsbPort[size]; - } - }; } diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java index 2cd8209fccda..d30201a597bf 100644 --- a/core/java/android/hardware/usb/UsbPortStatus.java +++ b/core/java/android/hardware/usb/UsbPortStatus.java @@ -16,27 +16,134 @@ package android.hardware.usb; -import android.annotation.UnsupportedAppUsage; +import android.annotation.IntDef; +import android.annotation.SystemApi; +import android.hardware.usb.V1_0.Constants; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.Immutable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Describes the status of a USB port. - * <p> - * This object is immutable. - * </p> * * @hide */ +@Immutable +@SystemApi public final class UsbPortStatus implements Parcelable { private final int mCurrentMode; - private final int mCurrentPowerRole; - private final int mCurrentDataRole; + private final @UsbPowerRole int mCurrentPowerRole; + private final @UsbDataRole int mCurrentDataRole; private final int mSupportedRoleCombinations; + /** + * Power role: This USB port does not have a power role. + */ + public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE; + + /** + * Power role: This USB port can act as a source (provide power). + */ + public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE; + + /** + * Power role: This USB port can act as a sink (receive power). + */ + public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK; + + @IntDef(prefix = { "POWER_ROLE_" }, value = { + POWER_ROLE_NONE, + POWER_ROLE_SOURCE, + POWER_ROLE_SINK + }) + @Retention(RetentionPolicy.SOURCE) + @interface UsbPowerRole{} + + /** + * Power role: This USB port does not have a data role. + */ + public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE; + + /** + * Data role: This USB port can act as a host (access data services). + */ + public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST; + + /** + * Data role: This USB port can act as a device (offer data services). + */ + public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE; + + @IntDef(prefix = { "DATA_ROLE_" }, value = { + DATA_ROLE_NONE, + DATA_ROLE_HOST, + DATA_ROLE_DEVICE + }) + @Retention(RetentionPolicy.SOURCE) + @interface UsbDataRole{} + + /** + * There is currently nothing connected to this USB port. + */ + public static final int MODE_NONE = Constants.PortMode.NONE; + + /** + * This USB port can act as a downstream facing port (host). + * + * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and + * {@link #DATA_ROLE_HOST} combination of roles (and possibly others as well). + */ + public static final int MODE_DFP = Constants.PortMode.DFP; + + /** + * This USB port can act as an upstream facing port (device). + * + * <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and + * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well). + */ + public static final int MODE_UFP = Constants.PortMode.UFP; + + /** + * This USB port can act either as an downstream facing port (host) or as + * an upstream facing port (device). + * + * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and + * {@link #DATA_ROLE_HOST} combination of roles and the {@link #POWER_ROLE_SINK} and + * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well). + * + * @hide + */ + public static final int MODE_DUAL = Constants.PortMode.DRP; + + /** + * This USB port can support USB Type-C Audio accessory. + */ + public static final int MODE_AUDIO_ACCESSORY = + android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY; + + /** + * This USB port can support USB Type-C debug accessory. + */ + public static final int MODE_DEBUG_ACCESSORY = + android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY; + + @IntDef(prefix = { "MODE_" }, flag = true, value = { + MODE_NONE, + MODE_DFP, + MODE_UFP, + MODE_AUDIO_ACCESSORY, + MODE_DEBUG_ACCESSORY, + }) + @Retention(RetentionPolicy.SOURCE) + @interface UsbPortMode{} + /** @hide */ - public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole, - int supportedRoleCombinations) { + public UsbPortStatus(int currentMode, @UsbPowerRole int currentPowerRole, + @UsbDataRole int currentDataRole, int supportedRoleCombinations) { mCurrentMode = currentMode; mCurrentPowerRole = currentPowerRole; mCurrentDataRole = currentDataRole; @@ -46,9 +153,8 @@ public final class UsbPortStatus implements Parcelable { /** * Returns true if there is anything connected to the port. * - * @return True if there is anything connected to the port. + * @return {@code true} iff there is anything connected to the port. */ - @UnsupportedAppUsage public boolean isConnected() { return mCurrentMode != 0; } @@ -56,33 +162,31 @@ public final class UsbPortStatus implements Parcelable { /** * Gets the current mode of the port. * - * @return The current mode: {@link UsbPort#MODE_DFP}, {@link UsbPort#MODE_UFP}, - * or 0 if nothing is connected. + * @return The current mode: {@link #MODE_DFP}, {@link #MODE_UFP}, + * {@link #MODE_AUDIO_ACCESSORY}, {@link #MODE_DEBUG_ACCESSORY}, or {@link {@link #MODE_NONE} if + * nothing is connected. */ - @UnsupportedAppUsage - public int getCurrentMode() { + public @UsbPortMode int getCurrentMode() { return mCurrentMode; } /** * Gets the current power role of the port. * - * @return The current power role: {@link UsbPort#POWER_ROLE_SOURCE}, - * {@link UsbPort#POWER_ROLE_SINK}, or 0 if nothing is connected. + * @return The current power role: {@link #POWER_ROLE_SOURCE}, {@link #POWER_ROLE_SINK}, or + * {@link #POWER_ROLE_NONE} if nothing is connected. */ - @UnsupportedAppUsage - public int getCurrentPowerRole() { + public @UsbPowerRole int getCurrentPowerRole() { return mCurrentPowerRole; } /** * Gets the current data role of the port. * - * @return The current data role: {@link UsbPort#DATA_ROLE_HOST}, - * {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if nothing is connected. + * @return The current data role: {@link #DATA_ROLE_HOST}, {@link #DATA_ROLE_DEVICE}, or + * {@link #DATA_ROLE_NONE} if nothing is connected. */ - @UnsupportedAppUsage - public int getCurrentDataRole() { + public @UsbDataRole int getCurrentDataRole() { return mCurrentDataRole; } @@ -90,19 +194,20 @@ public final class UsbPortStatus implements Parcelable { * Returns true if the specified power and data role combination is supported * given what is currently connected to the port. * - * @param powerRole The power role to check: {@link UsbPort#POWER_ROLE_SOURCE} - * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role. - * @param dataRole The data role to check: either {@link UsbPort#DATA_ROLE_HOST} - * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role. + * @param powerRole The power role to check: {@link #POWER_ROLE_SOURCE} or + * {@link #POWER_ROLE_SINK}, or {@link #POWER_ROLE_NONE} if no power role. + * @param dataRole The data role to check: either {@link #DATA_ROLE_HOST} or + * {@link #DATA_ROLE_DEVICE}, or {@link #DATA_ROLE_NONE} if no data role. */ - @UnsupportedAppUsage - public boolean isRoleCombinationSupported(int powerRole, int dataRole) { + public boolean isRoleCombinationSupported(@UsbPowerRole int powerRole, + @UsbDataRole int dataRole) { return (mSupportedRoleCombinations & UsbPort.combineRolesAsBit(powerRole, dataRole)) != 0; } - /** @hide */ - @UnsupportedAppUsage + /** + * Get the supported role combinations. + */ public int getSupportedRoleCombinations() { return mSupportedRoleCombinations; } diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java index cac22652ebd7..240c2e757faf 100644 --- a/core/java/com/android/internal/usb/DumpUtils.java +++ b/core/java/com/android/internal/usb/DumpUtils.java @@ -16,12 +16,12 @@ package com.android.internal.usb; -import static android.hardware.usb.UsbPort.MODE_AUDIO_ACCESSORY; -import static android.hardware.usb.UsbPort.MODE_DEBUG_ACCESSORY; -import static android.hardware.usb.UsbPort.MODE_DFP; -import static android.hardware.usb.UsbPort.MODE_DUAL; -import static android.hardware.usb.UsbPort.MODE_NONE; -import static android.hardware.usb.UsbPort.MODE_UFP; +import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY; +import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY; +import static android.hardware.usb.UsbPortStatus.MODE_DFP; +import static android.hardware.usb.UsbPortStatus.MODE_DUAL; +import static android.hardware.usb.UsbPortStatus.MODE_NONE; +import static android.hardware.usb.UsbPortStatus.MODE_UFP; import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull; diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 60cb08f00f89..294b7509698b 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -16,6 +16,12 @@ package com.android.server.usb; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST; +import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; + import static com.android.internal.usb.DumpUtils.writeAccessory; import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull; @@ -36,6 +42,7 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.debug.AdbManagerInternal; import android.debug.IAdbTransport; +import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbConfiguration; import android.hardware.usb.UsbConstants; @@ -294,9 +301,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser BroadcastReceiver portReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT); + ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT); UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS); - mHandler.updateHostState(port, status); + mHandler.updateHostState( + port.getUsbPort(context.getSystemService(UsbManager.class)), status); } }; @@ -821,23 +829,20 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser boolean prevHostConnected = mHostConnected; UsbPort port = (UsbPort) args.arg1; UsbPortStatus status = (UsbPortStatus) args.arg2; - mHostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST; - mSourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE; - mSinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK; - mAudioAccessoryConnected = - (status.getCurrentMode() == UsbPort.MODE_AUDIO_ACCESSORY); - mAudioAccessorySupported = port.isModeSupported(UsbPort.MODE_AUDIO_ACCESSORY); + mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST; + mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE; + mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK; + mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY); + mAudioAccessorySupported = port.isModeSupported(MODE_AUDIO_ACCESSORY); // Ideally we want to see if PR_SWAP and DR_SWAP is supported. // But, this should be suffice, since, all four combinations are only supported // when PR_SWAP and DR_SWAP are supported. mSupportsAllCombinations = status.isRoleCombinationSupported( - UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST) - && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, - UsbPort.DATA_ROLE_HOST) - && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, - UsbPort.DATA_ROLE_DEVICE) - && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, - UsbPort.DATA_ROLE_HOST); + POWER_ROLE_SOURCE, DATA_ROLE_HOST) + && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST) + && status.isRoleCombinationSupported(POWER_ROLE_SOURCE, + DATA_ROLE_DEVICE) + && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST); args.recycle(); updateUsbNotification(false); diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index 96618f569928..6f210e37d6d1 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -16,12 +16,22 @@ package com.android.server.usb; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST; +import static android.hardware.usb.UsbPortStatus.MODE_DFP; +import static android.hardware.usb.UsbPortStatus.MODE_DUAL; +import static android.hardware.usb.UsbPortStatus.MODE_UFP; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; + import static com.android.internal.usb.DumpUtils.writePort; import static com.android.internal.usb.DumpUtils.writePortStatus; +import android.Manifest; import android.annotation.NonNull; import android.content.Context; import android.content.Intent; +import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; @@ -78,13 +88,13 @@ public class UsbPortManager { // All non-trivial role combinations. private static final int COMBO_SOURCE_HOST = - UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST); - private static final int COMBO_SOURCE_DEVICE = - UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE); + UsbPort.combineRolesAsBit(POWER_ROLE_SOURCE, DATA_ROLE_HOST); + private static final int COMBO_SOURCE_DEVICE = UsbPort.combineRolesAsBit( + POWER_ROLE_SOURCE, DATA_ROLE_DEVICE); private static final int COMBO_SINK_HOST = - UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST); - private static final int COMBO_SINK_DEVICE = - UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE); + UsbPort.combineRolesAsBit(POWER_ROLE_SINK, DATA_ROLE_HOST); + private static final int COMBO_SINK_DEVICE = UsbPort.combineRolesAsBit( + POWER_ROLE_SINK, DATA_ROLE_DEVICE); // The system context. private final Context mContext; @@ -217,12 +227,12 @@ public class UsbPortManager { final int newMode; if ((!canChangePowerRole && currentPowerRole != newPowerRole) || (!canChangeDataRole && currentDataRole != newDataRole)) { - if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SOURCE - && newDataRole == UsbPort.DATA_ROLE_HOST) { - newMode = UsbPort.MODE_DFP; - } else if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SINK - && newDataRole == UsbPort.DATA_ROLE_DEVICE) { - newMode = UsbPort.MODE_UFP; + if (canChangeMode && newPowerRole == POWER_ROLE_SOURCE + && newDataRole == DATA_ROLE_HOST) { + newMode = MODE_DFP; + } else if (canChangeMode && newPowerRole == POWER_ROLE_SINK + && newDataRole == DATA_ROLE_DEVICE) { + newMode = MODE_UFP; } else { logAndPrint(Log.ERROR, pw, "Found mismatch in supported USB role combinations " + "while attempting to change role: " + portInfo @@ -607,7 +617,7 @@ public class UsbPortManager { IndentingPrintWriter pw) { // Only allow mode switch capability for dual role ports. // Validate that the current mode matches the supported modes we expect. - if ((supportedModes & UsbPort.MODE_DUAL) != UsbPort.MODE_DUAL) { + if ((supportedModes & MODE_DUAL) != MODE_DUAL) { canChangeMode = false; if (currentMode != 0 && currentMode != supportedModes) { logAndPrint(Log.WARN, pw, "Ignoring inconsistent current mode from USB " @@ -633,16 +643,16 @@ public class UsbPortManager { // Can only change power role. // Assume data role must remain at its current value. supportedRoleCombinations |= UsbPort.combineRolesAsBit( - UsbPort.POWER_ROLE_SOURCE, currentDataRole); + POWER_ROLE_SOURCE, currentDataRole); supportedRoleCombinations |= UsbPort.combineRolesAsBit( - UsbPort.POWER_ROLE_SINK, currentDataRole); + POWER_ROLE_SINK, currentDataRole); } else if (canChangeDataRole) { // Can only change data role. // Assume power role must remain at its current value. supportedRoleCombinations |= UsbPort.combineRolesAsBit( - currentPowerRole, UsbPort.DATA_ROLE_HOST); + currentPowerRole, DATA_ROLE_HOST); supportedRoleCombinations |= UsbPort.combineRolesAsBit( - currentPowerRole, UsbPort.DATA_ROLE_DEVICE); + currentPowerRole, DATA_ROLE_DEVICE); } else if (canChangeMode) { // Can only change the mode. // Assume both standard UFP and DFP configurations will become available @@ -654,7 +664,8 @@ public class UsbPortManager { // Update the port data structures. PortInfo portInfo = mPorts.get(portId); if (portInfo == null) { - portInfo = new PortInfo(portId, supportedModes); + portInfo = new PortInfo(mContext.getSystemService(UsbManager.class), portId, + supportedModes); portInfo.setStatus(currentMode, canChangeMode, currentPowerRole, canChangePowerRole, currentDataRole, canChangeDataRole, @@ -701,12 +712,13 @@ public class UsbPortManager { intent.addFlags( Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - intent.putExtra(UsbManager.EXTRA_PORT, portInfo.mUsbPort); + intent.putExtra(UsbManager.EXTRA_PORT, ParcelableUsbPort.of(portInfo.mUsbPort)); intent.putExtra(UsbManager.EXTRA_PORT_STATUS, portInfo.mUsbPortStatus); // Guard against possible reentrance by posting the broadcast from the handler // instead of from within the critical section. - mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL)); + mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL, + Manifest.permission.MANAGE_USB)); // Log to statsd if (!mConnected.containsKey(portInfo.mUsbPort.getId()) @@ -772,8 +784,8 @@ public class UsbPortManager { // 0 when port is connected. Else reports the last connected duration public long mLastConnectDurationMillis; - public PortInfo(String portId, int supportedModes) { - mUsbPort = new UsbPort(portId, supportedModes); + PortInfo(@NonNull UsbManager usbManager, @NonNull String portId, int supportedModes) { + mUsbPort = new UsbPort(usbManager, portId, supportedModes); } public boolean setStatus(int currentMode, boolean canChangeMode, diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index f9abedfbf586..911547720a8f 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -16,6 +16,14 @@ package com.android.server.usb; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST; +import static android.hardware.usb.UsbPortStatus.MODE_DFP; +import static android.hardware.usb.UsbPortStatus.MODE_DUAL; +import static android.hardware.usb.UsbPortStatus.MODE_UFP; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; + import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.PendingIntent; @@ -27,6 +35,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.hardware.usb.IUsbManager; +import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; @@ -52,7 +61,9 @@ import com.android.server.SystemService; import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; /** * UsbService manages all USB related state, including both host and device support. @@ -489,12 +500,25 @@ public class UsbService extends IUsbManager.Stub { } @Override - public UsbPort[] getPorts() { + public List<ParcelableUsbPort> getPorts() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); final long ident = Binder.clearCallingIdentity(); try { - return mPortManager != null ? mPortManager.getPorts() : null; + if (mPortManager == null) { + return null; + } else { + final UsbPort[] ports = mPortManager.getPorts(); + + final int numPorts = ports.length; + ArrayList<ParcelableUsbPort> parcelablePorts = new ArrayList<>(); + for (int i = 0; i < numPorts; i++) { + parcelablePorts.add(ParcelableUsbPort.of(ports[i])); + } + + return parcelablePorts; + } + } finally { Binder.restoreCallingIdentity(ident); } @@ -588,10 +612,10 @@ public class UsbService extends IUsbManager.Stub { final int powerRole; switch (args[2]) { case "source": - powerRole = UsbPort.POWER_ROLE_SOURCE; + powerRole = POWER_ROLE_SOURCE; break; case "sink": - powerRole = UsbPort.POWER_ROLE_SINK; + powerRole = POWER_ROLE_SINK; break; case "no-power": powerRole = 0; @@ -603,10 +627,10 @@ public class UsbService extends IUsbManager.Stub { final int dataRole; switch (args[3]) { case "host": - dataRole = UsbPort.DATA_ROLE_HOST; + dataRole = DATA_ROLE_HOST; break; case "device": - dataRole = UsbPort.DATA_ROLE_DEVICE; + dataRole = DATA_ROLE_DEVICE; break; case "no-data": dataRole = 0; @@ -631,13 +655,13 @@ public class UsbService extends IUsbManager.Stub { final int supportedModes; switch (args[2]) { case "ufp": - supportedModes = UsbPort.MODE_UFP; + supportedModes = MODE_UFP; break; case "dfp": - supportedModes = UsbPort.MODE_DFP; + supportedModes = MODE_DFP; break; case "dual": - supportedModes = UsbPort.MODE_DUAL; + supportedModes = MODE_DUAL; break; case "none": supportedModes = 0; @@ -658,10 +682,10 @@ public class UsbService extends IUsbManager.Stub { final boolean canChangeMode = args[2].endsWith("?"); switch (canChangeMode ? removeLastChar(args[2]) : args[2]) { case "ufp": - mode = UsbPort.MODE_UFP; + mode = MODE_UFP; break; case "dfp": - mode = UsbPort.MODE_DFP; + mode = MODE_DFP; break; default: pw.println("Invalid mode: " + args[2]); @@ -671,10 +695,10 @@ public class UsbService extends IUsbManager.Stub { final boolean canChangePowerRole = args[3].endsWith("?"); switch (canChangePowerRole ? removeLastChar(args[3]) : args[3]) { case "source": - powerRole = UsbPort.POWER_ROLE_SOURCE; + powerRole = POWER_ROLE_SOURCE; break; case "sink": - powerRole = UsbPort.POWER_ROLE_SINK; + powerRole = POWER_ROLE_SINK; break; default: pw.println("Invalid power role: " + args[3]); @@ -684,10 +708,10 @@ public class UsbService extends IUsbManager.Stub { final boolean canChangeDataRole = args[4].endsWith("?"); switch (canChangeDataRole ? removeLastChar(args[4]) : args[4]) { case "host": - dataRole = UsbPort.DATA_ROLE_HOST; + dataRole = DATA_ROLE_HOST; break; case "device": - dataRole = UsbPort.DATA_ROLE_DEVICE; + dataRole = DATA_ROLE_DEVICE; break; default: pw.println("Invalid data role: " + args[4]); |