Merge changes from topics "199357330", "200993386"
* changes: Add limitPowerTransfer SystemAPI to UsbPort Support IUsb AIDL interface
This commit is contained in:
committed by
Android (Google) Code Review
commit
da433c60c1
@@ -147,10 +147,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_UNKNOWN = -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_1 = 11; // 0xb
|
||||
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_V2_0 = 20; // 0x14
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5086,8 +5086,20 @@ package android.hardware.usb {
|
||||
}
|
||||
|
||||
public final class UsbPort {
|
||||
method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableLimitPowerTransfer(boolean);
|
||||
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 @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
|
||||
field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1; // 0x1
|
||||
field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED = 2; // 0x2
|
||||
field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER = 4; // 0x4
|
||||
field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH = 3; // 0x3
|
||||
field public static final int ENABLE_LIMIT_POWER_TRANSFER_SUCCESS = 0; // 0x0
|
||||
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 {
|
||||
@@ -5097,6 +5109,7 @@ package android.hardware.usb {
|
||||
method public int getCurrentPowerRole();
|
||||
method public int getSupportedRoleCombinations();
|
||||
method public boolean isConnected();
|
||||
method public boolean isPowerTransferLimited();
|
||||
method public boolean isRoleCombinationSupported(int, int);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.UsbPortStatus> CREATOR;
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.hardware.usb;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.hardware.usb.IUsbOperationInternal;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.ParcelableUsbPort;
|
||||
@@ -136,7 +137,7 @@ interface IUsbManager
|
||||
void resetUsbGadget();
|
||||
|
||||
/* 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. */
|
||||
int getUsbHalVersion();
|
||||
@@ -156,9 +157,14 @@ interface IUsbManager
|
||||
/* Sets the port's current role. */
|
||||
void setPortRoles(in String portId, int powerRole, int dataRole);
|
||||
|
||||
/* Limit power transfer in & out of the port within the allowed limit by the USB
|
||||
* specification.
|
||||
*/
|
||||
void enableLimitPowerTransfer(in String portId, boolean limit, int operationId, in IUsbOperationInternal callback);
|
||||
|
||||
/* Enable/disable contaminant detection */
|
||||
void enableContaminantDetection(in String portId, boolean enable);
|
||||
|
||||
/* Sets USB device connection handler. */
|
||||
void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
|
||||
/* Sets USB device connection handler. */
|
||||
void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
|
||||
}
|
||||
|
||||
24
core/java/android/hardware/usb/IUsbOperationInternal.aidl
Normal file
24
core/java/android/hardware/usb/IUsbOperationInternal.aidl
Normal 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);
|
||||
}
|
||||
@@ -36,6 +36,8 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.hardware.usb.gadget.V1_0.GadgetFunction;
|
||||
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.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
@@ -48,6 +50,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
@@ -516,6 +519,14 @@ public class UsbManager {
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
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.
|
||||
*
|
||||
@@ -556,6 +567,14 @@ public class UsbManager {
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
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)}
|
||||
* {@hide}
|
||||
@@ -665,6 +684,7 @@ public class UsbManager {
|
||||
USB_HAL_V1_1,
|
||||
USB_HAL_V1_2,
|
||||
USB_HAL_V1_3,
|
||||
USB_HAL_V2_0,
|
||||
})
|
||||
public @interface UsbHalVersion {}
|
||||
|
||||
@@ -1169,8 +1189,9 @@ public class UsbManager {
|
||||
/**
|
||||
* Enable/Disable the USB data signaling.
|
||||
* <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.
|
||||
* Call UsbPort API if the device has more than one UsbPort.
|
||||
* </p>
|
||||
*
|
||||
* @param enable enable or disable USB data signaling
|
||||
@@ -1181,11 +1202,11 @@ public class UsbManager {
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.MANAGE_USB)
|
||||
public boolean enableUsbDataSignal(boolean enable) {
|
||||
try {
|
||||
return mService.enableUsbDataSignal(enable);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
List<UsbPort> usbPorts = getPorts();
|
||||
if (usbPorts.size() == 1) {
|
||||
return usbPorts.get(0).enableUsbData(enable) == UsbPort.ENABLE_USB_DATA_SUCCESS;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1270,6 +1291,73 @@ public class UsbManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be called by {@link UsbPort#enableLimitPowerTransfer}.
|
||||
* <p>
|
||||
* limits or restores power transfer in and out of USB port.
|
||||
*
|
||||
* @param port USB port for which power transfer has to be limited or restored.
|
||||
* @param limit limit power transfer when true.
|
||||
* relax power transfer restrictions when false.
|
||||
* @param operationId operationId for the request.
|
||||
* @param callback callback object to be invoked when the operation is complete.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.MANAGE_USB)
|
||||
void enableLimitPowerTransfer(@NonNull UsbPort port, boolean limit, int operationId,
|
||||
IUsbOperationInternal callback) {
|
||||
Objects.requireNonNull(port, "enableLimitPowerTransfer:port must not be null. opId:"
|
||||
+ operationId);
|
||||
try {
|
||||
mService.enableLimitPowerTransfer(port.getId(), limit, operationId, callback);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "enableLimitPowerTransfer failed. opId:" + operationId, e);
|
||||
try {
|
||||
callback.onOperationComplete(UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL);
|
||||
} catch (RemoteException r) {
|
||||
Log.e(TAG, "enableLimitPowerTransfer failed to call onOperationComplete. opId:"
|
||||
+ operationId, r);
|
||||
}
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be called by {@link UsbPort#enableUsbData}.
|
||||
* <p>
|
||||
* Enables or disables USB data on the specific port.
|
||||
*
|
||||
* @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.
|
||||
* <p>
|
||||
|
||||
131
core/java/android/hardware/usb/UsbOperationInternal.java
Normal file
131
core/java/android/hardware/usb/UsbOperationInternal.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
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_DISABLED;
|
||||
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 android.Manifest;
|
||||
import android.annotation.CheckResult;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.hardware.usb.UsbOperationInternal;
|
||||
import android.hardware.usb.V1_0.Constants;
|
||||
import android.os.Binder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Represents a physical USB port and describes its characteristics.
|
||||
@@ -51,6 +63,7 @@ import java.util.Objects;
|
||||
*/
|
||||
@SystemApi
|
||||
public final class UsbPort {
|
||||
private static final String TAG = "UsbPort";
|
||||
private final String mId;
|
||||
private final int mSupportedModes;
|
||||
private final UsbManager mUsbManager;
|
||||
@@ -64,6 +77,83 @@ public final class UsbPort {
|
||||
*/
|
||||
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{}
|
||||
|
||||
/**
|
||||
* The {@link #enableLimitPowerTransfer} request was successfully completed.
|
||||
*/
|
||||
public static final int ENABLE_LIMIT_POWER_TRANSFER_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* The {@link #enableLimitPowerTransfer} request failed due to internal error.
|
||||
*/
|
||||
public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1;
|
||||
|
||||
/**
|
||||
* The {@link #enableLimitPowerTransfer} request failed as it's not supported.
|
||||
*/
|
||||
public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED = 2;
|
||||
|
||||
/**
|
||||
* The {@link #enableLimitPowerTransfer} request failed as port id mismatched.
|
||||
*/
|
||||
public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH = 3;
|
||||
|
||||
/**
|
||||
* The {@link #enableLimitPowerTransfer} request failed due to other reasons.
|
||||
*/
|
||||
public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER = 4;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "ENABLE_LIMIT_POWER_TRANSFER_" }, value = {
|
||||
ENABLE_LIMIT_POWER_TRANSFER_SUCCESS,
|
||||
ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL,
|
||||
ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED,
|
||||
ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH,
|
||||
ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface EnableLimitPowerTransferStatus{}
|
||||
|
||||
/** @hide */
|
||||
public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
|
||||
int supportedContaminantProtectionModes,
|
||||
@@ -157,7 +247,7 @@ public final class UsbPort {
|
||||
* {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
|
||||
* </p><p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
@@ -176,6 +266,88 @@ public final class UsbPort {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits power transfer In and out of the port.
|
||||
* <p>
|
||||
* Disables charging and limits sourcing power(when permitted by the USB spec) until
|
||||
* port disconnect event.
|
||||
* </p>
|
||||
* @param enable limits power transfer when true.
|
||||
* @return {@link #ENABLE_LIMIT_POWER_TRANSFER_SUCCESS} when request completes successfully or
|
||||
* {@link #ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL} when request fails due to
|
||||
* internal error or
|
||||
* {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED} when not supported or
|
||||
* {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH} when request fails due to
|
||||
* port id mismatch or
|
||||
* {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER} when fails due to other reasons.
|
||||
*/
|
||||
@CheckResult
|
||||
@RequiresPermission(Manifest.permission.MANAGE_USB)
|
||||
public @EnableLimitPowerTransferStatus int enableLimitPowerTransfer(boolean enable) {
|
||||
// UID is added To minimize operationID overlap between two different packages.
|
||||
int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
|
||||
Log.i(TAG, "enableLimitPowerTransfer opId:" + operationId
|
||||
+ " callingUid:" + Binder.getCallingUid());
|
||||
UsbOperationInternal opCallback =
|
||||
new UsbOperationInternal(operationId, mId);
|
||||
mUsbManager.enableLimitPowerTransfer(this, enable, operationId, opCallback);
|
||||
opCallback.waitForOperationComplete();
|
||||
int result = opCallback.getStatus();
|
||||
switch (result) {
|
||||
case USB_OPERATION_SUCCESS:
|
||||
return ENABLE_LIMIT_POWER_TRANSFER_SUCCESS;
|
||||
case USB_OPERATION_ERROR_INTERNAL:
|
||||
return ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL;
|
||||
case USB_OPERATION_ERROR_NOT_SUPPORTED:
|
||||
return ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED;
|
||||
case USB_OPERATION_ERROR_PORT_MISMATCH:
|
||||
return ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH;
|
||||
default:
|
||||
return ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
**/
|
||||
|
||||
@@ -19,7 +19,6 @@ package android.hardware.usb;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.hardware.usb.V1_0.Constants;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -36,27 +35,30 @@ import java.lang.annotation.RetentionPolicy;
|
||||
@Immutable
|
||||
@SystemApi
|
||||
public final class UsbPortStatus implements Parcelable {
|
||||
private static final String TAG = "UsbPortStatus";
|
||||
private final int mCurrentMode;
|
||||
private final @UsbPowerRole int mCurrentPowerRole;
|
||||
private final @UsbDataRole int mCurrentDataRole;
|
||||
private final int mSupportedRoleCombinations;
|
||||
private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
|
||||
private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
|
||||
private final boolean mUsbDataEnabled;
|
||||
private final boolean mPowerTransferLimited;
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
|
||||
public static final int POWER_ROLE_SINK = 2;
|
||||
|
||||
@IntDef(prefix = { "POWER_ROLE_" }, value = {
|
||||
POWER_ROLE_NONE,
|
||||
@@ -69,17 +71,17 @@ public final class UsbPortStatus implements Parcelable {
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
|
||||
public static final int DATA_ROLE_DEVICE = 2;
|
||||
|
||||
@IntDef(prefix = { "DATA_ROLE_" }, value = {
|
||||
DATA_ROLE_NONE,
|
||||
@@ -92,15 +94,7 @@ public final class UsbPortStatus implements Parcelable {
|
||||
/**
|
||||
* There is currently nothing connected to this USB port.
|
||||
*/
|
||||
public static final int MODE_NONE = Constants.PortMode.NONE;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
public static final int MODE_NONE = 0;
|
||||
|
||||
/**
|
||||
* This USB port can act as an upstream facing port (device).
|
||||
@@ -108,7 +102,15 @@ public final class UsbPortStatus implements Parcelable {
|
||||
* <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and
|
||||
* {@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
|
||||
@@ -120,87 +122,76 @@ public final class UsbPortStatus implements Parcelable {
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public static final int MODE_AUDIO_ACCESSORY =
|
||||
android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY;
|
||||
public static final int MODE_AUDIO_ACCESSORY = 1 << 2;
|
||||
|
||||
/**
|
||||
* This USB port can support USB Type-C debug accessory.
|
||||
*/
|
||||
public static final int MODE_DEBUG_ACCESSORY =
|
||||
android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
|
||||
public static final int MODE_DEBUG_ACCESSORY = 1 << 3;
|
||||
|
||||
/**
|
||||
* Contaminant presence detection not supported by the device.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_SUPPORTED;
|
||||
public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED = 0;
|
||||
|
||||
/**
|
||||
* Contaminant presence detection supported but disabled.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_DETECTION_DISABLED =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DISABLED;
|
||||
public static final int CONTAMINANT_DETECTION_DISABLED = 1;
|
||||
|
||||
/**
|
||||
* Contaminant presence enabled but not detected.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_DETECTION_NOT_DETECTED =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_DETECTED;
|
||||
public static final int CONTAMINANT_DETECTION_NOT_DETECTED = 2;
|
||||
|
||||
/**
|
||||
* Contaminant presence enabled and detected.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_DETECTION_DETECTED =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DETECTED;
|
||||
public static final int CONTAMINANT_DETECTION_DETECTED = 3;
|
||||
|
||||
/**
|
||||
* Contaminant protection - No action performed upon detection of
|
||||
* contaminant presence.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_PROTECTION_NONE =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.NONE;
|
||||
public static final int CONTAMINANT_PROTECTION_NONE = 0;
|
||||
|
||||
/**
|
||||
* Contaminant protection - Port is forced to sink upon detection of
|
||||
* contaminant presence.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_PROTECTION_SINK =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SINK;
|
||||
public static final int CONTAMINANT_PROTECTION_SINK = 1 << 0;
|
||||
|
||||
/**
|
||||
* Contaminant protection - Port is forced to source upon detection of
|
||||
* contaminant presence.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_PROTECTION_SOURCE =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SOURCE;
|
||||
public static final int CONTAMINANT_PROTECTION_SOURCE = 1 << 1;
|
||||
|
||||
/**
|
||||
* Contaminant protection - Port is disabled upon detection of
|
||||
* contaminant presence.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_DISABLE;
|
||||
public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE = 1 << 2;
|
||||
|
||||
/**
|
||||
* Contaminant protection - Port is disabled upon detection of
|
||||
* contaminant presence.
|
||||
* @hide
|
||||
*/
|
||||
public static final int CONTAMINANT_PROTECTION_DISABLED =
|
||||
android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.DISABLED;
|
||||
public static final int CONTAMINANT_PROTECTION_DISABLED = 1 << 3;
|
||||
|
||||
@IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
|
||||
CONTAMINANT_DETECTION_NOT_SUPPORTED,
|
||||
@@ -231,6 +222,21 @@ public final class UsbPortStatus implements Parcelable {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface UsbPortMode{}
|
||||
|
||||
/** @hide */
|
||||
public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
|
||||
int supportedRoleCombinations, int contaminantProtectionStatus,
|
||||
int contaminantDetectionStatus, boolean usbDataEnabled,
|
||||
boolean powerTransferLimited) {
|
||||
mCurrentMode = currentMode;
|
||||
mCurrentPowerRole = currentPowerRole;
|
||||
mCurrentDataRole = currentDataRole;
|
||||
mSupportedRoleCombinations = supportedRoleCombinations;
|
||||
mContaminantProtectionStatus = contaminantProtectionStatus;
|
||||
mContaminantDetectionStatus = contaminantDetectionStatus;
|
||||
mUsbDataEnabled = usbDataEnabled;
|
||||
mPowerTransferLimited = powerTransferLimited;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
|
||||
int supportedRoleCombinations, int contaminantProtectionStatus,
|
||||
@@ -241,6 +247,8 @@ public final class UsbPortStatus implements Parcelable {
|
||||
mSupportedRoleCombinations = supportedRoleCombinations;
|
||||
mContaminantProtectionStatus = contaminantProtectionStatus;
|
||||
mContaminantDetectionStatus = contaminantDetectionStatus;
|
||||
mUsbDataEnabled = true;
|
||||
mPowerTransferLimited = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,6 +331,25 @@ public final class UsbPortStatus implements Parcelable {
|
||||
return mContaminantProtectionStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns UsbData status.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean getUsbDataStatus() {
|
||||
return mUsbDataEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether power transfer is limited.
|
||||
*
|
||||
* @return true when power transfer is limited.
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean isPowerTransferLimited() {
|
||||
return mPowerTransferLimited;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -336,6 +363,10 @@ public final class UsbPortStatus implements Parcelable {
|
||||
+ getContaminantDetectionStatus()
|
||||
+ ", contaminantProtectionStatus="
|
||||
+ getContaminantProtectionStatus()
|
||||
+ ", usbDataEnabled="
|
||||
+ getUsbDataStatus()
|
||||
+ ", isPowerTransferLimited="
|
||||
+ isPowerTransferLimited()
|
||||
+ "}";
|
||||
}
|
||||
|
||||
@@ -352,6 +383,8 @@ public final class UsbPortStatus implements Parcelable {
|
||||
dest.writeInt(mSupportedRoleCombinations);
|
||||
dest.writeInt(mContaminantProtectionStatus);
|
||||
dest.writeInt(mContaminantDetectionStatus);
|
||||
dest.writeBoolean(mUsbDataEnabled);
|
||||
dest.writeBoolean(mPowerTransferLimited);
|
||||
}
|
||||
|
||||
public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
|
||||
@@ -364,9 +397,11 @@ public final class UsbPortStatus implements Parcelable {
|
||||
int supportedRoleCombinations = in.readInt();
|
||||
int contaminantProtectionStatus = in.readInt();
|
||||
int contaminantDetectionStatus = in.readInt();
|
||||
boolean usbDataEnabled = in.readBoolean();
|
||||
boolean powerTransferLimited = in.readBoolean();
|
||||
return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
|
||||
supportedRoleCombinations, contaminantProtectionStatus,
|
||||
contaminantDetectionStatus);
|
||||
contaminantDetectionStatus, usbDataEnabled, powerTransferLimited);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -244,7 +244,10 @@ public class DumpUtils {
|
||||
writeContaminantPresenceStatus(dump, "contaminant_presence_status",
|
||||
UsbPortStatusProto.CONTAMINANT_PRESENCE_STATUS,
|
||||
status.getContaminantDetectionStatus());
|
||||
|
||||
dump.write("usb_data_enabled", UsbPortStatusProto.USB_DATA_ENABLED,
|
||||
status.getUsbDataStatus());
|
||||
dump.write("is_power_transfer_limited", UsbPortStatusProto.IS_POWER_TRANSFER_LIMITED,
|
||||
status.isPowerTransferLimited());
|
||||
dump.end(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,9 +196,19 @@ message UsbIsHeadsetProto {
|
||||
message UsbPortManagerProto {
|
||||
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;
|
||||
repeated UsbPortInfoProto usb_ports = 2;
|
||||
optional bool enable_usb_data_signaling = 3;
|
||||
optional HalVersion hal_version = 4;
|
||||
}
|
||||
|
||||
message UsbPortInfoProto {
|
||||
@@ -254,6 +264,8 @@ message UsbPortStatusProto {
|
||||
optional DataRole data_role = 4;
|
||||
repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
|
||||
optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6;
|
||||
optional bool usb_data_enabled = 7;
|
||||
optional bool is_power_transfer_limited = 8;
|
||||
}
|
||||
|
||||
message UsbPortStatusRoleCombinationProto {
|
||||
|
||||
@@ -29,6 +29,7 @@ java_library_static {
|
||||
"android.hardware.usb-V1.1-java",
|
||||
"android.hardware.usb-V1.2-java",
|
||||
"android.hardware.usb-V1.3-java",
|
||||
"android.hardware.usb-V1-java",
|
||||
"android.hardware.usb.gadget-V1.0-java",
|
||||
"android.hardware.usb.gadget-V1.1-java",
|
||||
"android.hardware.usb.gadget-V1.2-java",
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
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_PROTECTION_NONE;
|
||||
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.POWER_ROLE_SINK;
|
||||
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.writePortStatus;
|
||||
@@ -38,6 +46,7 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.usb.IUsbOperationInternal;
|
||||
import android.hardware.usb.ParcelableUsbPort;
|
||||
import android.hardware.usb.UsbManager;
|
||||
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.dump.DualDumpOutputStream;
|
||||
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.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Allows trusted components to control the properties of physical USB ports
|
||||
@@ -109,16 +122,9 @@ public class UsbPortManager {
|
||||
// The system context.
|
||||
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.
|
||||
// Mostly due a command sent by the remote Usb device.
|
||||
private HALCallback mHALCallback = new HALCallback(null, this);
|
||||
|
||||
// Cookie sent for usb hal death notification.
|
||||
private static final int USB_HAL_DEATH_COOKIE = 1000;
|
||||
//private HALCallback mHALCallback = new HALCallback(null, this);
|
||||
|
||||
// Used as the key while sending the bundle to Main thread.
|
||||
private static final String PORT_INFO = "port_info";
|
||||
@@ -156,36 +162,23 @@ public class UsbPortManager {
|
||||
*/
|
||||
private int mIsPortContaminatedNotificationId;
|
||||
|
||||
private boolean mEnableUsbDataSignaling;
|
||||
protected int mCurrentUsbHalVersion;
|
||||
private UsbPortHal mUsbPortHal;
|
||||
|
||||
private long mTransactionId;
|
||||
|
||||
public UsbPortManager(Context context) {
|
||||
mContext = context;
|
||||
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(null);
|
||||
mUsbPortHal = UsbPortHalInstance.getInstance(this, null);
|
||||
logAndPrint(Log.DEBUG, null, "getInstance done");
|
||||
}
|
||||
|
||||
public void systemReady() {
|
||||
mSystemReady = true;
|
||||
if (mProxy != null) {
|
||||
mSystemReady = true;
|
||||
if (mUsbPortHal != null) {
|
||||
mUsbPortHal.systemReady();
|
||||
try {
|
||||
mProxy.queryPortStatus();
|
||||
mEnableUsbDataSignaling = true;
|
||||
} catch (RemoteException e) {
|
||||
mUsbPortHal.queryPortStatus(++mTransactionId);
|
||||
} catch (Exception e) {
|
||||
logAndPrintException(null,
|
||||
"ServiceStart: Failed to query port status", e);
|
||||
}
|
||||
@@ -233,6 +226,7 @@ public class UsbPortManager {
|
||||
intent.setComponent(ComponentName.unflattenFromString(r.getString(
|
||||
com.android.internal.R.string.config_usbContaminantActivity)));
|
||||
intent.putExtra(UsbManager.EXTRA_PORT, ParcelableUsbPort.of(currentPortInfo.mUsbPort));
|
||||
intent.putExtra(UsbManager.EXTRA_PORT_STATUS, currentPortInfo.mUsbPortStatus);
|
||||
|
||||
// Simple notification clicks are immutable
|
||||
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
|
||||
@@ -340,13 +334,52 @@ public class UsbPortManager {
|
||||
}
|
||||
|
||||
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(portId, enable);
|
||||
} catch (RemoteException e) {
|
||||
mUsbPortHal.enableContaminantPresenceDetection(portId, enable, ++mTransactionId);
|
||||
} catch (Exception e) {
|
||||
logAndPrintException(pw, "Failed to set contaminant detection", e);
|
||||
} catch (ClassCastException e) {
|
||||
logAndPrintException(pw, "Method only applicable to V1.2 or above implementation", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits power transfer in/out of USB-C port.
|
||||
*
|
||||
* @param portId port identifier.
|
||||
* @param limit limit power transfer when true.
|
||||
*/
|
||||
public void enableLimitPowerTransfer(@NonNull String portId, boolean limit, long transactionId,
|
||||
IUsbOperationInternal callback, IndentingPrintWriter pw) {
|
||||
Objects.requireNonNull(portId);
|
||||
final PortInfo portInfo = mPorts.get(portId);
|
||||
if (portInfo == null) {
|
||||
logAndPrint(Log.ERROR, pw, "enableLimitPowerTransfer: No such port: " + portId
|
||||
+ " opId:" + transactionId);
|
||||
try {
|
||||
if (callback != null) {
|
||||
callback.onOperationComplete(USB_OPERATION_ERROR_PORT_MISMATCH);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(pw,
|
||||
"enableLimitPowerTransfer: Failed to call OperationComplete. opId:"
|
||||
+ transactionId, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
mUsbPortHal.enableLimitPowerTransfer(portId, limit, transactionId, callback);
|
||||
} catch (Exception e) {
|
||||
logAndPrintException(pw,
|
||||
"enableLimitPowerTransfer: Failed to limit power transfer. opId:"
|
||||
+ transactionId , e);
|
||||
if (callback != null) {
|
||||
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(pw,
|
||||
"enableLimitPowerTransfer:Failed to call onOperationComplete. opId:"
|
||||
+ transactionId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,46 +388,79 @@ public class UsbPortManager {
|
||||
*
|
||||
* @param enable enable or disable USB data signaling
|
||||
*/
|
||||
public boolean enableUsbDataSignal(boolean enable) {
|
||||
try {
|
||||
mEnableUsbDataSignaling = enable;
|
||||
// Call into the hal. Use the castFrom method from HIDL.
|
||||
android.hardware.usb.V1_3.IUsb proxy = android.hardware.usb.V1_3.IUsb.castFrom(mProxy);
|
||||
return proxy.enableUsbDataSignal(enable);
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(null, "Failed to set USB data signaling", e);
|
||||
return false;
|
||||
} catch (ClassCastException e) {
|
||||
logAndPrintException(null, "Method only applicable to V1.3 or above implementation", e);
|
||||
public boolean enableUsbData(@NonNull String portId, boolean enable, int transactionId,
|
||||
@NonNull IUsbOperationInternal callback, IndentingPrintWriter pw) {
|
||||
Objects.requireNonNull(callback);
|
||||
Objects.requireNonNull(portId);
|
||||
final PortInfo portInfo = mPorts.get(portId);
|
||||
if (portInfo == null) {
|
||||
logAndPrint(Log.ERROR, pw, "enableUsbData: No such port: " + portId
|
||||
+ " opId:" + transactionId);
|
||||
try {
|
||||
callback.onOperationComplete(USB_OPERATION_ERROR_PORT_MISMATCH);
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(pw,
|
||||
"enableUsbData: Failed to call OperationComplete. opId:"
|
||||
+ transactionId, e);
|
||||
}
|
||||
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
|
||||
*
|
||||
* @param none
|
||||
* @return {@link UsbManager#USB_HAL_RETRY} returned when hal version
|
||||
* is yet to be determined.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* update USB HAL version
|
||||
*
|
||||
* @param none
|
||||
*/
|
||||
private void updateUsbHalVersion() {
|
||||
if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) {
|
||||
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_3;
|
||||
} else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) {
|
||||
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_2;
|
||||
} else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) {
|
||||
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_1;
|
||||
} else {
|
||||
mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_0;
|
||||
}
|
||||
logAndPrint(Log.INFO, null, "USB HAL version: " + mCurrentUsbHalVersion);
|
||||
private int toHalUsbDataRole(int usbDataRole) {
|
||||
if (usbDataRole == DATA_ROLE_DEVICE)
|
||||
return HAL_DATA_ROLE_DEVICE;
|
||||
else
|
||||
return HAL_DATA_ROLE_HOST;
|
||||
}
|
||||
|
||||
private int toHalUsbPowerRole(int usbPowerRole) {
|
||||
if (usbPowerRole == POWER_ROLE_SINK)
|
||||
return HAL_POWER_ROLE_SINK;
|
||||
else
|
||||
return HAL_POWER_ROLE_SOURCE;
|
||||
}
|
||||
|
||||
private int toHalUsbMode(int usbMode) {
|
||||
if (usbMode == MODE_UFP)
|
||||
return HAL_MODE_UFP;
|
||||
else
|
||||
return HAL_MODE_DFP;
|
||||
}
|
||||
|
||||
public void setPortRoles(String portId, int newPowerRole, int newDataRole,
|
||||
@@ -473,7 +539,7 @@ public class UsbPortManager {
|
||||
sim.currentPowerRole = newPowerRole;
|
||||
sim.currentDataRole = newDataRole;
|
||||
updatePortsLocked(pw, null);
|
||||
} else if (mProxy != null) {
|
||||
} else if (mUsbPortHal != null) {
|
||||
if (currentMode != newMode) {
|
||||
// Changing the mode will have the side-effect of also changing
|
||||
// the power and data roles but it might take some time to apply
|
||||
@@ -485,44 +551,37 @@ public class UsbPortManager {
|
||||
logAndPrint(Log.ERROR, pw, "Trying to set the USB port mode: "
|
||||
+ "portId=" + portId
|
||||
+ ", newMode=" + UsbPort.modeToString(newMode));
|
||||
PortRole newRole = new PortRole();
|
||||
newRole.type = PortRoleType.MODE;
|
||||
newRole.role = newMode;
|
||||
try {
|
||||
mProxy.switchRole(portId, newRole);
|
||||
} catch (RemoteException e) {
|
||||
mUsbPortHal.switchMode(portId, toHalUsbMode(newMode), ++mTransactionId);
|
||||
} catch (Exception e) {
|
||||
logAndPrintException(pw, "Failed to set the USB port mode: "
|
||||
+ "portId=" + portId
|
||||
+ ", newMode=" + UsbPort.modeToString(newRole.role), e);
|
||||
+ ", newMode=" + UsbPort.modeToString(newMode), e);
|
||||
}
|
||||
} else {
|
||||
// Change power and data role independently as needed.
|
||||
if (currentPowerRole != newPowerRole) {
|
||||
PortRole newRole = new PortRole();
|
||||
newRole.type = PortRoleType.POWER_ROLE;
|
||||
newRole.role = newPowerRole;
|
||||
try {
|
||||
mProxy.switchRole(portId, newRole);
|
||||
} catch (RemoteException e) {
|
||||
mUsbPortHal.switchPowerRole(portId, toHalUsbPowerRole(newPowerRole),
|
||||
++mTransactionId);
|
||||
} catch (Exception e) {
|
||||
logAndPrintException(pw, "Failed to set the USB port power role: "
|
||||
+ "portId=" + portId
|
||||
+ ", newPowerRole=" + UsbPort.powerRoleToString
|
||||
(newRole.role),
|
||||
(newPowerRole),
|
||||
e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (currentDataRole != newDataRole) {
|
||||
PortRole newRole = new PortRole();
|
||||
newRole.type = PortRoleType.DATA_ROLE;
|
||||
newRole.role = newDataRole;
|
||||
try {
|
||||
mProxy.switchRole(portId, newRole);
|
||||
} catch (RemoteException e) {
|
||||
mUsbPortHal.switchDataRole(portId, toHalUsbDataRole(newDataRole),
|
||||
++mTransactionId);
|
||||
} catch (Exception e) {
|
||||
logAndPrintException(pw, "Failed to set the USB port data role: "
|
||||
+ "portId=" + portId
|
||||
+ ", newDataRole=" + UsbPort.dataRoleToString(newRole
|
||||
.role),
|
||||
+ ", newDataRole=" + UsbPort.dataRoleToString
|
||||
(newDataRole),
|
||||
e);
|
||||
}
|
||||
}
|
||||
@@ -531,6 +590,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) {
|
||||
synchronized (mLock) {
|
||||
if (mSimulatedPorts.containsKey(portId)) {
|
||||
@@ -662,191 +730,12 @@ public class UsbPortManager {
|
||||
portInfo.dump(dump, "usb_ports", UsbPortManagerProto.USB_PORTS);
|
||||
}
|
||||
|
||||
dump.write("enable_usb_data_signaling", UsbPortManagerProto.ENABLE_USB_DATA_SIGNALING,
|
||||
mEnableUsbDataSignaling);
|
||||
dump.write("usb_hal_version", UsbPortManagerProto.HAL_VERSION, getUsbHalVersion());
|
||||
}
|
||||
|
||||
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.
|
||||
* USB hal callback populates and sends the newPortInfo.
|
||||
@@ -869,7 +758,9 @@ public class UsbPortManager {
|
||||
portInfo.supportsEnableContaminantPresenceProtection,
|
||||
portInfo.contaminantProtectionStatus,
|
||||
portInfo.supportsEnableContaminantPresenceDetection,
|
||||
portInfo.contaminantDetectionStatus, pw);
|
||||
portInfo.contaminantDetectionStatus,
|
||||
portInfo.usbDataEnabled,
|
||||
portInfo.powerTransferLimited, pw);
|
||||
}
|
||||
} else {
|
||||
for (RawPortInfo currentPortInfo : newPortInfo) {
|
||||
@@ -881,7 +772,9 @@ public class UsbPortManager {
|
||||
currentPortInfo.supportsEnableContaminantPresenceProtection,
|
||||
currentPortInfo.contaminantProtectionStatus,
|
||||
currentPortInfo.supportsEnableContaminantPresenceDetection,
|
||||
currentPortInfo.contaminantDetectionStatus, pw);
|
||||
currentPortInfo.contaminantDetectionStatus,
|
||||
currentPortInfo.usbDataEnabled,
|
||||
currentPortInfo.powerTransferLimited, pw);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,6 +810,8 @@ public class UsbPortManager {
|
||||
int contaminantProtectionStatus,
|
||||
boolean supportsEnableContaminantPresenceDetection,
|
||||
int contaminantDetectionStatus,
|
||||
boolean usbDataEnabled,
|
||||
boolean powerTransferLimited,
|
||||
IndentingPrintWriter pw) {
|
||||
// Only allow mode switch capability for dual role ports.
|
||||
// Validate that the current mode matches the supported modes we expect.
|
||||
@@ -975,7 +870,8 @@ public class UsbPortManager {
|
||||
currentPowerRole, canChangePowerRole,
|
||||
currentDataRole, canChangeDataRole,
|
||||
supportedRoleCombinations, contaminantProtectionStatus,
|
||||
contaminantDetectionStatus);
|
||||
contaminantDetectionStatus, usbDataEnabled,
|
||||
powerTransferLimited);
|
||||
mPorts.put(portId, portInfo);
|
||||
} else {
|
||||
// Validate that ports aren't changing definition out from under us.
|
||||
@@ -1012,7 +908,8 @@ public class UsbPortManager {
|
||||
currentPowerRole, canChangePowerRole,
|
||||
currentDataRole, canChangeDataRole,
|
||||
supportedRoleCombinations, contaminantProtectionStatus,
|
||||
contaminantDetectionStatus)) {
|
||||
contaminantDetectionStatus, usbDataEnabled,
|
||||
powerTransferLimited)) {
|
||||
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
|
||||
} else {
|
||||
portInfo.mDisposition = PortInfo.DISPOSITION_READY;
|
||||
@@ -1034,6 +931,7 @@ public class UsbPortManager {
|
||||
private void handlePortChangedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
|
||||
logAndPrint(Log.INFO, pw, "USB port changed: " + portInfo);
|
||||
enableContaminantDetectionIfNeeded(portInfo, pw);
|
||||
disableLimitPowerTransferIfNeeded(portInfo, pw);
|
||||
handlePortLocked(portInfo, pw);
|
||||
}
|
||||
|
||||
@@ -1090,6 +988,19 @@ public class UsbPortManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void disableLimitPowerTransferIfNeeded(PortInfo portInfo, IndentingPrintWriter pw) {
|
||||
if (!mConnected.containsKey(portInfo.mUsbPort.getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mConnected.get(portInfo.mUsbPort.getId())
|
||||
&& !portInfo.mUsbPortStatus.isConnected()
|
||||
&& portInfo.mUsbPortStatus.isPowerTransferLimited()) {
|
||||
// Relax enableLimitPowerTransfer upon unplug.
|
||||
enableLimitPowerTransfer(portInfo.mUsbPort.getId(), false, ++mTransactionId, null, pw);
|
||||
}
|
||||
}
|
||||
|
||||
private void logToStatsd(PortInfo portInfo, IndentingPrintWriter pw) {
|
||||
// Port is removed
|
||||
if (portInfo.mUsbPortStatus == null) {
|
||||
@@ -1141,14 +1052,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);
|
||||
if (pw != null) {
|
||||
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);
|
||||
if (pw != null) {
|
||||
pw.println(msg + e);
|
||||
@@ -1179,7 +1090,7 @@ public class UsbPortManager {
|
||||
/**
|
||||
* 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_CHANGED = 1;
|
||||
public static final int DISPOSITION_READY = 2;
|
||||
@@ -1224,7 +1135,7 @@ public class UsbPortManager {
|
||||
!= supportedRoleCombinations) {
|
||||
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
|
||||
supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
|
||||
UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED);
|
||||
UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED, true, false);
|
||||
dispositionChanged = true;
|
||||
}
|
||||
|
||||
@@ -1243,7 +1154,8 @@ public class UsbPortManager {
|
||||
int currentPowerRole, boolean canChangePowerRole,
|
||||
int currentDataRole, boolean canChangeDataRole,
|
||||
int supportedRoleCombinations, int contaminantProtectionStatus,
|
||||
int contaminantDetectionStatus) {
|
||||
int contaminantDetectionStatus, boolean usbDataEnabled,
|
||||
boolean powerTransferLimited) {
|
||||
boolean dispositionChanged = false;
|
||||
|
||||
mCanChangeMode = canChangeMode;
|
||||
@@ -1258,10 +1170,15 @@ public class UsbPortManager {
|
||||
|| mUsbPortStatus.getContaminantProtectionStatus()
|
||||
!= contaminantProtectionStatus
|
||||
|| mUsbPortStatus.getContaminantDetectionStatus()
|
||||
!= contaminantDetectionStatus) {
|
||||
!= contaminantDetectionStatus
|
||||
|| mUsbPortStatus.getUsbDataStatus()
|
||||
!= usbDataEnabled
|
||||
|| mUsbPortStatus.isPowerTransferLimited()
|
||||
!= powerTransferLimited) {
|
||||
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
|
||||
supportedRoleCombinations, contaminantProtectionStatus,
|
||||
contaminantDetectionStatus);
|
||||
contaminantDetectionStatus, usbDataEnabled,
|
||||
powerTransferLimited);
|
||||
dispositionChanged = true;
|
||||
}
|
||||
|
||||
@@ -1290,7 +1207,6 @@ public class UsbPortManager {
|
||||
UsbPortInfoProto.CONNECTED_AT_MILLIS, mConnectedAtMillis);
|
||||
dump.write("last_connect_duration_millis",
|
||||
UsbPortInfoProto.LAST_CONNECT_DURATION_MILLIS, mLastConnectDurationMillis);
|
||||
|
||||
dump.end(token);
|
||||
}
|
||||
|
||||
@@ -1304,115 +1220,4 @@ public class UsbPortManager {
|
||||
+ ", 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];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
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_HOST;
|
||||
import static android.hardware.usb.UsbPortStatus.MODE_DFP;
|
||||
@@ -35,6 +36,7 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.usb.IUsbManager;
|
||||
import android.hardware.usb.IUsbOperationInternal;
|
||||
import android.hardware.usb.ParcelableUsbPort;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
@@ -44,6 +46,7 @@ import android.hardware.usb.UsbPortStatus;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.usb.UsbServiceDumpProto;
|
||||
@@ -730,6 +733,28 @@ public class UsbService extends IUsbManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableLimitPowerTransfer(String portId, boolean limit, int operationId,
|
||||
IUsbOperationInternal callback) {
|
||||
Objects.requireNonNull(portId, "portId must not be null. opID:" + operationId);
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
||||
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (mPortManager != null) {
|
||||
mPortManager.enableLimitPowerTransfer(portId, limit, operationId, callback, null);
|
||||
} else {
|
||||
try {
|
||||
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "enableLimitPowerTransfer: Failed to call onOperationComplete", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableContaminantDetection(String portId, boolean enable) {
|
||||
Objects.requireNonNull(portId, "portId must not be null");
|
||||
@@ -762,19 +787,30 @@ public class UsbService extends IUsbManager.Stub {
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
boolean wait;
|
||||
try {
|
||||
if (mPortManager != null) {
|
||||
return mPortManager.enableUsbDataSignal(enable);
|
||||
wait = mPortManager.enableUsbData(portId, enable, operationId, callback, null);
|
||||
} 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 {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
return wait;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 boolean powerTransferLimited;
|
||||
|
||||
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;
|
||||
this.powerTransferLimited = false;
|
||||
}
|
||||
|
||||
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,
|
||||
boolean powerTransferLimited) {
|
||||
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;
|
||||
this.powerTransferLimited = powerTransferLimited;
|
||||
}
|
||||
|
||||
@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);
|
||||
dest.writeBoolean(powerTransferLimited);
|
||||
}
|
||||
|
||||
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();
|
||||
boolean powerTransferLimited = in.readBoolean();
|
||||
return new RawPortInfo(id, supportedModes,
|
||||
supportedContaminantProtectionModes, currentMode, canChangeMode,
|
||||
currentPowerRole, canChangePowerRole,
|
||||
currentDataRole, canChangeDataRole,
|
||||
supportsEnableContaminantPresenceProtection,
|
||||
contaminantProtectionStatus,
|
||||
supportsEnableContaminantPresenceDetection,
|
||||
contaminantDetectionStatus, usbDataEnabled,
|
||||
powerTransferLimited);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RawPortInfo[] newArray(int size) {
|
||||
return new RawPortInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableLimitPowerTransfer(String portName, boolean limit, long operationID,
|
||||
IUsbOperationInternal callback) {
|
||||
Objects.requireNonNull(portName);
|
||||
long key = operationID;
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
if (mProxy == null) {
|
||||
logAndPrint(Log.ERROR, mPw,
|
||||
"enableLimitPowerTransfer: Proxy is null. Retry !opID:"
|
||||
+ operationID);
|
||||
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
|
||||
return;
|
||||
}
|
||||
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.limitPowerTransfer(portName, limit, key);
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(mPw,
|
||||
"enableLimitPowerTransfer: Failed while invoking AIDL HAL"
|
||||
+ " portID=" + portName + " opID:" + operationID, e);
|
||||
if (callback != null) {
|
||||
callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
|
||||
}
|
||||
sCallbacks.remove(key);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(mPw,
|
||||
"enableLimitPowerTransfer: Failed to call onOperationComplete portID="
|
||||
+ portName + " opID:" + operationID, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
current.powerTransferLimited);
|
||||
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 void notifyLimitPowerTransferStatus(String portName, boolean limit, int retval,
|
||||
long operationID) {
|
||||
if (retval == Status.SUCCESS) {
|
||||
UsbPortManager.logAndPrint(Log.INFO, mPw, portName + ": opID:"
|
||||
+ operationID + " successful");
|
||||
} else {
|
||||
UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
|
||||
+ "notifyLimitPowerTransferStatus: opID:"
|
||||
+ operationID + " failed. err:" + retval);
|
||||
}
|
||||
try {
|
||||
IUsbOperationInternal callback = sCallbacks.get(operationID);
|
||||
if (callback != null) {
|
||||
sCallbacks.get(operationID).onOperationComplete(retval == Status.SUCCESS
|
||||
? USB_OPERATION_SUCCESS
|
||||
: USB_OPERATION_ERROR_INTERNAL);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(mPw,
|
||||
"enableLimitPowerTransfer: Failed to call onOperationComplete",
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Invoked to enableLimitPowerTransfer on the specified port.
|
||||
*
|
||||
* @param portName Port Identifier.
|
||||
* @param limit limit power transfer when true. Port wouldn't charge or power USB accessoried
|
||||
* when set.
|
||||
* Lift power transfer restrictions 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.
|
||||
*/
|
||||
public void enableLimitPowerTransfer(String portName, boolean limit, long transactionId,
|
||||
IUsbOperationInternal callback);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* 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 enableLimitPowerTransfer(String portName, boolean limit, long transactionId,
|
||||
IUsbOperationInternal callback) {
|
||||
/* Not supported in HIDL hals*/
|
||||
try {
|
||||
callback.onOperationComplete(USB_OPERATION_ERROR_NOT_SUPPORTED);
|
||||
} catch (RemoteException e) {
|
||||
logAndPrintException(mPw, "Failed to call onOperationComplete", 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,
|
||||
false);
|
||||
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,
|
||||
false);
|
||||
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,
|
||||
false);
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user