diff options
| author | 2021-11-03 18:44:14 +0800 | |
|---|---|---|
| committer | 2022-01-25 12:01:34 +0800 | |
| commit | 476cd2e3ca02fcd48cecca5217e5e43053437a7e (patch) | |
| tree | 0b16d8cddd6f486e6db39d7d7c3c78f3ef62a4a4 | |
| parent | 7212c8fda4942546a33f632ea5247ceb73005a4d (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
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; |