diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 0c84c9756bde2..3a2be31ee0b26 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4690,6 +4690,7 @@ package android.hardware.usb { method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbData(boolean); method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbDataWhileDocked(); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus(); + method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int resetUsbPort(); method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int); field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1; // 0x1 field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED = 2; // 0x2 diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 459dab1bffe16..b617e056774b7 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -136,6 +136,9 @@ interface IUsbManager /* Resets the USB gadget. */ void resetUsbGadget(); + /* Resets the USB port. */ + boolean resetUsbPort(in String portId, int operationId, in IUsbOperationInternal callback); + /* Set USB data on or off */ boolean enableUsbData(in String portId, boolean enable, int operationId, in IUsbOperationInternal callback); diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index f0e040ed4686a..60f5135aed6c2 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -1323,6 +1323,43 @@ public class UsbManager { } } + /** + * Should only be called by {@link UsbPort#resetUsbPort}. + *
+ * Disable and then re-enable USB data signaling. + * + * Reset USB first port.. + * It will force to stop and restart USB data signaling. + * Call UsbPort API if the device has more than one UsbPort. + *
+ * + * @param port reset the USB Port + * @return true enable or disable USB data successfully + * false if something wrong + * + * Should only be called by {@link UsbPort#resetUsbPort}. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_USB) + boolean resetUsbPort(@NonNull UsbPort port, int operationId, + IUsbOperationInternal callback) { + Objects.requireNonNull(port, "resetUsbPort: port must not be null. opId:" + operationId); + try { + return mService.resetUsbPort(port.getId(), operationId, callback); + } catch (RemoteException e) { + Log.e(TAG, "resetUsbPort: failed. ", e); + try { + callback.onOperationComplete(UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL); + } catch (RemoteException r) { + Log.e(TAG, "resetUsbPort: failed to call onOperationComplete. opId:" + + operationId, r); + } + throw e.rethrowFromSystemServer(); + } + } + /** * Should only be called by {@link UsbPort#enableUsbData}. *
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index bef4dea019a23..a9797250898ff 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -128,6 +128,9 @@ public final class UsbPort {
@Retention(RetentionPolicy.SOURCE)
@interface EnableUsbDataStatus{}
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ResetUsbPortStatus{}
+
/**
* The {@link #enableLimitPowerTransfer} request was successfully completed.
*/
@@ -318,6 +321,43 @@ public final class UsbPort {
mUsbManager.setPortRoles(this, powerRole, dataRole);
}
+ /**
+ * Reset Usb data on the port.
+ *
+ * @return {@link #ENABLE_USB_DATA_SUCCESS} when request completes successfully or
+ * {@link #ENABLE_USB_DATA_ERROR_INTERNAL} when request fails due to internal
+ * error or
+ * {@link ENABLE_USB_DATA_ERROR_NOT_SUPPORTED} when not supported or
+ * {@link ENABLE_USB_DATA_ERROR_PORT_MISMATCH} when request fails due to port id
+ * mismatch or
+ * {@link ENABLE_USB_DATA_ERROR_OTHER} when fails due to other reasons.
+ */
+ @CheckResult
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ public @ResetUsbPortStatus int resetUsbPort() {
+ // UID is added To minimize operationID overlap between two different packages.
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
+ Log.i(TAG, "resetUsbData opId:" + operationId);
+ UsbOperationInternal opCallback =
+ new UsbOperationInternal(operationId, mId);
+ if (mUsbManager.resetUsbPort(this, operationId, opCallback) == true) {
+ opCallback.waitForOperationComplete();
+ }
+ int result = opCallback.getStatus();
+ switch (result) {
+ case USB_OPERATION_SUCCESS:
+ return ENABLE_USB_DATA_SUCCESS;
+ case USB_OPERATION_ERROR_INTERNAL:
+ return ENABLE_USB_DATA_ERROR_INTERNAL;
+ case USB_OPERATION_ERROR_NOT_SUPPORTED:
+ return ENABLE_USB_DATA_ERROR_NOT_SUPPORTED;
+ case USB_OPERATION_ERROR_PORT_MISMATCH:
+ return ENABLE_USB_DATA_ERROR_PORT_MISMATCH;
+ default:
+ return ENABLE_USB_DATA_ERROR_OTHER;
+ }
+ }
+
/**
* Enables/Disables Usb data on the port.
*
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 65b79bfbb36f2..d0825ba3b6202 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -503,6 +503,49 @@ public class UsbPortManager {
return HAL_MODE_DFP;
}
+ /**
+ * Reset USB port.
+ *
+ * @param portId port identifier.
+ */
+ public boolean resetUsbPort(@NonNull String portId, int transactionId,
+ @NonNull IUsbOperationInternal callback, IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ Objects.requireNonNull(callback);
+ Objects.requireNonNull(portId);
+ final PortInfo portInfo = mPorts.get(portId);
+ if (portInfo == null) {
+ logAndPrint(Log.ERROR, pw, "resetUsbPort: No such port: " + portId
+ + " opId:" + transactionId);
+ try {
+ callback.onOperationComplete(
+ USB_OPERATION_ERROR_PORT_MISMATCH);
+ } catch (RemoteException e) {
+ logAndPrintException(pw,
+ "resetUsbPort: Failed to call OperationComplete. opId:"
+ + transactionId, e);
+ }
+ return false;
+ }
+
+ try {
+ try {
+ return mUsbPortHal.resetUsbPort(portId, transactionId, callback);
+ } catch (Exception e) {
+ logAndPrintException(pw,
+ "reseetUsbPort: Failed to resetUsbPort. opId:"
+ + transactionId , e);
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(pw,
+ "resetUsbPort: Failed to call onOperationComplete. opId:"
+ + transactionId, e);
+ }
+ return false;
+ }
+ }
+
public void setPortRoles(String portId, int newPowerRole, int newDataRole,
IndentingPrintWriter pw) {
synchronized (mLock) {
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 88ffc7d613e29..f3308bb74501b 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -679,6 +679,35 @@ public class UsbService extends IUsbManager.Stub {
}
}
+ @Override
+ public boolean resetUsbPort(String portId, int operationId,
+ IUsbOperationInternal callback) {
+ Objects.requireNonNull(portId, "resetUsbPort: portId must not be null. opId:"
+ + operationId);
+ Objects.requireNonNull(callback, "resetUsbPort: callback must not be null. opId:"
+ + operationId);
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ boolean wait;
+
+ try {
+ if (mPortManager != null) {
+ wait = mPortManager.resetUsbPort(portId, operationId, callback, null);
+ } else {
+ wait = false;
+ try {
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "resetUsbPort: Failed to call onOperationComplete", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return wait;
+ }
+
@Override
public List