summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ricky Niu <rickyniu@google.com> 2021-11-03 18:44:14 +0800
committer Ricky Niu <rickyniu@google.com> 2022-01-25 12:01:34 +0800
commit476cd2e3ca02fcd48cecca5217e5e43053437a7e (patch)
tree0b16d8cddd6f486e6db39d7d7c3c78f3ef62a4a4
parent7212c8fda4942546a33f632ea5247ceb73005a4d (diff)
Support USB Port Reset
Verify the USB Gadget HAL already implement. Bug: 197300598 Test: Verify the API working manually Signed-off-by: Ricky Niu <rickyniu@google.com> Change-Id: I8a4a4966237c925c87b32f74a382b7a56f82ab7d
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/java/android/hardware/usb/IUsbManager.aidl3
-rw-r--r--core/java/android/hardware/usb/UsbManager.java37
-rw-r--r--core/java/android/hardware/usb/UsbPort.java40
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java43
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java29
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java66
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java14
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java13
9 files changed, 246 insertions, 0 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0c84c9756bde..3a2be31ee0b2 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 459dab1bffe1..b617e056774b 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 f0e040ed4686..60f5135aed6c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -1324,6 +1324,43 @@ public class UsbManager {
}
/**
+ * Should only be called by {@link UsbPort#resetUsbPort}.
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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}.
* <p>
* Enables or disables USB data on the specific port.
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index bef4dea019a2..a9797250898f 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.
*/
@@ -319,6 +322,43 @@ public final class UsbPort {
}
/**
+ * 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.
*
* @param enable When true enables USB data if disabled.
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 65b79bfbb36f..d0825ba3b620 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 88ffc7d613e2..f3308bb74501 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -680,6 +680,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<ParcelableUsbPort> getPorts() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index 558260073733..f468db353ccd 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -238,6 +238,50 @@ public final class UsbPortAidl implements UsbPortHal {
}
@Override
+ public boolean resetUsbPort(String portName, long operationID,
+ IUsbOperationInternal callback) {
+ Objects.requireNonNull(portName);
+ Objects.requireNonNull(callback);
+ long key = operationID;
+ synchronized (mLock) {
+ try {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw,
+ "resetUsbPort: Proxy is null. Retry !opID:"
+ + operationID);
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ return false;
+ }
+ while (sCallbacks.get(key) != null) {
+ key = ThreadLocalRandom.current().nextInt();
+ }
+ if (key != operationID) {
+ logAndPrint(Log.INFO, mPw, "resetUsbPort: operationID exists ! opID:"
+ + operationID + " key:" + key);
+ }
+ try {
+ sCallbacks.put(operationID, callback);
+ mProxy.resetUsbPort(portName, operationID);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "resetUsbPort: Failed to resetUsbPort: portID="
+ + portName + "opId:" + operationID, e);
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ sCallbacks.remove(key);
+ return false;
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "resetUsbPort: Failed to call onOperationComplete portID="
+ + portName + "opID:" + operationID, e);
+ sCallbacks.remove(key);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ @Override
public boolean enableUsbData(String portName, boolean enable, long operationID,
IUsbOperationInternal callback) {
Objects.requireNonNull(portName);
@@ -605,5 +649,27 @@ public final class UsbPortAidl implements UsbPortHal {
e);
}
}
+
+ @Override
+ public void notifyResetUsbPortStatus(String portName, int retval,
+ long operationID) {
+ if (retval == Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyResetUsbPortStatus:"
+ + portName + ": opID:" + operationID);
+ } else {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
+ + "notifyEnableUsbDataStatus: opID:"
+ + operationID + " failed. err:" + retval);
+ }
+ try {
+ sCallbacks.get(operationID).onOperationComplete(retval == Status.SUCCESS
+ ? USB_OPERATION_SUCCESS
+ : USB_OPERATION_ERROR_INTERNAL);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "notifyResetUsbPortStatus: Failed to call onOperationComplete",
+ e);
+ }
+ }
}
}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
index abfdd6f517cd..4fa296da7267 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
@@ -193,4 +193,18 @@ public interface UsbPortHal {
*/
public void enableLimitPowerTransfer(String portName, boolean limit, long transactionId,
IUsbOperationInternal callback);
+
+ /**
+ * Invoked to reset UsbData on the specified port.
+ *
+ * @param portName Port Identifier.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ * @param callback callback object to be invoked to invoke the status of the operation upon
+ * completion.
+ * @param callback callback object to be invoked to invoke the status of the operation upon
+ * completion.
+ */
+ public boolean resetUsbPort(String portName, long transactionId,
+ IUsbOperationInternal callback);
}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
index c1d76355e75b..64e8adc597c6 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -318,6 +318,19 @@ public final class UsbPortHidl implements UsbPortHal {
}
@Override
+ public boolean resetUsbPort(String portName, long transactionId,
+ IUsbOperationInternal callback) {
+ try {
+ callback.onOperationComplete(USB_OPERATION_ERROR_NOT_SUPPORTED);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+ + transactionId
+ + " portId:" + portName, e);
+ }
+ return false;
+ }
+
+ @Override
public boolean enableUsbData(String portName, boolean enable, long transactionId,
IUsbOperationInternal callback) {
int halVersion;