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
This commit is contained in:
Ricky Niu
2021-11-03 18:44:14 +08:00
parent 7212c8fda4
commit 476cd2e3ca
9 changed files with 246 additions and 0 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -1323,6 +1323,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>

View File

@@ -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.
*

View File

@@ -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) {

View File

@@ -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<ParcelableUsbPort> getPorts() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);

View File

@@ -237,6 +237,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) {
@@ -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);
}
}
}
}

View File

@@ -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);
}

View File

@@ -317,6 +317,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) {