Merge changes from topic "227137943"

* changes:
  Implement getInterfaceHash/Version (USB)
  Support IUsb AIDL interface
This commit is contained in:
Treehugger Robot
2022-04-27 16:21:29 +00:00
committed by Gerrit Code Review
18 changed files with 1837 additions and 443 deletions

View File

@@ -100,10 +100,12 @@ package android.hardware.usb {
field public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2; // 0x2 field public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2; // 0x2
field public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1; // 0xffffffff field public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1; // 0xffffffff
field public static final int USB_HAL_NOT_SUPPORTED = -1; // 0xffffffff field public static final int USB_HAL_NOT_SUPPORTED = -1; // 0xffffffff
field public static final int USB_HAL_RETRY = -2; // 0xfffffffe
field public static final int USB_HAL_V1_0 = 10; // 0xa field public static final int USB_HAL_V1_0 = 10; // 0xa
field public static final int USB_HAL_V1_1 = 11; // 0xb field public static final int USB_HAL_V1_1 = 11; // 0xb
field public static final int USB_HAL_V1_2 = 12; // 0xc field public static final int USB_HAL_V1_2 = 12; // 0xc
field public static final int USB_HAL_V1_3 = 13; // 0xd field public static final int USB_HAL_V1_3 = 13; // 0xd
field public static final int USB_HAL_V2_0 = 20; // 0x14
} }
} }

View File

@@ -4169,8 +4169,14 @@ package android.hardware.usb {
} }
public final class UsbPort { public final class UsbPort {
method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbData(boolean);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus(); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int); method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
field public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1; // 0x1
field public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2; // 0x2
field public static final int ENABLE_USB_DATA_ERROR_OTHER = 4; // 0x4
field public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3; // 0x3
field public static final int ENABLE_USB_DATA_SUCCESS = 0; // 0x0
} }
public final class UsbPortStatus implements android.os.Parcelable { public final class UsbPortStatus implements android.os.Parcelable {

View File

@@ -18,6 +18,7 @@ package android.hardware.usb;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.ComponentName; import android.content.ComponentName;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDevice;
import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.ParcelableUsbPort;
@@ -136,7 +137,7 @@ interface IUsbManager
void resetUsbGadget(); void resetUsbGadget();
/* Set USB data on or off */ /* Set USB data on or off */
boolean enableUsbDataSignal(boolean enable); boolean enableUsbData(in String portId, boolean enable, int operationId, in IUsbOperationInternal callback);
/* Gets the USB Hal Version. */ /* Gets the USB Hal Version. */
int getUsbHalVersion(); int getUsbHalVersion();
@@ -159,6 +160,6 @@ interface IUsbManager
/* Enable/disable contaminant detection */ /* Enable/disable contaminant detection */
void enableContaminantDetection(in String portId, boolean enable); void enableContaminantDetection(in String portId, boolean enable);
/* Sets USB device connection handler. */ /* Sets USB device connection handler. */
void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler); void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
} }

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2021 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;
/**
* @hide
*/
oneway interface IUsbOperationInternal {
void onOperationComplete(in int status);
}

View File

@@ -36,6 +36,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.gadget.V1_0.GadgetFunction; import android.hardware.usb.gadget.V1_0.GadgetFunction;
import android.hardware.usb.gadget.V1_2.UsbSpeed; import android.hardware.usb.gadget.V1_2.UsbSpeed;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbPort;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
@@ -48,6 +50,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner; import java.util.StringJoiner;
/** /**
@@ -515,6 +518,14 @@ public class UsbManager {
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024; public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024;
/**
* Returned when the client has to retry querying the version.
*
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_RETRY = -2;
/** /**
* The Value for USB hal is not presented. * The Value for USB hal is not presented.
* *
@@ -555,6 +566,14 @@ public class UsbManager {
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_3 = 13; public static final int USB_HAL_V1_3 = 13;
/**
* Value for USB Hal Version v2.0.
*
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V2_0 = 20;
/** /**
* Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)} * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
* {@hide} * {@hide}
@@ -664,6 +683,7 @@ public class UsbManager {
USB_HAL_V1_1, USB_HAL_V1_1,
USB_HAL_V1_2, USB_HAL_V1_2,
USB_HAL_V1_3, USB_HAL_V1_3,
USB_HAL_V2_0,
}) })
public @interface UsbHalVersion {} public @interface UsbHalVersion {}
@@ -1168,8 +1188,9 @@ public class UsbManager {
/** /**
* Enable/Disable the USB data signaling. * Enable/Disable the USB data signaling.
* <p> * <p>
* Enables/Disables USB data path in all the USB ports. * Enables/Disables USB data path of the first port..
* It will force to stop or restore USB data signaling. * It will force to stop or restore USB data signaling.
* Call UsbPort API if the device has more than one UsbPort.
* </p> * </p>
* *
* @param enable enable or disable USB data signaling * @param enable enable or disable USB data signaling
@@ -1180,11 +1201,11 @@ public class UsbManager {
*/ */
@RequiresPermission(Manifest.permission.MANAGE_USB) @RequiresPermission(Manifest.permission.MANAGE_USB)
public boolean enableUsbDataSignal(boolean enable) { public boolean enableUsbDataSignal(boolean enable) {
try { List<UsbPort> usbPorts = getPorts();
return mService.enableUsbDataSignal(enable); if (usbPorts.size() == 1) {
} catch (RemoteException e) { return usbPorts.get(0).enableUsbData(enable) == UsbPort.ENABLE_USB_DATA_SUCCESS;
throw e.rethrowFromSystemServer();
} }
return false;
} }
/** /**
@@ -1269,6 +1290,41 @@ public class UsbManager {
} }
} }
/**
* Should only be called by {@link UsbPort#enableUsbData}.
* <p>
* Enables or disables USB data on the specific port.
*
* @param port USB port for which USB data needs to be enabled or disabled.
* @param enable Enable USB data when true.
* Disable USB data when false.
* @param operationId operationId for the request.
* @param callback callback object to be invoked when the operation is complete.
* @return True when the operation is asynchronous. The caller must therefore call
* {@link UsbOperationInternal#waitForOperationComplete} for processing
* the result.
* False when the operation is synchronous. Caller can proceed reading the result
* through {@link UsbOperationInternal#getStatus}
* @hide
*/
@RequiresPermission(Manifest.permission.MANAGE_USB)
boolean enableUsbData(@NonNull UsbPort port, boolean enable, int operationId,
IUsbOperationInternal callback) {
Objects.requireNonNull(port, "enableUsbData: port must not be null. opId:" + operationId);
try {
return mService.enableUsbData(port.getId(), enable, operationId, callback);
} catch (RemoteException e) {
Log.e(TAG, "enableUsbData: failed. opId:" + operationId, e);
try {
callback.onOperationComplete(UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL);
} catch (RemoteException r) {
Log.e(TAG, "enableUsbData: failed to call onOperationComplete. opId:"
+ operationId, r);
}
throw e.rethrowFromSystemServer();
}
}
/** /**
* Sets the component that will handle USB device connection. * Sets the component that will handle USB device connection.
* <p> * <p>

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2022 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.IntDef;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbPort;
import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
/**
* UsbOperationInternal allows UsbPort to support both synchronous and
* asynchronous function irrespective of whether the underlying hal
* method is synchronous or asynchronous.
*
* @hide
*/
public final class UsbOperationInternal extends IUsbOperationInternal.Stub {
private static final String TAG = "UsbPortStatus";
private final int mOperationID;
// Cached portId.
private final String mId;
// True implies operation did not timeout.
private boolean mOperationComplete;
private @UsbOperationStatus int mStatus;
final ReentrantLock mLock = new ReentrantLock();
final Condition mOperationWait = mLock.newCondition();
// Maximum time the caller has to wait for onOperationComplete to be called.
private static final int USB_OPERATION_TIMEOUT_MSECS = 5000;
/**
* The requested operation was successfully completed.
* Returned in {@link onOperationComplete} and {@link getStatus}.
*/
public static final int USB_OPERATION_SUCCESS = 0;
/**
* The requested operation failed due to internal error.
* Returned in {@link onOperationComplete} and {@link getStatus}.
*/
public static final int USB_OPERATION_ERROR_INTERNAL = 1;
/**
* The requested operation failed as it's not supported.
* Returned in {@link onOperationComplete} and {@link getStatus}.
*/
public static final int USB_OPERATION_ERROR_NOT_SUPPORTED = 2;
/**
* The requested operation failed as it's not supported.
* Returned in {@link onOperationComplete} and {@link getStatus}.
*/
public static final int USB_OPERATION_ERROR_PORT_MISMATCH = 3;
@IntDef(prefix = { "USB_OPERATION_" }, value = {
USB_OPERATION_SUCCESS,
USB_OPERATION_ERROR_INTERNAL,
USB_OPERATION_ERROR_NOT_SUPPORTED,
USB_OPERATION_ERROR_PORT_MISMATCH
})
@Retention(RetentionPolicy.SOURCE)
@interface UsbOperationStatus{}
UsbOperationInternal(int operationID, String id) {
this.mOperationID = operationID;
this.mId = id;
}
/**
* Hal glue layer would directly call this function when the requested
* operation is complete.
*/
@Override
public void onOperationComplete(@UsbOperationStatus int status) {
mLock.lock();
try {
mOperationComplete = true;
mStatus = status;
Log.i(TAG, "Port:" + mId + " opID:" + mOperationID + " status:" + mStatus);
mOperationWait.signal();
} finally {
mLock.unlock();
}
}
/**
* Caller invokes this function to wait for the operation to be complete.
*/
public void waitForOperationComplete() {
mLock.lock();
try {
long now = System.currentTimeMillis();
long deadline = now + USB_OPERATION_TIMEOUT_MSECS;
// Wait in loop to overcome spurious wakeups.
do {
mOperationWait.await(deadline - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
} while (!mOperationComplete && System.currentTimeMillis() < deadline);
if (!mOperationComplete) {
Log.e(TAG, "Port:" + mId + " opID:" + mOperationID
+ " operationComplete not received in " + USB_OPERATION_TIMEOUT_MSECS
+ "msecs");
}
} catch (InterruptedException e) {
Log.e(TAG, "Port:" + mId + " opID:" + mOperationID + " operationComplete interrupted");
} finally {
mLock.unlock();
}
}
public @UsbOperationStatus int getStatus() {
return mOperationComplete ? mStatus : USB_OPERATION_ERROR_INTERNAL;
}
}

View File

@@ -16,6 +16,10 @@
package android.hardware.usb; package android.hardware.usb;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED; import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED; import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED; import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED;
@@ -34,15 +38,23 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
import android.Manifest; import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SystemApi; import android.annotation.SystemApi;
import android.hardware.usb.UsbOperationInternal;
import android.hardware.usb.V1_0.Constants; import android.hardware.usb.V1_0.Constants;
import android.os.Binder;
import android.util.Log;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Represents a physical USB port and describes its characteristics. * Represents a physical USB port and describes its characteristics.
@@ -51,6 +63,7 @@ import java.util.Objects;
*/ */
@SystemApi @SystemApi
public final class UsbPort { public final class UsbPort {
private static final String TAG = "UsbPort";
private final String mId; private final String mId;
private final int mSupportedModes; private final int mSupportedModes;
private final UsbManager mUsbManager; private final UsbManager mUsbManager;
@@ -64,6 +77,47 @@ public final class UsbPort {
*/ */
private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE; private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
/**
* Counter for tracking UsbOperation operations.
*/
private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
/**
* The {@link #enableUsbData} request was successfully completed.
*/
public static final int ENABLE_USB_DATA_SUCCESS = 0;
/**
* The {@link #enableUsbData} request failed due to internal error.
*/
public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1;
/**
* The {@link #enableUsbData} request failed as it's not supported.
*/
public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2;
/**
* The {@link #enableUsbData} request failed as port id mismatched.
*/
public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3;
/**
* The {@link #enableUsbData} request failed due to other reasons.
*/
public static final int ENABLE_USB_DATA_ERROR_OTHER = 4;
/** @hide */
@IntDef(prefix = { "ENABLE_USB_DATA_" }, value = {
ENABLE_USB_DATA_SUCCESS,
ENABLE_USB_DATA_ERROR_INTERNAL,
ENABLE_USB_DATA_ERROR_NOT_SUPPORTED,
ENABLE_USB_DATA_ERROR_PORT_MISMATCH,
ENABLE_USB_DATA_ERROR_OTHER
})
@Retention(RetentionPolicy.SOURCE)
@interface EnableUsbDataStatus{}
/** @hide */ /** @hide */
public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes, public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
int supportedContaminantProtectionModes, int supportedContaminantProtectionModes,
@@ -157,7 +211,7 @@ public final class UsbPort {
* {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}. * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
* </p><p> * </p><p>
* Note: This function is asynchronous and may fail silently without applying * 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 * the operationed changes. If this function does cause a status change to occur then
* a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent. * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent.
* </p> * </p>
* *
@@ -176,6 +230,47 @@ public final class UsbPort {
mUsbManager.setPortRoles(this, powerRole, dataRole); mUsbManager.setPortRoles(this, powerRole, dataRole);
} }
/**
* Enables/Disables Usb data on the port.
*
* @param enable When true enables USB data if disabled.
* When false disables USB data if enabled.
* @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 @EnableUsbDataStatus int enableUsbData(boolean enable) {
// UID is added To minimize operationID overlap between two different packages.
int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
Log.i(TAG, "enableUsbData opId:" + operationId
+ " callingUid:" + Binder.getCallingUid());
UsbOperationInternal opCallback =
new UsbOperationInternal(operationId, mId);
if (mUsbManager.enableUsbData(this, enable, 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;
}
}
/** /**
* @hide * @hide
**/ **/

View File

@@ -19,7 +19,6 @@ package android.hardware.usb;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.SystemApi; import android.annotation.SystemApi;
import android.hardware.usb.V1_0.Constants;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
@@ -36,27 +35,29 @@ import java.lang.annotation.RetentionPolicy;
@Immutable @Immutable
@SystemApi @SystemApi
public final class UsbPortStatus implements Parcelable { public final class UsbPortStatus implements Parcelable {
private static final String TAG = "UsbPortStatus";
private final int mCurrentMode; private final int mCurrentMode;
private final @UsbPowerRole int mCurrentPowerRole; private final @UsbPowerRole int mCurrentPowerRole;
private final @UsbDataRole int mCurrentDataRole; private final @UsbDataRole int mCurrentDataRole;
private final int mSupportedRoleCombinations; private final int mSupportedRoleCombinations;
private final @ContaminantProtectionStatus int mContaminantProtectionStatus; private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
private final @ContaminantDetectionStatus int mContaminantDetectionStatus; private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
private final boolean mUsbDataEnabled;
/** /**
* Power role: This USB port does not have a power role. * Power role: This USB port does not have a power role.
*/ */
public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE; public static final int POWER_ROLE_NONE = 0;
/** /**
* Power role: This USB port can act as a source (provide power). * Power role: This USB port can act as a source (provide power).
*/ */
public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE; public static final int POWER_ROLE_SOURCE = 1;
/** /**
* Power role: This USB port can act as a sink (receive power). * Power role: This USB port can act as a sink (receive power).
*/ */
public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK; public static final int POWER_ROLE_SINK = 2;
@IntDef(prefix = { "POWER_ROLE_" }, value = { @IntDef(prefix = { "POWER_ROLE_" }, value = {
POWER_ROLE_NONE, POWER_ROLE_NONE,
@@ -69,17 +70,17 @@ public final class UsbPortStatus implements Parcelable {
/** /**
* Power role: This USB port does not have a data role. * Power role: This USB port does not have a data role.
*/ */
public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE; public static final int DATA_ROLE_NONE = 0;
/** /**
* Data role: This USB port can act as a host (access data services). * Data role: This USB port can act as a host (access data services).
*/ */
public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST; public static final int DATA_ROLE_HOST = 1;
/** /**
* Data role: This USB port can act as a device (offer data services). * Data role: This USB port can act as a device (offer data services).
*/ */
public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE; public static final int DATA_ROLE_DEVICE = 2;
@IntDef(prefix = { "DATA_ROLE_" }, value = { @IntDef(prefix = { "DATA_ROLE_" }, value = {
DATA_ROLE_NONE, DATA_ROLE_NONE,
@@ -92,15 +93,7 @@ public final class UsbPortStatus implements Parcelable {
/** /**
* There is currently nothing connected to this USB port. * There is currently nothing connected to this USB port.
*/ */
public static final int MODE_NONE = Constants.PortMode.NONE; public static final int MODE_NONE = 0;
/**
* 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). * This USB port can act as an upstream facing port (device).
@@ -108,7 +101,15 @@ public final class UsbPortStatus implements Parcelable {
* <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and * <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and
* {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well). * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well).
*/ */
public static final int MODE_UFP = Constants.PortMode.UFP; public static final int MODE_UFP = 1 << 0;
/**
* 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 = 1 << 1;
/** /**
* This USB port can act either as an downstream facing port (host) or as * This USB port can act either as an downstream facing port (host) or as
@@ -120,87 +121,76 @@ public final class UsbPortStatus implements Parcelable {
* *
* @hide * @hide
*/ */
public static final int MODE_DUAL = Constants.PortMode.DRP; public static final int MODE_DUAL = MODE_UFP | MODE_DFP;
/** /**
* This USB port can support USB Type-C Audio accessory. * This USB port can support USB Type-C Audio accessory.
*/ */
public static final int MODE_AUDIO_ACCESSORY = public static final int MODE_AUDIO_ACCESSORY = 1 << 2;
android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY;
/** /**
* This USB port can support USB Type-C debug accessory. * This USB port can support USB Type-C debug accessory.
*/ */
public static final int MODE_DEBUG_ACCESSORY = public static final int MODE_DEBUG_ACCESSORY = 1 << 3;
android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
/** /**
* Contaminant presence detection not supported by the device. * Contaminant presence detection not supported by the device.
* @hide * @hide
*/ */
public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED = public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED = 0;
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_SUPPORTED;
/** /**
* Contaminant presence detection supported but disabled. * Contaminant presence detection supported but disabled.
* @hide * @hide
*/ */
public static final int CONTAMINANT_DETECTION_DISABLED = public static final int CONTAMINANT_DETECTION_DISABLED = 1;
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DISABLED;
/** /**
* Contaminant presence enabled but not detected. * Contaminant presence enabled but not detected.
* @hide * @hide
*/ */
public static final int CONTAMINANT_DETECTION_NOT_DETECTED = public static final int CONTAMINANT_DETECTION_NOT_DETECTED = 2;
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_DETECTED;
/** /**
* Contaminant presence enabled and detected. * Contaminant presence enabled and detected.
* @hide * @hide
*/ */
public static final int CONTAMINANT_DETECTION_DETECTED = public static final int CONTAMINANT_DETECTION_DETECTED = 3;
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DETECTED;
/** /**
* Contaminant protection - No action performed upon detection of * Contaminant protection - No action performed upon detection of
* contaminant presence. * contaminant presence.
* @hide * @hide
*/ */
public static final int CONTAMINANT_PROTECTION_NONE = public static final int CONTAMINANT_PROTECTION_NONE = 0;
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.NONE;
/** /**
* Contaminant protection - Port is forced to sink upon detection of * Contaminant protection - Port is forced to sink upon detection of
* contaminant presence. * contaminant presence.
* @hide * @hide
*/ */
public static final int CONTAMINANT_PROTECTION_SINK = public static final int CONTAMINANT_PROTECTION_SINK = 1 << 0;
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SINK;
/** /**
* Contaminant protection - Port is forced to source upon detection of * Contaminant protection - Port is forced to source upon detection of
* contaminant presence. * contaminant presence.
* @hide * @hide
*/ */
public static final int CONTAMINANT_PROTECTION_SOURCE = public static final int CONTAMINANT_PROTECTION_SOURCE = 1 << 1;
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SOURCE;
/** /**
* Contaminant protection - Port is disabled upon detection of * Contaminant protection - Port is disabled upon detection of
* contaminant presence. * contaminant presence.
* @hide * @hide
*/ */
public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE = public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE = 1 << 2;
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_DISABLE;
/** /**
* Contaminant protection - Port is disabled upon detection of * Contaminant protection - Port is disabled upon detection of
* contaminant presence. * contaminant presence.
* @hide * @hide
*/ */
public static final int CONTAMINANT_PROTECTION_DISABLED = public static final int CONTAMINANT_PROTECTION_DISABLED = 1 << 3;
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.DISABLED;
@IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = { @IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
CONTAMINANT_DETECTION_NOT_SUPPORTED, CONTAMINANT_DETECTION_NOT_SUPPORTED,
@@ -231,6 +221,19 @@ public final class UsbPortStatus implements Parcelable {
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@interface UsbPortMode{} @interface UsbPortMode{}
/** @hide */
public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus,
int contaminantDetectionStatus, boolean usbDataEnabled) {
mCurrentMode = currentMode;
mCurrentPowerRole = currentPowerRole;
mCurrentDataRole = currentDataRole;
mSupportedRoleCombinations = supportedRoleCombinations;
mContaminantProtectionStatus = contaminantProtectionStatus;
mContaminantDetectionStatus = contaminantDetectionStatus;
mUsbDataEnabled = usbDataEnabled;
}
/** @hide */ /** @hide */
public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole, public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus, int supportedRoleCombinations, int contaminantProtectionStatus,
@@ -241,6 +244,7 @@ public final class UsbPortStatus implements Parcelable {
mSupportedRoleCombinations = supportedRoleCombinations; mSupportedRoleCombinations = supportedRoleCombinations;
mContaminantProtectionStatus = contaminantProtectionStatus; mContaminantProtectionStatus = contaminantProtectionStatus;
mContaminantDetectionStatus = contaminantDetectionStatus; mContaminantDetectionStatus = contaminantDetectionStatus;
mUsbDataEnabled = true;
} }
/** /**
@@ -323,6 +327,15 @@ public final class UsbPortStatus implements Parcelable {
return mContaminantProtectionStatus; return mContaminantProtectionStatus;
} }
/**
* Returns UsbData status.
*
* @hide
*/
public boolean getUsbDataStatus() {
return mUsbDataEnabled;
}
@NonNull @NonNull
@Override @Override
public String toString() { public String toString() {
@@ -336,6 +349,8 @@ public final class UsbPortStatus implements Parcelable {
+ getContaminantDetectionStatus() + getContaminantDetectionStatus()
+ ", contaminantProtectionStatus=" + ", contaminantProtectionStatus="
+ getContaminantProtectionStatus() + getContaminantProtectionStatus()
+ ", usbDataEnabled="
+ getUsbDataStatus()
+ "}"; + "}";
} }
@@ -352,6 +367,7 @@ public final class UsbPortStatus implements Parcelable {
dest.writeInt(mSupportedRoleCombinations); dest.writeInt(mSupportedRoleCombinations);
dest.writeInt(mContaminantProtectionStatus); dest.writeInt(mContaminantProtectionStatus);
dest.writeInt(mContaminantDetectionStatus); dest.writeInt(mContaminantDetectionStatus);
dest.writeBoolean(mUsbDataEnabled);
} }
public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR = public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -364,9 +380,10 @@ public final class UsbPortStatus implements Parcelable {
int supportedRoleCombinations = in.readInt(); int supportedRoleCombinations = in.readInt();
int contaminantProtectionStatus = in.readInt(); int contaminantProtectionStatus = in.readInt();
int contaminantDetectionStatus = in.readInt(); int contaminantDetectionStatus = in.readInt();
boolean usbDataEnabled = in.readBoolean();
return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole, return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus, supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus); contaminantDetectionStatus, usbDataEnabled);
} }
@Override @Override

View File

@@ -244,7 +244,8 @@ public class DumpUtils {
writeContaminantPresenceStatus(dump, "contaminant_presence_status", writeContaminantPresenceStatus(dump, "contaminant_presence_status",
UsbPortStatusProto.CONTAMINANT_PRESENCE_STATUS, UsbPortStatusProto.CONTAMINANT_PRESENCE_STATUS,
status.getContaminantDetectionStatus()); status.getContaminantDetectionStatus());
dump.write("usb_data_enabled", UsbPortStatusProto.USB_DATA_ENABLED,
status.getUsbDataStatus());
dump.end(token); dump.end(token);
} }
} }

View File

@@ -195,9 +195,19 @@ message UsbIsHeadsetProto {
message UsbPortManagerProto { message UsbPortManagerProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC; option (android.msg_privacy).dest = DEST_AUTOMATIC;
enum HalVersion {
V_UNKNOWN = 0;
V1_0 = 10;
V1_1 = 11;
V1_2 = 12;
V1_3 = 13;
V2 = 20;
}
optional bool is_simulation_active = 1; optional bool is_simulation_active = 1;
repeated UsbPortInfoProto usb_ports = 2; repeated UsbPortInfoProto usb_ports = 2;
optional bool enable_usb_data_signaling = 3; optional bool enable_usb_data_signaling = 3;
optional HalVersion hal_version = 4;
} }
message UsbPortInfoProto { message UsbPortInfoProto {
@@ -253,6 +263,7 @@ message UsbPortStatusProto {
optional DataRole data_role = 4; optional DataRole data_role = 4;
repeated UsbPortStatusRoleCombinationProto role_combinations = 5; repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6; optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6;
optional bool usb_data_enabled = 7;
} }
message UsbPortStatusRoleCombinationProto { message UsbPortStatusRoleCombinationProto {

View File

@@ -29,6 +29,7 @@ java_library_static {
"android.hardware.usb-V1.1-java", "android.hardware.usb-V1.1-java",
"android.hardware.usb-V1.2-java", "android.hardware.usb-V1.2-java",
"android.hardware.usb-V1.3-java", "android.hardware.usb-V1.3-java",
"android.hardware.usb-V1-java",
"android.hardware.usb.gadget-V1.0-java", "android.hardware.usb.gadget-V1.0-java",
"android.hardware.usb.gadget-V1.1-java", "android.hardware.usb.gadget-V1.1-java",
"android.hardware.usb.gadget-V1.2-java", "android.hardware.usb.gadget-V1.2-java",

View File

@@ -16,6 +16,8 @@
package com.android.server.usb; package com.android.server.usb;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED; import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE; import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
@@ -25,6 +27,12 @@ import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
import static android.hardware.usb.UsbPortStatus.MODE_UFP; 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_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
import static com.android.server.usb.hal.port.UsbPortHal.HAL_POWER_ROLE_SOURCE;
import static com.android.server.usb.hal.port.UsbPortHal.HAL_POWER_ROLE_SINK;
import static com.android.server.usb.hal.port.UsbPortHal.HAL_DATA_ROLE_HOST;
import static com.android.server.usb.hal.port.UsbPortHal.HAL_DATA_ROLE_DEVICE;
import static com.android.server.usb.hal.port.UsbPortHal.HAL_MODE_DFP;
import static com.android.server.usb.hal.port.UsbPortHal.HAL_MODE_UFP;
import static com.android.internal.usb.DumpUtils.writePort; import static com.android.internal.usb.DumpUtils.writePort;
import static com.android.internal.usb.DumpUtils.writePortStatus; import static com.android.internal.usb.DumpUtils.writePortStatus;
@@ -38,6 +46,7 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPort;
@@ -74,9 +83,13 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.dump.DualDumpOutputStream; import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.FgThread; import com.android.server.FgThread;
import com.android.server.usb.hal.port.RawPortInfo;
import com.android.server.usb.hal.port.UsbPortHal;
import com.android.server.usb.hal.port.UsbPortHalInstance;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Objects;
/** /**
* Allows trusted components to control the properties of physical USB ports * Allows trusted components to control the properties of physical USB ports
@@ -109,16 +122,9 @@ public class UsbPortManager {
// The system context. // The system context.
private final Context mContext; private final Context mContext;
// Proxy object for the usb hal daemon.
@GuardedBy("mLock")
private IUsb mProxy = null;
// Callback when the UsbPort status is changed by the kernel. // Callback when the UsbPort status is changed by the kernel.
// Mostly due a command sent by the remote Usb device. // Mostly due a command sent by the remote Usb device.
private HALCallback mHALCallback = new HALCallback(null, this); //private HALCallback mHALCallback = new HALCallback(null, this);
// Cookie sent for usb hal death notification.
private static final int USB_HAL_DEATH_COOKIE = 1000;
// Used as the key while sending the bundle to Main thread. // Used as the key while sending the bundle to Main thread.
private static final String PORT_INFO = "port_info"; private static final String PORT_INFO = "port_info";
@@ -156,36 +162,23 @@ public class UsbPortManager {
*/ */
private int mIsPortContaminatedNotificationId; private int mIsPortContaminatedNotificationId;
private boolean mEnableUsbDataSignaling; private UsbPortHal mUsbPortHal;
protected int mCurrentUsbHalVersion;
private long mTransactionId;
public UsbPortManager(Context context) { public UsbPortManager(Context context) {
mContext = context; mContext = context;
try { mUsbPortHal = UsbPortHalInstance.getInstance(this, null);
ServiceNotification serviceNotification = new ServiceNotification(); logAndPrint(Log.DEBUG, null, "getInstance done");
boolean ret = IServiceManager.getService()
.registerForNotifications("android.hardware.usb@1.0::IUsb",
"", serviceNotification);
if (!ret) {
logAndPrint(Log.ERROR, null,
"Failed to register service start notification");
}
} catch (RemoteException e) {
logAndPrintException(null,
"Failed to register service start notification", e);
return;
}
connectToProxy(null);
} }
public void systemReady() { public void systemReady() {
mSystemReady = true; mSystemReady = true;
if (mProxy != null) { if (mUsbPortHal != null) {
mUsbPortHal.systemReady();
try { try {
mProxy.queryPortStatus(); mUsbPortHal.queryPortStatus(++mTransactionId);
mEnableUsbDataSignaling = true; } catch (Exception e) {
} catch (RemoteException e) {
logAndPrintException(null, logAndPrintException(null,
"ServiceStart: Failed to query port status", e); "ServiceStart: Failed to query port status", e);
} }
@@ -340,13 +333,9 @@ public class UsbPortManager {
} }
try { try {
// Oneway call into the hal. Use the castFrom method from HIDL. mUsbPortHal.enableContaminantPresenceDetection(portId, enable, ++mTransactionId);
android.hardware.usb.V1_2.IUsb proxy = android.hardware.usb.V1_2.IUsb.castFrom(mProxy); } catch (Exception e) {
proxy.enableContaminantPresenceDetection(portId, enable);
} catch (RemoteException e) {
logAndPrintException(pw, "Failed to set contaminant detection", e); logAndPrintException(pw, "Failed to set contaminant detection", e);
} catch (ClassCastException e) {
logAndPrintException(pw, "Method only applicable to V1.2 or above implementation", e);
} }
} }
@@ -355,46 +344,79 @@ public class UsbPortManager {
* *
* @param enable enable or disable USB data signaling * @param enable enable or disable USB data signaling
*/ */
public boolean enableUsbDataSignal(boolean enable) { public boolean enableUsbData(@NonNull String portId, boolean enable, int transactionId,
try { @NonNull IUsbOperationInternal callback, IndentingPrintWriter pw) {
mEnableUsbDataSignaling = enable; Objects.requireNonNull(callback);
// Call into the hal. Use the castFrom method from HIDL. Objects.requireNonNull(portId);
android.hardware.usb.V1_3.IUsb proxy = android.hardware.usb.V1_3.IUsb.castFrom(mProxy); final PortInfo portInfo = mPorts.get(portId);
return proxy.enableUsbDataSignal(enable); if (portInfo == null) {
} catch (RemoteException e) { logAndPrint(Log.ERROR, pw, "enableUsbData: No such port: " + portId
logAndPrintException(null, "Failed to set USB data signaling", e); + " opId:" + transactionId);
return false; try {
} catch (ClassCastException e) { callback.onOperationComplete(USB_OPERATION_ERROR_PORT_MISMATCH);
logAndPrintException(null, "Method only applicable to V1.3 or above implementation", e); } catch (RemoteException e) {
logAndPrintException(pw,
"enableUsbData: Failed to call OperationComplete. opId:"
+ transactionId, e);
}
return false; return false;
} }
try {
try {
return mUsbPortHal.enableUsbData(portId, enable, transactionId, callback);
} catch (Exception e) {
logAndPrintException(pw,
"enableUsbData: Failed to invoke enableUsbData. opId:"
+ transactionId , e);
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
}
} catch (RemoteException e) {
logAndPrintException(pw,
"enableUsbData: Failed to call onOperationComplete. opId:"
+ transactionId, e);
}
return false;
} }
/** /**
* Get USB HAL version * Get USB HAL version
* *
* @param none * @param none
* @return {@link UsbManager#USB_HAL_RETRY} returned when hal version
* is yet to be determined.
*/ */
public int getUsbHalVersion() { public int getUsbHalVersion() {
return mCurrentUsbHalVersion; if (mUsbPortHal != null) {
try {
return mUsbPortHal.getUsbHalVersion();
} catch (RemoteException e) {
return UsbManager.USB_HAL_RETRY;
}
}
return UsbManager.USB_HAL_RETRY;
} }
/** private int toHalUsbDataRole(int usbDataRole) {
* update USB HAL version if (usbDataRole == DATA_ROLE_DEVICE)
* return HAL_DATA_ROLE_DEVICE;
* @param none else
*/ return HAL_DATA_ROLE_HOST;
private void updateUsbHalVersion() { }
if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) {
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_3; private int toHalUsbPowerRole(int usbPowerRole) {
} else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) { if (usbPowerRole == POWER_ROLE_SINK)
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_2; return HAL_POWER_ROLE_SINK;
} else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) { else
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_1; return HAL_POWER_ROLE_SOURCE;
} else { }
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_0;
} private int toHalUsbMode(int usbMode) {
logAndPrint(Log.INFO, null, "USB HAL version: " + mCurrentUsbHalVersion); if (usbMode == MODE_UFP)
return HAL_MODE_UFP;
else
return HAL_MODE_DFP;
} }
public void setPortRoles(String portId, int newPowerRole, int newDataRole, public void setPortRoles(String portId, int newPowerRole, int newDataRole,
@@ -473,7 +495,7 @@ public class UsbPortManager {
sim.currentPowerRole = newPowerRole; sim.currentPowerRole = newPowerRole;
sim.currentDataRole = newDataRole; sim.currentDataRole = newDataRole;
updatePortsLocked(pw, null); updatePortsLocked(pw, null);
} else if (mProxy != null) { } else if (mUsbPortHal != null) {
if (currentMode != newMode) { if (currentMode != newMode) {
// Changing the mode will have the side-effect of also changing // Changing the mode will have the side-effect of also changing
// the power and data roles but it might take some time to apply // the power and data roles but it might take some time to apply
@@ -485,44 +507,37 @@ public class UsbPortManager {
logAndPrint(Log.ERROR, pw, "Trying to set the USB port mode: " logAndPrint(Log.ERROR, pw, "Trying to set the USB port mode: "
+ "portId=" + portId + "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newMode)); + ", newMode=" + UsbPort.modeToString(newMode));
PortRole newRole = new PortRole();
newRole.type = PortRoleType.MODE;
newRole.role = newMode;
try { try {
mProxy.switchRole(portId, newRole); mUsbPortHal.switchMode(portId, toHalUsbMode(newMode), ++mTransactionId);
} catch (RemoteException e) { } catch (Exception e) {
logAndPrintException(pw, "Failed to set the USB port mode: " logAndPrintException(pw, "Failed to set the USB port mode: "
+ "portId=" + portId + "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newRole.role), e); + ", newMode=" + UsbPort.modeToString(newMode), e);
} }
} else { } else {
// Change power and data role independently as needed. // Change power and data role independently as needed.
if (currentPowerRole != newPowerRole) { if (currentPowerRole != newPowerRole) {
PortRole newRole = new PortRole();
newRole.type = PortRoleType.POWER_ROLE;
newRole.role = newPowerRole;
try { try {
mProxy.switchRole(portId, newRole); mUsbPortHal.switchPowerRole(portId, toHalUsbPowerRole(newPowerRole),
} catch (RemoteException e) { ++mTransactionId);
} catch (Exception e) {
logAndPrintException(pw, "Failed to set the USB port power role: " logAndPrintException(pw, "Failed to set the USB port power role: "
+ "portId=" + portId + "portId=" + portId
+ ", newPowerRole=" + UsbPort.powerRoleToString + ", newPowerRole=" + UsbPort.powerRoleToString
(newRole.role), (newPowerRole),
e); e);
return; return;
} }
} }
if (currentDataRole != newDataRole) { if (currentDataRole != newDataRole) {
PortRole newRole = new PortRole();
newRole.type = PortRoleType.DATA_ROLE;
newRole.role = newDataRole;
try { try {
mProxy.switchRole(portId, newRole); mUsbPortHal.switchDataRole(portId, toHalUsbDataRole(newDataRole),
} catch (RemoteException e) { ++mTransactionId);
} catch (Exception e) {
logAndPrintException(pw, "Failed to set the USB port data role: " logAndPrintException(pw, "Failed to set the USB port data role: "
+ "portId=" + portId + "portId=" + portId
+ ", newDataRole=" + UsbPort.dataRoleToString(newRole + ", newDataRole=" + UsbPort.dataRoleToString
.role), (newDataRole),
e); e);
} }
} }
@@ -531,6 +546,15 @@ public class UsbPortManager {
} }
} }
public void updatePorts(ArrayList<RawPortInfo> newPortInfo) {
Message message = mHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
message.what = MSG_UPDATE_PORTS;
message.setData(bundle);
mHandler.sendMessage(message);
}
public void addSimulatedPort(String portId, int supportedModes, IndentingPrintWriter pw) { public void addSimulatedPort(String portId, int supportedModes, IndentingPrintWriter pw) {
synchronized (mLock) { synchronized (mLock) {
if (mSimulatedPorts.containsKey(portId)) { if (mSimulatedPorts.containsKey(portId)) {
@@ -662,191 +686,12 @@ public class UsbPortManager {
portInfo.dump(dump, "usb_ports", UsbPortManagerProto.USB_PORTS); portInfo.dump(dump, "usb_ports", UsbPortManagerProto.USB_PORTS);
} }
dump.write("enable_usb_data_signaling", UsbPortManagerProto.ENABLE_USB_DATA_SIGNALING, dump.write("usb_hal_version", UsbPortManagerProto.HAL_VERSION, getUsbHalVersion());
mEnableUsbDataSignaling);
} }
dump.end(token); dump.end(token);
} }
private static class HALCallback extends IUsbCallback.Stub {
public IndentingPrintWriter pw;
public UsbPortManager portManager;
HALCallback(IndentingPrintWriter pw, UsbPortManager portManager) {
this.pw = pw;
this.portManager = portManager;
}
public void notifyPortStatusChange(
ArrayList<android.hardware.usb.V1_0.PortStatus> currentPortStatus, int retval) {
if (!portManager.mSystemReady) {
return;
}
if (retval != Status.SUCCESS) {
logAndPrint(Log.ERROR, pw, "port status enquiry failed");
return;
}
ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
for (android.hardware.usb.V1_0.PortStatus current : currentPortStatus) {
RawPortInfo temp = new RawPortInfo(current.portName,
current.supportedModes, CONTAMINANT_PROTECTION_NONE,
current.currentMode,
current.canChangeMode, current.currentPowerRole,
current.canChangePowerRole,
current.currentDataRole, current.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
newPortInfo.add(temp);
logAndPrint(Log.INFO, pw, "ClientCallback V1_0: " + current.portName);
}
Message message = portManager.mHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
message.what = MSG_UPDATE_PORTS;
message.setData(bundle);
portManager.mHandler.sendMessage(message);
}
public void notifyPortStatusChange_1_1(ArrayList<PortStatus_1_1> currentPortStatus,
int retval) {
if (!portManager.mSystemReady) {
return;
}
if (retval != Status.SUCCESS) {
logAndPrint(Log.ERROR, pw, "port status enquiry failed");
return;
}
ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
int numStatus = currentPortStatus.size();
for (int i = 0; i < numStatus; i++) {
PortStatus_1_1 current = currentPortStatus.get(i);
RawPortInfo temp = new RawPortInfo(current.status.portName,
current.supportedModes, CONTAMINANT_PROTECTION_NONE,
current.currentMode,
current.status.canChangeMode, current.status.currentPowerRole,
current.status.canChangePowerRole,
current.status.currentDataRole, current.status.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
newPortInfo.add(temp);
logAndPrint(Log.INFO, pw, "ClientCallback V1_1: " + current.status.portName);
}
Message message = portManager.mHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
message.what = MSG_UPDATE_PORTS;
message.setData(bundle);
portManager.mHandler.sendMessage(message);
}
public void notifyPortStatusChange_1_2(
ArrayList<PortStatus> currentPortStatus, int retval) {
if (!portManager.mSystemReady) {
return;
}
if (retval != Status.SUCCESS) {
logAndPrint(Log.ERROR, pw, "port status enquiry failed");
return;
}
ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
int numStatus = currentPortStatus.size();
for (int i = 0; i < numStatus; i++) {
PortStatus current = currentPortStatus.get(i);
RawPortInfo temp = new RawPortInfo(current.status_1_1.status.portName,
current.status_1_1.supportedModes,
current.supportedContaminantProtectionModes,
current.status_1_1.currentMode,
current.status_1_1.status.canChangeMode,
current.status_1_1.status.currentPowerRole,
current.status_1_1.status.canChangePowerRole,
current.status_1_1.status.currentDataRole,
current.status_1_1.status.canChangeDataRole,
current.supportsEnableContaminantPresenceProtection,
current.contaminantProtectionStatus,
current.supportsEnableContaminantPresenceDetection,
current.contaminantDetectionStatus);
newPortInfo.add(temp);
logAndPrint(Log.INFO, pw, "ClientCallback V1_2: "
+ current.status_1_1.status.portName);
}
Message message = portManager.mHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
message.what = MSG_UPDATE_PORTS;
message.setData(bundle);
portManager.mHandler.sendMessage(message);
}
public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
if (retval == Status.SUCCESS) {
logAndPrint(Log.INFO, pw, portName + " role switch successful");
} else {
logAndPrint(Log.ERROR, pw, portName + " role switch failed");
}
}
}
final class DeathRecipient implements HwBinder.DeathRecipient {
public IndentingPrintWriter pw;
DeathRecipient(IndentingPrintWriter pw) {
this.pw = pw;
}
@Override
public void serviceDied(long cookie) {
if (cookie == USB_HAL_DEATH_COOKIE) {
logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
synchronized (mLock) {
mProxy = null;
}
}
}
}
final class ServiceNotification extends IServiceNotification.Stub {
@Override
public void onRegistration(String fqName, String name, boolean preexisting) {
logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
connectToProxy(null);
}
}
private void connectToProxy(IndentingPrintWriter pw) {
synchronized (mLock) {
if (mProxy != null) {
return;
}
try {
mProxy = IUsb.getService();
mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
mProxy.setCallback(mHALCallback);
mProxy.queryPortStatus();
updateUsbHalVersion();
} catch (NoSuchElementException e) {
logAndPrintException(pw, "connectToProxy: usb hal service not found."
+ " Did the service fail to start?", e);
} catch (RemoteException e) {
logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
}
}
}
/** /**
* Simulated ports directly add the new roles to mSimulatedPorts before calling. * Simulated ports directly add the new roles to mSimulatedPorts before calling.
* USB hal callback populates and sends the newPortInfo. * USB hal callback populates and sends the newPortInfo.
@@ -869,7 +714,8 @@ public class UsbPortManager {
portInfo.supportsEnableContaminantPresenceProtection, portInfo.supportsEnableContaminantPresenceProtection,
portInfo.contaminantProtectionStatus, portInfo.contaminantProtectionStatus,
portInfo.supportsEnableContaminantPresenceDetection, portInfo.supportsEnableContaminantPresenceDetection,
portInfo.contaminantDetectionStatus, pw); portInfo.contaminantDetectionStatus,
portInfo.usbDataEnabled, pw);
} }
} else { } else {
for (RawPortInfo currentPortInfo : newPortInfo) { for (RawPortInfo currentPortInfo : newPortInfo) {
@@ -881,7 +727,8 @@ public class UsbPortManager {
currentPortInfo.supportsEnableContaminantPresenceProtection, currentPortInfo.supportsEnableContaminantPresenceProtection,
currentPortInfo.contaminantProtectionStatus, currentPortInfo.contaminantProtectionStatus,
currentPortInfo.supportsEnableContaminantPresenceDetection, currentPortInfo.supportsEnableContaminantPresenceDetection,
currentPortInfo.contaminantDetectionStatus, pw); currentPortInfo.contaminantDetectionStatus,
currentPortInfo.usbDataEnabled, pw);
} }
} }
@@ -917,6 +764,7 @@ public class UsbPortManager {
int contaminantProtectionStatus, int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection, boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus, int contaminantDetectionStatus,
boolean usbDataEnabled,
IndentingPrintWriter pw) { IndentingPrintWriter pw) {
// Only allow mode switch capability for dual role ports. // Only allow mode switch capability for dual role ports.
// Validate that the current mode matches the supported modes we expect. // Validate that the current mode matches the supported modes we expect.
@@ -975,7 +823,7 @@ public class UsbPortManager {
currentPowerRole, canChangePowerRole, currentPowerRole, canChangePowerRole,
currentDataRole, canChangeDataRole, currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus, supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus); contaminantDetectionStatus, usbDataEnabled);
mPorts.put(portId, portInfo); mPorts.put(portId, portInfo);
} else { } else {
// Validate that ports aren't changing definition out from under us. // Validate that ports aren't changing definition out from under us.
@@ -1012,7 +860,7 @@ public class UsbPortManager {
currentPowerRole, canChangePowerRole, currentPowerRole, canChangePowerRole,
currentDataRole, canChangeDataRole, currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus, supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus)) { contaminantDetectionStatus, usbDataEnabled)) {
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED; portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
} else { } else {
portInfo.mDisposition = PortInfo.DISPOSITION_READY; portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1141,14 +989,14 @@ public class UsbPortManager {
} }
} }
private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) { public static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
Slog.println(priority, TAG, msg); Slog.println(priority, TAG, msg);
if (pw != null) { if (pw != null) {
pw.println(msg); pw.println(msg);
} }
} }
private static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) { public static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
Slog.e(TAG, msg, e); Slog.e(TAG, msg, e);
if (pw != null) { if (pw != null) {
pw.println(msg + e); pw.println(msg + e);
@@ -1179,7 +1027,7 @@ public class UsbPortManager {
/** /**
* Describes a USB port. * Describes a USB port.
*/ */
private static final class PortInfo { public static final class PortInfo {
public static final int DISPOSITION_ADDED = 0; public static final int DISPOSITION_ADDED = 0;
public static final int DISPOSITION_CHANGED = 1; public static final int DISPOSITION_CHANGED = 1;
public static final int DISPOSITION_READY = 2; public static final int DISPOSITION_READY = 2;
@@ -1224,7 +1072,7 @@ public class UsbPortManager {
!= supportedRoleCombinations) { != supportedRoleCombinations) {
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole, mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE, supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED); UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED, true);
dispositionChanged = true; dispositionChanged = true;
} }
@@ -1243,7 +1091,7 @@ public class UsbPortManager {
int currentPowerRole, boolean canChangePowerRole, int currentPowerRole, boolean canChangePowerRole,
int currentDataRole, boolean canChangeDataRole, int currentDataRole, boolean canChangeDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus, int supportedRoleCombinations, int contaminantProtectionStatus,
int contaminantDetectionStatus) { int contaminantDetectionStatus, boolean usbDataEnabled) {
boolean dispositionChanged = false; boolean dispositionChanged = false;
mCanChangeMode = canChangeMode; mCanChangeMode = canChangeMode;
@@ -1258,10 +1106,12 @@ public class UsbPortManager {
|| mUsbPortStatus.getContaminantProtectionStatus() || mUsbPortStatus.getContaminantProtectionStatus()
!= contaminantProtectionStatus != contaminantProtectionStatus
|| mUsbPortStatus.getContaminantDetectionStatus() || mUsbPortStatus.getContaminantDetectionStatus()
!= contaminantDetectionStatus) { != contaminantDetectionStatus
|| mUsbPortStatus.getUsbDataStatus()
!= usbDataEnabled){
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole, mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus, supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus); contaminantDetectionStatus, usbDataEnabled);
dispositionChanged = true; dispositionChanged = true;
} }
@@ -1290,7 +1140,6 @@ public class UsbPortManager {
UsbPortInfoProto.CONNECTED_AT_MILLIS, mConnectedAtMillis); UsbPortInfoProto.CONNECTED_AT_MILLIS, mConnectedAtMillis);
dump.write("last_connect_duration_millis", dump.write("last_connect_duration_millis",
UsbPortInfoProto.LAST_CONNECT_DURATION_MILLIS, mLastConnectDurationMillis); UsbPortInfoProto.LAST_CONNECT_DURATION_MILLIS, mLastConnectDurationMillis);
dump.end(token); dump.end(token);
} }
@@ -1304,115 +1153,4 @@ public class UsbPortManager {
+ ", lastConnectDurationMillis=" + mLastConnectDurationMillis; + ", lastConnectDurationMillis=" + mLastConnectDurationMillis;
} }
} }
/**
* Used for storing the raw data from the kernel
* Values of the member variables mocked directly incase of emulation.
*/
private static final class RawPortInfo implements Parcelable {
public final String portId;
public final int supportedModes;
public final int supportedContaminantProtectionModes;
public int currentMode;
public boolean canChangeMode;
public int currentPowerRole;
public boolean canChangePowerRole;
public int currentDataRole;
public boolean canChangeDataRole;
public boolean supportsEnableContaminantPresenceProtection;
public int contaminantProtectionStatus;
public boolean supportsEnableContaminantPresenceDetection;
public int contaminantDetectionStatus;
RawPortInfo(String portId, int supportedModes) {
this.portId = portId;
this.supportedModes = supportedModes;
this.supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
this.supportsEnableContaminantPresenceProtection = false;
this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
this.supportsEnableContaminantPresenceDetection = false;
this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
}
RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
int currentMode, boolean canChangeMode,
int currentPowerRole, boolean canChangePowerRole,
int currentDataRole, boolean canChangeDataRole,
boolean supportsEnableContaminantPresenceProtection,
int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus) {
this.portId = portId;
this.supportedModes = supportedModes;
this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
this.currentMode = currentMode;
this.canChangeMode = canChangeMode;
this.currentPowerRole = currentPowerRole;
this.canChangePowerRole = canChangePowerRole;
this.currentDataRole = currentDataRole;
this.canChangeDataRole = canChangeDataRole;
this.supportsEnableContaminantPresenceProtection =
supportsEnableContaminantPresenceProtection;
this.contaminantProtectionStatus = contaminantProtectionStatus;
this.supportsEnableContaminantPresenceDetection =
supportsEnableContaminantPresenceDetection;
this.contaminantDetectionStatus = contaminantDetectionStatus;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(portId);
dest.writeInt(supportedModes);
dest.writeInt(supportedContaminantProtectionModes);
dest.writeInt(currentMode);
dest.writeByte((byte) (canChangeMode ? 1 : 0));
dest.writeInt(currentPowerRole);
dest.writeByte((byte) (canChangePowerRole ? 1 : 0));
dest.writeInt(currentDataRole);
dest.writeByte((byte) (canChangeDataRole ? 1 : 0));
dest.writeBoolean(supportsEnableContaminantPresenceProtection);
dest.writeInt(contaminantProtectionStatus);
dest.writeBoolean(supportsEnableContaminantPresenceDetection);
dest.writeInt(contaminantDetectionStatus);
}
public static final Parcelable.Creator<RawPortInfo> CREATOR =
new Parcelable.Creator<RawPortInfo>() {
@Override
public RawPortInfo createFromParcel(Parcel in) {
String id = in.readString();
int supportedModes = in.readInt();
int supportedContaminantProtectionModes = in.readInt();
int currentMode = in.readInt();
boolean canChangeMode = in.readByte() != 0;
int currentPowerRole = in.readInt();
boolean canChangePowerRole = in.readByte() != 0;
int currentDataRole = in.readInt();
boolean canChangeDataRole = in.readByte() != 0;
boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
int contaminantProtectionStatus = in.readInt();
boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
int contaminantDetectionStatus = in.readInt();
return new RawPortInfo(id, supportedModes,
supportedContaminantProtectionModes, currentMode, canChangeMode,
currentPowerRole, canChangePowerRole,
currentDataRole, canChangeDataRole,
supportsEnableContaminantPresenceProtection,
contaminantProtectionStatus,
supportsEnableContaminantPresenceDetection,
contaminantDetectionStatus);
}
@Override
public RawPortInfo[] newArray(int size) {
return new RawPortInfo[size];
}
};
}
} }

View File

@@ -16,6 +16,7 @@
package com.android.server.usb; package com.android.server.usb;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; 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_HOST;
import static android.hardware.usb.UsbPortStatus.MODE_DFP; import static android.hardware.usb.UsbPortStatus.MODE_DFP;
@@ -35,6 +36,7 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.hardware.usb.IUsbManager; import android.hardware.usb.IUsbManager;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDevice;
@@ -44,6 +46,7 @@ import android.hardware.usb.UsbPortStatus;
import android.os.Binder; import android.os.Binder;
import android.os.Bundle; import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.service.usb.UsbServiceDumpProto; import android.service.usb.UsbServiceDumpProto;
@@ -762,19 +765,30 @@ public class UsbService extends IUsbManager.Stub {
} }
@Override @Override
public boolean enableUsbDataSignal(boolean enable) { public boolean enableUsbData(String portId, boolean enable, int operationId,
IUsbOperationInternal callback) {
Objects.requireNonNull(portId, "enableUsbData: portId must not be null. opId:"
+ operationId);
Objects.requireNonNull(callback, "enableUsbData: callback must not be null. opId:"
+ operationId);
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
boolean wait;
try { try {
if (mPortManager != null) { if (mPortManager != null) {
return mPortManager.enableUsbDataSignal(enable); wait = mPortManager.enableUsbData(portId, enable, operationId, callback, null);
} else { } else {
return false; wait = false;
try {
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
} catch (RemoteException e) {
Slog.e(TAG, "enableUsbData: Failed to call onOperationComplete", e);
}
} }
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
return wait;
} }
@Override @Override

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2021 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 com.android.server.usb.hal.port;
import android.hardware.usb.UsbPortStatus;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Used for storing the raw data from the HAL.
* Values of the member variables mocked directly in case of emulation.
*/
public final class RawPortInfo implements Parcelable {
public final String portId;
public final int supportedModes;
public final int supportedContaminantProtectionModes;
public int currentMode;
public boolean canChangeMode;
public int currentPowerRole;
public boolean canChangePowerRole;
public int currentDataRole;
public boolean canChangeDataRole;
public boolean supportsEnableContaminantPresenceProtection;
public int contaminantProtectionStatus;
public boolean supportsEnableContaminantPresenceDetection;
public int contaminantDetectionStatus;
public boolean usbDataEnabled;
public RawPortInfo(String portId, int supportedModes) {
this.portId = portId;
this.supportedModes = supportedModes;
this.supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
this.supportsEnableContaminantPresenceProtection = false;
this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
this.supportsEnableContaminantPresenceDetection = false;
this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
this.usbDataEnabled = true;
}
public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
int currentMode, boolean canChangeMode,
int currentPowerRole, boolean canChangePowerRole,
int currentDataRole, boolean canChangeDataRole,
boolean supportsEnableContaminantPresenceProtection,
int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus,
boolean usbDataEnabled) {
this.portId = portId;
this.supportedModes = supportedModes;
this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
this.currentMode = currentMode;
this.canChangeMode = canChangeMode;
this.currentPowerRole = currentPowerRole;
this.canChangePowerRole = canChangePowerRole;
this.currentDataRole = currentDataRole;
this.canChangeDataRole = canChangeDataRole;
this.supportsEnableContaminantPresenceProtection =
supportsEnableContaminantPresenceProtection;
this.contaminantProtectionStatus = contaminantProtectionStatus;
this.supportsEnableContaminantPresenceDetection =
supportsEnableContaminantPresenceDetection;
this.contaminantDetectionStatus = contaminantDetectionStatus;
this.usbDataEnabled = usbDataEnabled;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(portId);
dest.writeInt(supportedModes);
dest.writeInt(supportedContaminantProtectionModes);
dest.writeInt(currentMode);
dest.writeByte((byte) (canChangeMode ? 1 : 0));
dest.writeInt(currentPowerRole);
dest.writeByte((byte) (canChangePowerRole ? 1 : 0));
dest.writeInt(currentDataRole);
dest.writeByte((byte) (canChangeDataRole ? 1 : 0));
dest.writeBoolean(supportsEnableContaminantPresenceProtection);
dest.writeInt(contaminantProtectionStatus);
dest.writeBoolean(supportsEnableContaminantPresenceDetection);
dest.writeInt(contaminantDetectionStatus);
dest.writeBoolean(usbDataEnabled);
}
public static final Parcelable.Creator<RawPortInfo> CREATOR =
new Parcelable.Creator<RawPortInfo>() {
@Override
public RawPortInfo createFromParcel(Parcel in) {
String id = in.readString();
int supportedModes = in.readInt();
int supportedContaminantProtectionModes = in.readInt();
int currentMode = in.readInt();
boolean canChangeMode = in.readByte() != 0;
int currentPowerRole = in.readInt();
boolean canChangePowerRole = in.readByte() != 0;
int currentDataRole = in.readInt();
boolean canChangeDataRole = in.readByte() != 0;
boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
int contaminantProtectionStatus = in.readInt();
boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
int contaminantDetectionStatus = in.readInt();
boolean usbDataEnabled = in.readBoolean();
return new RawPortInfo(id, supportedModes,
supportedContaminantProtectionModes, currentMode, canChangeMode,
currentPowerRole, canChangePowerRole,
currentDataRole, canChangeDataRole,
supportsEnableContaminantPresenceProtection,
contaminantProtectionStatus,
supportsEnableContaminantPresenceDetection,
contaminantDetectionStatus, usbDataEnabled);
}
@Override
public RawPortInfo[] newArray(int size) {
return new RawPortInfo[size];
}
};
}

View File

@@ -0,0 +1,476 @@
/*
* Copyright (C) 2021 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 com.android.server.usb.hal.port;
import static android.hardware.usb.UsbManager.USB_HAL_V2_0;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
import static com.android.server.usb.UsbPortManager.logAndPrint;
import static com.android.server.usb.UsbPortManager.logAndPrintException;
import android.annotation.Nullable;
import android.hardware.usb.ContaminantProtectionStatus;
import android.hardware.usb.IUsb;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbManager.UsbHalVersion;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import android.hardware.usb.PortMode;
import android.hardware.usb.Status;
import android.hardware.usb.IUsbCallback;
import android.hardware.usb.PortRole;
import android.hardware.usb.PortStatus;
import android.os.ServiceManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.usb.UsbPortManager;
import com.android.server.usb.hal.port.RawPortInfo;
import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom;
import java.util.NoSuchElementException;
import java.util.Objects;
/**
* Implements the methods to interact with AIDL USB HAL.
*/
public final class UsbPortAidl implements UsbPortHal {
private static final String TAG = UsbPortAidl.class.getSimpleName();
private static final String USB_AIDL_SERVICE =
"android.hardware.usb.IUsb/default";
private static final LongSparseArray<IUsbOperationInternal>
sCallbacks = new LongSparseArray<>();
// Proxy object for the usb hal daemon.
@GuardedBy("mLock")
private IUsb mProxy;
private UsbPortManager mPortManager;
public IndentingPrintWriter mPw;
// Mutex for all mutable shared state.
private final Object mLock = new Object();
// Callback when the UsbPort status is changed by the kernel.
private HALCallback mHALCallback;
private IBinder mBinder;
private boolean mSystemReady;
private long mTransactionId;
public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
synchronized (mLock) {
if (mProxy == null) {
throw new RemoteException("IUsb not initialized yet");
}
}
logAndPrint(Log.INFO, null, "USB HAL AIDL version: USB_HAL_V2_0");
return USB_HAL_V2_0;
}
@Override
public void systemReady() {
mSystemReady = true;
}
public void serviceDied() {
logAndPrint(Log.ERROR, mPw, "Usb AIDL hal service died");
synchronized (mLock) {
mProxy = null;
}
connectToProxy(null);
}
private void connectToProxy(IndentingPrintWriter pw) {
synchronized (mLock) {
if (mProxy != null) {
return;
}
try {
mBinder = ServiceManager.waitForService(USB_AIDL_SERVICE);
mProxy = IUsb.Stub.asInterface(mBinder);
mBinder.linkToDeath(this::serviceDied, 0);
mProxy.setCallback(mHALCallback);
mProxy.queryPortStatus(++mTransactionId);
} catch (NoSuchElementException e) {
logAndPrintException(pw, "connectToProxy: usb hal service not found."
+ " Did the service fail to start?", e);
} catch (RemoteException e) {
logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
}
}
}
static boolean isServicePresent(IndentingPrintWriter pw) {
try {
return ServiceManager.isDeclared(USB_AIDL_SERVICE);
} catch (NoSuchElementException e) {
logAndPrintException(pw, "connectToProxy: usb Aidl hal service not found.", e);
}
return false;
}
public UsbPortAidl(UsbPortManager portManager, IndentingPrintWriter pw) {
mPortManager = Objects.requireNonNull(portManager);
mPw = pw;
mHALCallback = new HALCallback(null, mPortManager, this);
connectToProxy(mPw);
}
@Override
public void enableContaminantPresenceDetection(String portName, boolean enable,
long operationID) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID: "
+ operationID);
return;
}
try {
// Oneway call into the hal. Use the castFrom method from HIDL.
mProxy.enableContaminantPresenceDetection(portName, enable, operationID);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set contaminant detection. opID:"
+ operationID, e);
}
}
}
@Override
public void queryPortStatus(long operationID) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ operationID);
return;
}
try {
mProxy.queryPortStatus(operationID);
} catch (RemoteException e) {
logAndPrintException(null, "ServiceStart: Failed to query port status. opID:"
+ operationID, e);
}
}
}
@Override
public void switchMode(String portId, @HalUsbPortMode int newMode, long operationID) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ operationID);
return;
}
PortRole newRole = new PortRole();
newRole.setMode((byte)newMode);
try {
mProxy.switchRole(portId, newRole, operationID);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set the USB port mode: "
+ "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newMode)
+ "opID:" + operationID, e);
}
}
}
@Override
public void switchPowerRole(String portId, @HalUsbPowerRole int newPowerRole,
long operationID) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ operationID);
return;
}
PortRole newRole = new PortRole();
newRole.setPowerRole((byte)newPowerRole);
try {
mProxy.switchRole(portId, newRole, operationID);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set the USB power role: portId=" + portId
+ ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+ "opID:" + operationID, e);
}
}
}
@Override
public void switchDataRole(String portId, @HalUsbDataRole int newDataRole, long operationID) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ operationID);
return;
}
PortRole newRole = new PortRole();
newRole.setDataRole((byte)newDataRole);
try {
mProxy.switchRole(portId, newRole, operationID);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set the USB data role: portId=" + portId
+ ", newDataRole=" + UsbPort.dataRoleToString(newDataRole)
+ "opID:" + operationID, e);
}
}
}
@Override
public boolean enableUsbData(String portName, boolean enable, long operationID,
IUsbOperationInternal callback) {
Objects.requireNonNull(portName);
Objects.requireNonNull(callback);
long key = operationID;
synchronized (mLock) {
try {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw,
"enableUsbData: 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, "enableUsbData: operationID exists ! opID:"
+ operationID + " key:" + key);
}
try {
sCallbacks.put(key, callback);
mProxy.enableUsbData(portName, enable, key);
} catch (RemoteException e) {
logAndPrintException(mPw,
"enableUsbData: Failed to invoke enableUsbData: portID="
+ portName + "opID:" + operationID, e);
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
sCallbacks.remove(key);
return false;
}
} catch (RemoteException e) {
logAndPrintException(mPw,
"enableUsbData: Failed to call onOperationComplete portID="
+ portName + "opID:" + operationID, e);
sCallbacks.remove(key);
return false;
}
return true;
}
}
private static class HALCallback extends IUsbCallback.Stub {
public IndentingPrintWriter mPw;
public UsbPortManager mPortManager;
public UsbPortAidl mUsbPortAidl;
HALCallback(IndentingPrintWriter pw, UsbPortManager portManager, UsbPortAidl usbPortAidl) {
this.mPw = pw;
this.mPortManager = portManager;
this.mUsbPortAidl = usbPortAidl;
}
/**
* Converts from AIDL defined mode constants to UsbPortStatus constants.
* AIDL does not gracefully support bitfield when combined with enums.
*/
private int toPortMode(byte aidlPortMode) {
switch (aidlPortMode) {
case PortMode.NONE:
return UsbPortStatus.MODE_NONE;
case PortMode.UFP:
return UsbPortStatus.MODE_UFP;
case PortMode.DFP:
return UsbPortStatus.MODE_DFP;
case PortMode.DRP:
return UsbPortStatus.MODE_DUAL;
case PortMode.AUDIO_ACCESSORY:
return UsbPortStatus.MODE_AUDIO_ACCESSORY;
case PortMode.DEBUG_ACCESSORY:
return UsbPortStatus.MODE_DEBUG_ACCESSORY;
default:
UsbPortManager.logAndPrint(Log.ERROR, mPw, "Unrecognized aidlPortMode:"
+ aidlPortMode);
return UsbPortStatus.MODE_NONE;
}
}
private int toSupportedModes(byte[] aidlPortModes) {
int supportedModes = UsbPortStatus.MODE_NONE;
for (byte aidlPortMode : aidlPortModes) {
supportedModes |= toPortMode(aidlPortMode);
}
return supportedModes;
}
/**
* Converts from AIDL defined contaminant protection constants to UsbPortStatus constants.
* AIDL does not gracefully support bitfield when combined with enums.
* Common to both ContaminantProtectionMode and ContaminantProtectionStatus.
*/
private int toContaminantProtectionStatus(byte aidlContaminantProtection) {
switch (aidlContaminantProtection) {
case ContaminantProtectionStatus.NONE:
return UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
case ContaminantProtectionStatus.FORCE_SINK:
return UsbPortStatus.CONTAMINANT_PROTECTION_SINK;
case ContaminantProtectionStatus.FORCE_SOURCE:
return UsbPortStatus.CONTAMINANT_PROTECTION_SOURCE;
case ContaminantProtectionStatus.FORCE_DISABLE:
return UsbPortStatus.CONTAMINANT_PROTECTION_FORCE_DISABLE;
case ContaminantProtectionStatus.DISABLED:
return UsbPortStatus.CONTAMINANT_PROTECTION_DISABLED;
default:
UsbPortManager.logAndPrint(Log.ERROR, mPw,
"Unrecognized aidlContaminantProtection:"
+ aidlContaminantProtection);
return UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
}
}
private int toSupportedContaminantProtectionModes(byte[] aidlModes) {
int supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
for (byte aidlMode : aidlModes) {
supportedContaminantProtectionModes |= toContaminantProtectionStatus(aidlMode);
}
return supportedContaminantProtectionModes;
}
@Override
public void notifyPortStatusChange(
android.hardware.usb.PortStatus[] currentPortStatus, int retval) {
if (!mUsbPortAidl.mSystemReady) {
return;
}
if (retval != Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
return;
}
ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
int numStatus = currentPortStatus.length;
for (int i = 0; i < numStatus; i++) {
PortStatus current = currentPortStatus[i];
RawPortInfo temp = new RawPortInfo(current.portName,
toSupportedModes(current.supportedModes),
toSupportedContaminantProtectionModes(current
.supportedContaminantProtectionModes),
toPortMode(current.currentMode),
current.canChangeMode,
current.currentPowerRole,
current.canChangePowerRole,
current.currentDataRole,
current.canChangeDataRole,
current.supportsEnableContaminantPresenceProtection,
toContaminantProtectionStatus(current.contaminantProtectionStatus),
current.supportsEnableContaminantPresenceDetection,
current.contaminantDetectionStatus,
current.usbDataEnabled);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback AIDL V1: "
+ current.portName);
}
mPortManager.updatePorts(newPortInfo);
}
@Override
public void notifyRoleSwitchStatus(String portName, PortRole role, int retval,
long operationID) {
if (retval == Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.INFO, mPw, portName
+ " role switch successful. opID:"
+ operationID);
} else {
UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + " role switch failed. err:"
+ retval
+ "opID:" + operationID);
}
}
@Override
public void notifyQueryPortStatus(String portName, int retval, long operationID) {
if (retval == Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.INFO, mPw, portName + ": opID:"
+ operationID + " successful");
} else {
UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + ": opID:"
+ operationID + " failed. err:" + retval);
}
}
@Override
public void notifyEnableUsbDataStatus(String portName, boolean enable, int retval,
long operationID) {
if (retval == Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyEnableUsbDataStatus:"
+ portName + ": opID:"
+ operationID + " enable:" + enable);
} 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,
"notifyEnableUsbDataStatus: Failed to call onOperationComplete",
e);
}
}
@Override
public void notifyContaminantEnabledStatus(String portName, boolean enable, int retval,
long operationID) {
if (retval == Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyContaminantEnabledStatus:"
+ portName + ": opID:"
+ operationID + " enable:" + enable);
} else {
UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
+ "notifyContaminantEnabledStatus: opID:"
+ operationID + " failed. err:" + retval);
}
}
@Override
public String getInterfaceHash() {
return IUsbCallback.HASH;
}
@Override
public int getInterfaceVersion() {
return IUsbCallback.VERSION;
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2021 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 com.android.server.usb.hal.port;
import android.annotation.IntDef;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbManager.UsbHalVersion;
import android.os.RemoteException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.String;
/**
* @hide
*/
public interface UsbPortHal {
/**
* Power role: This USB port can act as a source (provide power).
* @hide
*/
public static final int HAL_POWER_ROLE_SOURCE = 1;
/**
* Power role: This USB port can act as a sink (receive power).
* @hide
*/
public static final int HAL_POWER_ROLE_SINK = 2;
@IntDef(prefix = { "HAL_POWER_ROLE_" }, value = {
HAL_POWER_ROLE_SOURCE,
HAL_POWER_ROLE_SINK
})
@Retention(RetentionPolicy.SOURCE)
@interface HalUsbPowerRole{}
/**
* Data role: This USB port can act as a host (access data services).
* @hide
*/
public static final int HAL_DATA_ROLE_HOST = 1;
/**
* Data role: This USB port can act as a device (offer data services).
* @hide
*/
public static final int HAL_DATA_ROLE_DEVICE = 2;
@IntDef(prefix = { "HAL_DATA_ROLE_" }, value = {
HAL_DATA_ROLE_HOST,
HAL_DATA_ROLE_DEVICE
})
@Retention(RetentionPolicy.SOURCE)
@interface HalUsbDataRole{}
/**
* This USB port can act as a downstream facing port (host).
*
* @hide
*/
public static final int HAL_MODE_DFP = 1;
/**
* This USB port can act as an upstream facing port (device).
*
* @hide
*/
public static final int HAL_MODE_UFP = 2;
@IntDef(prefix = { "HAL_MODE_" }, value = {
HAL_MODE_DFP,
HAL_MODE_UFP,
})
@Retention(RetentionPolicy.SOURCE)
@interface HalUsbPortMode{}
/**
* UsbPortManager would call this when the system is done booting.
*/
public void systemReady();
/**
* Invoked to enable/disable contaminant presence detection on the USB port.
*
* @param portName Port Identifier.
* @param enable Enable contaminant presence detection when true.
* Disable when false.
* @param transactionId Used for tracking the current request and is passed down to the HAL
* implementation as needed.
*/
public void enableContaminantPresenceDetection(String portName, boolean enable,
long transactionId);
/**
* Invoked to query port status of all the ports.
*
* @param transactionId Used for tracking the current request and is passed down to the HAL
* implementation as needed.
*/
public void queryPortStatus(long transactionId);
/**
* Invoked to switch USB port mode.
*
* @param portName Port Identifier.
* @param mode New mode that the port is switching into.
* @param transactionId Used for tracking the current request and is passed down to the HAL
* implementation as needed.
*/
public void switchMode(String portName, @HalUsbPortMode int mode, long transactionId);
/**
* Invoked to switch USB port power role.
*
* @param portName Port Identifier.
* @param powerRole New power role that the port is switching into.
* @param transactionId Used for tracking the current request and is passed down to the HAL
* implementation as needed.
*/
public void switchPowerRole(String portName, @HalUsbPowerRole int powerRole,
long transactionId);
/**
* Invoked to switch USB port data role.
*
* @param portName Port Identifier.
* @param dataRole New data role that the port is switching into.
* @param transactionId Used for tracking the current request and is passed down to the HAL
* implementation as needed.
*/
public void switchDataRole(String portName, @HalUsbDataRole int dataRole, long transactionId);
/**
* Invoked to query the version of current hal implementation.
*/
public @UsbHalVersion int getUsbHalVersion() throws RemoteException;
/**
* Invoked to enable/disable UsbData on the specified port.
*
* @param portName Port Identifier.
* @param enable Enable USB data when true.
* Disable when false.
* @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 when the operation is complete.
* @return True when the operation is asynchronous. The caller of
* {@link UsbOperationCallbackInternal} must therefore call
* {@link UsbOperationCallbackInternal#waitForOperationComplete} for processing
* the result.
* False when the operation is synchronous. Caller can proceed reading the result
* through {@link UsbOperationCallbackInternal#getStatus}
*/
public boolean enableUsbData(String portName, boolean enable, long transactionId,
IUsbOperationInternal callback);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2021 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 com.android.server.usb.hal.port;
import static com.android.server.usb.UsbPortManager.logAndPrint;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.usb.hal.port.UsbPortHidl;
import com.android.server.usb.hal.port.UsbPortAidl;
import com.android.server.usb.UsbPortManager;
import android.util.Log;
/**
* Helper class that queries the underlying hal layer to populate UsbPortHal instance.
*/
public final class UsbPortHalInstance {
public static UsbPortHal getInstance(UsbPortManager portManager, IndentingPrintWriter pw) {
logAndPrint(Log.DEBUG, null, "Querying USB HAL version");
if (UsbPortHidl.isServicePresent(null)) {
logAndPrint(Log.INFO, null, "USB HAL HIDL present");
return new UsbPortHidl(portManager, pw);
}
if (UsbPortAidl.isServicePresent(null)) {
logAndPrint(Log.INFO, null, "USB HAL AIDL present");
return new UsbPortAidl(portManager, pw);
}
return null;
}
}

View File

@@ -0,0 +1,471 @@
/*
* Copyright (C) 2021 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 com.android.server.usb.hal.port;
import static android.hardware.usb.UsbManager.USB_HAL_NOT_SUPPORTED;
import static android.hardware.usb.UsbManager.USB_HAL_V1_0;
import static android.hardware.usb.UsbManager.USB_HAL_V1_1;
import static android.hardware.usb.UsbManager.USB_HAL_V1_2;
import static android.hardware.usb.UsbManager.USB_HAL_V1_3;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED;
import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
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.server.usb.UsbPortManager.logAndPrint;
import static com.android.server.usb.UsbPortManager.logAndPrintException;
import android.annotation.Nullable;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbManager.UsbHalVersion;
import android.hardware.usb.UsbPort;
import android.hardware.usb.V1_0.IUsb;
import android.hardware.usb.V1_0.PortRoleType;
import android.hardware.usb.V1_0.Status;
import android.hardware.usb.V1_1.PortStatus_1_1;
import android.hardware.usb.V1_2.IUsbCallback;
import android.hardware.usb.V1_0.PortRole;
import android.hardware.usb.V1_2.PortStatus;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
import android.os.IHwBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.usb.UsbPortManager;
import com.android.server.usb.hal.port.RawPortInfo;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.Objects;
/**
*
*/
public final class UsbPortHidl implements UsbPortHal {
private static final String TAG = UsbPortHidl.class.getSimpleName();
// Cookie sent for usb hal death notification.
private static final int USB_HAL_DEATH_COOKIE = 1000;
// Proxy object for the usb hal daemon.
@GuardedBy("mLock")
private IUsb mProxy;
private UsbPortManager mPortManager;
public IndentingPrintWriter mPw;
// Mutex for all mutable shared state.
private final Object mLock = new Object();
// Callback when the UsbPort status is changed by the kernel.
private HALCallback mHALCallback;
private boolean mSystemReady;
// Workaround since HIDL HAL versions report UsbDataEnabled status in UsbPortStatus;
private static boolean sUsbDataEnabled = true;
public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
int version;
synchronized(mLock) {
if (mProxy == null) {
throw new RemoteException("IUsb not initialized yet");
}
if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) {
version = USB_HAL_V1_3;
} else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) {
version = USB_HAL_V1_2;
} else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) {
version = USB_HAL_V1_1;
} else {
version = USB_HAL_V1_0;
}
logAndPrint(Log.INFO, null, "USB HAL HIDL version: " + version);
return version;
}
}
final class DeathRecipient implements IHwBinder.DeathRecipient {
public IndentingPrintWriter pw;
DeathRecipient(IndentingPrintWriter pw) {
this.pw = pw;
}
@Override
public void serviceDied(long cookie) {
if (cookie == USB_HAL_DEATH_COOKIE) {
logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
synchronized (mLock) {
mProxy = null;
}
}
}
}
final class ServiceNotification extends IServiceNotification.Stub {
@Override
public void onRegistration(String fqName, String name, boolean preexisting) {
logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
connectToProxy(null);
}
}
private void connectToProxy(IndentingPrintWriter pw) {
synchronized (mLock) {
if (mProxy != null) {
return;
}
try {
mProxy = IUsb.getService();
mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
mProxy.setCallback(mHALCallback);
mProxy.queryPortStatus();
//updateUsbHalVersion();
} catch (NoSuchElementException e) {
logAndPrintException(pw, "connectToProxy: usb hal service not found."
+ " Did the service fail to start?", e);
} catch (RemoteException e) {
logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
}
}
}
@Override
public void systemReady() {
mSystemReady = true;
}
static boolean isServicePresent(IndentingPrintWriter pw) {
try {
IUsb.getService(true);
} catch (NoSuchElementException e) {
logAndPrintException(pw, "connectToProxy: usb hidl hal service not found.", e);
return false;
} catch (RemoteException e) {
logAndPrintException(pw, "IUSB hal service present but failed to get service", e);
}
return true;
}
public UsbPortHidl(UsbPortManager portManager, IndentingPrintWriter pw) {
mPortManager = Objects.requireNonNull(portManager);
mPw = pw;
mHALCallback = new HALCallback(null, mPortManager, this);
try {
ServiceNotification serviceNotification = new ServiceNotification();
boolean ret = IServiceManager.getService()
.registerForNotifications("android.hardware.usb@1.0::IUsb",
"", serviceNotification);
if (!ret) {
logAndPrint(Log.ERROR, null,
"Failed to register service start notification");
}
} catch (RemoteException e) {
logAndPrintException(null,
"Failed to register service start notification", e);
return;
}
connectToProxy(mPw);
}
@Override
public void enableContaminantPresenceDetection(String portName, boolean enable,
long transactionId) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
return;
}
try {
// Oneway call into the hal. Use the castFrom method from HIDL.
android.hardware.usb.V1_2.IUsb proxy =
android.hardware.usb.V1_2.IUsb.castFrom(mProxy);
proxy.enableContaminantPresenceDetection(portName, enable);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set contaminant detection", e);
} catch (ClassCastException e) {
logAndPrintException(mPw, "Method only applicable to V1.2 or above implementation",
e);
}
}
}
@Override
public void queryPortStatus(long transactionId) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
return;
}
try {
mProxy.queryPortStatus();
} catch (RemoteException e) {
logAndPrintException(null, "ServiceStart: Failed to query port status", e);
}
}
}
@Override
public void switchMode(String portId, @HalUsbPortMode int newMode, long transactionId) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
return;
}
PortRole newRole = new PortRole();
newRole.type = PortRoleType.MODE;
newRole.role = newMode;
try {
mProxy.switchRole(portId, newRole);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set the USB port mode: "
+ "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newRole.role), e);
}
}
}
@Override
public void switchPowerRole(String portId, @HalUsbPowerRole int newPowerRole,
long transactionId) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
return;
}
PortRole newRole = new PortRole();
newRole.type = PortRoleType.POWER_ROLE;
newRole.role = newPowerRole;
try {
mProxy.switchRole(portId, newRole);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set the USB power role: portId=" + portId
+ ", newPowerRole=" + UsbPort.powerRoleToString(newRole.role), e);
}
}
}
@Override
public void switchDataRole(String portId, @HalUsbDataRole int newDataRole, long transactionId) {
synchronized (mLock) {
if (mProxy == null) {
logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
return;
}
PortRole newRole = new PortRole();
newRole.type = PortRoleType.DATA_ROLE;
newRole.role = newDataRole;
try {
mProxy.switchRole(portId, newRole);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to set the USB data role: portId=" + portId
+ ", newDataRole=" + UsbPort.dataRoleToString(newRole.role), e);
}
}
}
@Override
public boolean enableUsbData(String portName, boolean enable, long transactionId,
IUsbOperationInternal callback) {
int halVersion;
try {
halVersion = getUsbHalVersion();
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to query USB HAL version. opID:"
+ transactionId
+ " portId:" + portName, e);
return false;
}
if (halVersion != USB_HAL_V1_3) {
try {
callback.onOperationComplete(USB_OPERATION_ERROR_NOT_SUPPORTED);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+ transactionId
+ " portId:" + portName, e);
}
return false;
}
boolean success;
synchronized(mLock) {
try {
android.hardware.usb.V1_3.IUsb proxy
= android.hardware.usb.V1_3.IUsb.castFrom(mProxy);
success = proxy.enableUsbDataSignal(enable);
} catch (RemoteException e) {
logAndPrintException(mPw, "Failed enableUsbData: opId:" + transactionId
+ " portId=" + portName , e);
try {
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
} catch (RemoteException r) {
logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+ transactionId
+ " portId:" + portName, r);
}
return false;
}
}
if (success) {
sUsbDataEnabled = enable;
}
try {
callback.onOperationComplete(success
? USB_OPERATION_SUCCESS
: USB_OPERATION_ERROR_INTERNAL);
} catch (RemoteException r) {
logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+ transactionId
+ " portId:" + portName, r);
}
return false;
}
private static class HALCallback extends IUsbCallback.Stub {
public IndentingPrintWriter mPw;
public UsbPortManager mPortManager;
public UsbPortHidl mUsbPortHidl;
HALCallback(IndentingPrintWriter pw, UsbPortManager portManager, UsbPortHidl usbPortHidl) {
this.mPw = pw;
this.mPortManager = portManager;
this.mUsbPortHidl = usbPortHidl;
}
public void notifyPortStatusChange(
ArrayList<android.hardware.usb.V1_0.PortStatus> currentPortStatus, int retval) {
if (!mUsbPortHidl.mSystemReady) {
return;
}
if (retval != Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
return;
}
ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
for (android.hardware.usb.V1_0.PortStatus current : currentPortStatus) {
RawPortInfo temp = new RawPortInfo(current.portName,
current.supportedModes, CONTAMINANT_PROTECTION_NONE,
current.currentMode,
current.canChangeMode, current.currentPowerRole,
current.canChangePowerRole,
current.currentDataRole, current.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataEnabled);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
+ current.portName);
}
mPortManager.updatePorts(newPortInfo);
}
public void notifyPortStatusChange_1_1(ArrayList<PortStatus_1_1> currentPortStatus,
int retval) {
if (!mUsbPortHidl.mSystemReady) {
return;
}
if (retval != Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
return;
}
ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
int numStatus = currentPortStatus.size();
for (int i = 0; i < numStatus; i++) {
PortStatus_1_1 current = currentPortStatus.get(i);
RawPortInfo temp = new RawPortInfo(current.status.portName,
current.supportedModes, CONTAMINANT_PROTECTION_NONE,
current.currentMode,
current.status.canChangeMode, current.status.currentPowerRole,
current.status.canChangePowerRole,
current.status.currentDataRole, current.status.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataEnabled);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
+ current.status.portName);
}
mPortManager.updatePorts(newPortInfo);
}
public void notifyPortStatusChange_1_2(
ArrayList<PortStatus> currentPortStatus, int retval) {
if (!mUsbPortHidl.mSystemReady) {
return;
}
if (retval != Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
return;
}
ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
int numStatus = currentPortStatus.size();
for (int i = 0; i < numStatus; i++) {
PortStatus current = currentPortStatus.get(i);
RawPortInfo temp = new RawPortInfo(current.status_1_1.status.portName,
current.status_1_1.supportedModes,
current.supportedContaminantProtectionModes,
current.status_1_1.currentMode,
current.status_1_1.status.canChangeMode,
current.status_1_1.status.currentPowerRole,
current.status_1_1.status.canChangePowerRole,
current.status_1_1.status.currentDataRole,
current.status_1_1.status.canChangeDataRole,
current.supportsEnableContaminantPresenceProtection,
current.contaminantProtectionStatus,
current.supportsEnableContaminantPresenceDetection,
current.contaminantDetectionStatus,
sUsbDataEnabled);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
+ current.status_1_1.status.portName);
}
mPortManager.updatePorts(newPortInfo);
}
public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
if (retval == Status.SUCCESS) {
UsbPortManager.logAndPrint(Log.INFO, mPw, portName + " role switch successful");
} else {
UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + " role switch failed");
}
}
}
}