Merge changes from topics "199357330", "200993386"

* changes:
  Add Vts test for limitPowerTransfer interface
  Add limitPowerTransfer API to IUsb
  VTS tests for USB AIDL interface
  Migrate IUsb to AIDL
This commit is contained in:
Badhri Jagan Sridharan
2022-01-22 01:20:20 +00:00
committed by Android (Google) Code Review
33 changed files with 2534 additions and 0 deletions

View File

@@ -752,6 +752,13 @@
<instance>default</instance>
</interface>
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.usb</name>
<interface>
<name>IUsb</name>
<instance>default</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.usb.gadget</name>
<version>1.0-2</version>

33
usb/aidl/Android.bp Normal file
View File

@@ -0,0 +1,33 @@
// 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.
aidl_interface {
name: "android.hardware.usb",
vendor_available: true,
srcs: ["android/hardware/usb/*.aidl"],
stability: "vintf",
backend: {
cpp: {
enabled: false,
},
java: {
sdk_version: "module_current",
},
ndk: {
vndk: {
enabled: true,
},
},
},
}

View File

@@ -0,0 +1,41 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
enum ContaminantDetectionStatus {
NOT_SUPPORTED = 0,
DISABLED = 1,
NOT_DETECTED = 2,
DETECTED = 3,
}

View File

@@ -0,0 +1,41 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
enum ContaminantProtectionMode {
NONE = 0,
FORCE_SINK = 1,
FORCE_SOURCE = 2,
FORCE_DISABLE = 3,
}

View File

@@ -0,0 +1,42 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
enum ContaminantProtectionStatus {
NONE = 0,
FORCE_SINK = 1,
FORCE_SOURCE = 2,
FORCE_DISABLE = 3,
DISABLED = 4,
}

View File

@@ -0,0 +1,43 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
interface IUsb {
oneway void enableContaminantPresenceDetection(in String portName, in boolean enable, long transactionId);
oneway void enableUsbData(in String portName, boolean enable, long transactionId);
oneway void queryPortStatus(long transactionId);
oneway void setCallback(in android.hardware.usb.IUsbCallback callback);
oneway void switchRole(in String portName, in android.hardware.usb.PortRole role, long transactionId);
oneway void limitPowerTransfer(in String portName, boolean limit, long transactionId);
}

View File

@@ -0,0 +1,43 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
interface IUsbCallback {
oneway void notifyPortStatusChange(in android.hardware.usb.PortStatus[] currentPortStatus, in android.hardware.usb.Status retval);
oneway void notifyRoleSwitchStatus(in String portName, in android.hardware.usb.PortRole newRole, in android.hardware.usb.Status retval, long transactionId);
oneway void notifyEnableUsbDataStatus(in String portName, boolean enable, in android.hardware.usb.Status retval, long transactionId);
oneway void notifyContaminantEnabledStatus(in String portName, boolean enable, in android.hardware.usb.Status retval, long transactionId);
oneway void notifyQueryPortStatus(in String portName, in android.hardware.usb.Status retval, long transactionId);
oneway void notifyLimitPowerTransferStatus(in String portName, boolean limit, in android.hardware.usb.Status retval, long transactionId);
}

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
enum PortDataRole {
NONE = 0,
HOST = 1,
DEVICE = 2,
}

View File

@@ -0,0 +1,43 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
enum PortMode {
NONE = 0,
UFP = 1,
DFP = 2,
DRP = 3,
AUDIO_ACCESSORY = 4,
DEBUG_ACCESSORY = 5,
}

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
enum PortPowerRole {
NONE = 0,
SOURCE = 1,
SINK = 2,
}

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
union PortRole {
android.hardware.usb.PortPowerRole powerRole = android.hardware.usb.PortPowerRole.NONE;
android.hardware.usb.PortDataRole dataRole;
android.hardware.usb.PortMode mode;
}

View File

@@ -0,0 +1,52 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@VintfStability
parcelable PortStatus {
String portName;
android.hardware.usb.PortDataRole currentDataRole = android.hardware.usb.PortDataRole.NONE;
android.hardware.usb.PortPowerRole currentPowerRole = android.hardware.usb.PortPowerRole.NONE;
android.hardware.usb.PortMode currentMode = android.hardware.usb.PortMode.NONE;
boolean canChangeMode;
boolean canChangeDataRole;
boolean canChangePowerRole;
android.hardware.usb.PortMode[] supportedModes;
android.hardware.usb.ContaminantProtectionMode[] supportedContaminantProtectionModes;
boolean supportsEnableContaminantPresenceProtection;
android.hardware.usb.ContaminantProtectionStatus contaminantProtectionStatus = android.hardware.usb.ContaminantProtectionStatus.NONE;
boolean supportsEnableContaminantPresenceDetection;
android.hardware.usb.ContaminantDetectionStatus contaminantDetectionStatus = android.hardware.usb.ContaminantDetectionStatus.NOT_SUPPORTED;
boolean usbDataEnabled;
boolean powerTransferLimited;
}

View File

@@ -0,0 +1,42 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.usb;
@Backing(type="int") @VintfStability
enum Status {
SUCCESS = 0,
ERROR = 1,
INVALID_ARGUMENT = 2,
UNRECOGNIZED_ROLE = 3,
NOT_SUPPORTED = 4,
}

View File

@@ -0,0 +1,37 @@
/*
* 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;
@VintfStability
enum ContaminantDetectionStatus {
/**
* Contaminant presence detection is not supported.
*/
NOT_SUPPORTED = 0,
/**
* Contaminant presence detection is supported but disabled.
*/
DISABLED = 1,
/**
* Contaminant presence detection is enabled and contaminant not detected.
*/
NOT_DETECTED = 2,
/**
* Contaminant presence detection is enabled and contaminant detected.
*/
DETECTED = 3,
}

View File

@@ -0,0 +1,43 @@
/*
* 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;
@VintfStability
enum ContaminantProtectionMode {
/**
* No action performed upon detection of contaminant presence.
*/
NONE = 0,
/**
* Upon detection of contaminant presence, Port is forced to sink only
* mode where a port shall only detect chargers until contaminant presence
* is no longer detected.
*/
FORCE_SINK = 1,
/**
* Upon detection of contaminant presence, Port is forced to source only
* mode where a port shall only detect usb accessories such as headsets
* until contaminant presence is no longer detected.
*/
FORCE_SOURCE = 2,
/**
* Upon detection of contaminant presence, port is disabled until contaminant
* presence is no longer detected. In the disabled state port will
* not respond to connection of chargers or usb accessories.
*/
FORCE_DISABLE = 3,
}

View File

@@ -0,0 +1,51 @@
/*
* 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;
import android.hardware.usb.ContaminantProtectionMode;
@VintfStability
enum ContaminantProtectionStatus {
/**
* No action performed upon detection of contaminant presence.
*/
NONE = 0,
/**
* Upon detection of contaminant presence, Port is forced to sink only
* mode where a port shall only detect chargers until contaminant presence
* is no longer detected.
*/
FORCE_SINK = 1,
/**
* Upon detection of contaminant presence, Port is forced to source only
* mode where a port shall only detect usb accessories such as headsets
* until contaminant presence is no longer detected.
*/
FORCE_SOURCE = 2,
/**
* Upon detection of contaminant presence, port is disabled until contaminant
* presence is no longer detected. In the disabled state port will
* not respond to connection of chargers or usb accessories.
*/
FORCE_DISABLE = 3,
/**
* Client disabled cotaminant protection by calling
* enableContaminantPresencePortProtection set to false. Low level drivers should
* not autmomously take any corrective action when contaminant presence is detected.
*/
DISABLED = 4,
}

View File

@@ -0,0 +1,98 @@
/*
* 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;
import android.hardware.usb.IUsbCallback;
import android.hardware.usb.PortRole;
@VintfStability
oneway interface IUsb {
/**
* When supportsEnableContaminantPresenceDetection is true,
* enableContaminantPresenceDetection enables/disables contaminant
* presence detection algorithm. Calling enableContaminantPresenceDetection
* when supportsEnableContaminantPresenceDetection is false does
* not have any effect.
* Change in contantaminant presence status should be notified to the
* client via notifyPortStatusChange through PortStatus.
*
* @param portName name of the port.
* @param enable true Enable contaminant presence detection algorithm.
* false Disable contaminant presence detection algorithm.
* @param transactionId ID to be used when invoking the callback.
*/
void enableContaminantPresenceDetection(in String portName, in boolean enable, long transactionId);
/**
* This function is used to enable/disable USB data controller.
*
* @param portName Name of the port.
* @param enable true Enable USB data signaling.
* false Disable USB data signaling.
* @param transactionId ID to be used when invoking the callback.
*
*/
void enableUsbData(in String portName, boolean enable, long transactionId);
/**
* This functions is used to request the hal for the current status
* status of the Type-C ports. The result of the query would be sent
* through the IUsbCallback object's notifyRoleSwitchStatus
* to the caller. This api would would let the caller know of the number
* of type-c ports that are present and their connection status through the
* PortStatus type.
* @param transactionId ID to be used when invoking the callback.
*/
void queryPortStatus(long transactionId);
/**
* This function is used to register a callback function which is
* called by the HAL to inform the client of port status updates and
* result of the requested operation. Please refer IUsbCallback for
* complete description of when each of the IUsbCallback's interface
* methods is expected to be called.
*
* @param callback IUsbCallback object used to convey status to the
* userspace.
*/
void setCallback(in IUsbCallback callback);
/**
* This function is used to change the port role of a specific port.
* For example, when DR_SWAP or PR_SWAP is supported.
* The status of the role switch will be informed through IUsbCallback
* object's notifyPortStatusChange method.
*
* @param portName name of the port for which the role has to be changed
* @param role the new port role.
* @param transactionId ID to be used when invoking the callback.
*/
void switchRole(in String portName, in PortRole role, long transactionId);
/**
* This function is used to limit power transfer in and out of the port.
* When limited, the port does not charge from the partner port.
* Also, the port limits sourcing power to the partner port when the USB
* specification allows it to do so.
*
* @param portName name of the port for which power transfer is being limited.
* @param limit true limit power transfer.
* false relax limiting power transfer.
* @param transactionId ID to be used when invoking the callback.
*/
void limitPowerTransfer(in String portName, boolean limit, long transactionId);
}

View File

@@ -0,0 +1,98 @@
/*
* 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;
import android.hardware.usb.PortRole;
import android.hardware.usb.PortStatus;
import android.hardware.usb.Status;
/**
* Callback object used for all the IUsb async methods which expects a result.
* Caller is expected to register the callback object using setCallback method
* to receive updates on the PortStatus.
*/
@VintfStability
oneway interface IUsbCallback {
/**
* Used to convey the current port status to the caller.
* Must be called either when PortState changes due to the port partner or
* when caller requested for the PortStatus update through queryPortStatus.
*
* @param currentPortStatus describes the status of all the USB ports in the
* device.
* @param retval SUCCESS when the required information was enquired form
* kernel and the PortStatus object was built.
* ERROR otherwise.
*/
void notifyPortStatusChange(in PortStatus[] currentPortStatus, in Status retval);
/**
* Used to notify the result of the switchRole call to the caller.
*
* @param portName name of the port for which the roleswap is requested.
* @param newRole the new role requested by the caller.
* @param retval SUCCESS if the role switch succeeded. FAILURE otherwise.
* @param transactionId transactionId sent during switchRole request.
*/
void notifyRoleSwitchStatus(in String portName, in PortRole newRole, in Status retval,
long transactionId);
/**
* Used to notify the result of notifyEnableUsbDataStatus call to the caller.
*
* @param portName name of the port for which the enableUsbData is requested.
* @param enable true when usb data is enabled.
* false when usb data is disabled.
* @param retval SUCCESS if current request succeeded. FAILURE otherwise.
* @param transactionId transactionId sent during enableUsbData request.
*/
void notifyEnableUsbDataStatus(in String portName, boolean enable, in Status retval,
long transactionId);
/**
* Used to notify the result of enableContaminantPresenceDetection.
*
* @param portName name of the port for which contaminant detection is enabled/disabled.
* @param enable true when contaminant detection is enabled.
* false when disabled.
* @param retval SUCCESS if the request for enabling/disabling contamiant detection succeeds.
* FAILURE otherwise.
* @param transactionId transactionId sent during queryPortStatus request
*/
void notifyContaminantEnabledStatus(in String portName, boolean enable, in Status retval,
long transactionId);
/**
* Used to notify the request to query port status.
*
* @param portName name of the port for which port status is queried.
* @param retval SUCCESS if the port query succeeded. FAILURE otherwise.
* @param transactionId transactionId sent during queryPortStatus request
*/
void notifyQueryPortStatus(in String portName, in Status retval, long transactionId);
/**
* Used to notify the result of requesting limitPowerTransfer.
*
* @param portName name of the port for which power transfer is being limited.
* @param limit true limit power transfer.
* false relax limiting power transfer.
* @param retval SUCCESS if the request to enable/disable limitPowerTransfer succeeds.
* FAILURE otherwise.
* @param transactionId ID sent during limitPowerTransfer request.
*/
void notifyLimitPowerTransferStatus(in String portName, boolean limit, in Status retval, long transactionId);
}

View File

@@ -0,0 +1,35 @@
/*
* 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;
@VintfStability
enum PortDataRole {
/**
* Indicates that the port does not have a data role.
* In case of DRP, the current data role of the port is only resolved
* when the type-c handshake happens.
*/
NONE = 0,
/**
* Indicates that the port is acting as a host for data.
*/
HOST = 1,
/**
* Indicated that the port is acting as a device for data.
*/
DEVICE = 2,
}

View File

@@ -0,0 +1,49 @@
/*
* 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;
import android.hardware.usb.PortMode;
@VintfStability
enum PortMode {
/**
* Indicates that the port does not have a mode.
* In case of DRP, the current mode of the port is only resolved
* when the type-c handshake happens.
*/
NONE = 0,
/**
* Indicates that port can only act as device for data and sink for power.
*/
UFP = 1,
/**
* Indicates the port can only act as host for data and source for power.
*/
DFP = 2,
/**
* Indicates can either act as UFP or DFP at a given point of time.
*/
DRP = 3,
/*
* Indicates that the port supports Audio Accessory mode.
*/
AUDIO_ACCESSORY = 4,
/*
* Indicates that the port supports Debug Accessory mode.
*/
DEBUG_ACCESSORY = 5,
}

View File

@@ -0,0 +1,35 @@
/*
* 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;
@VintfStability
enum PortPowerRole {
/**
* Indicates that the port does not have a power role.
* In case of DRP, the current power role of the port is only resolved
* when the type-c handshake happens.
*/
NONE = 0,
/**
* Indicates that the port is supplying power to the other port.
*/
SOURCE = 1,
/**
* Indicates that the port is sinking power from the other port.
*/
SINK = 2,
}

View File

@@ -0,0 +1,31 @@
/*
* 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;
import android.hardware.usb.PortDataRole;
import android.hardware.usb.PortMode;
import android.hardware.usb.PortPowerRole;
/**
* Used as a container to send port role information.
*/
@VintfStability
union PortRole {
PortPowerRole powerRole = PortPowerRole.NONE;
PortDataRole dataRole;
PortMode mode;
}

View File

@@ -0,0 +1,111 @@
/*
* 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;
import android.hardware.usb.ContaminantDetectionStatus;
import android.hardware.usb.ContaminantProtectionMode;
import android.hardware.usb.ContaminantProtectionStatus;
import android.hardware.usb.PortDataRole;
import android.hardware.usb.PortMode;
import android.hardware.usb.PortPowerRole;
@VintfStability
parcelable PortStatus {
/**
* Name of the port.
* Used as the port's id by the caller.
*/
String portName;
/**
* Data role of the port.
*/
PortDataRole currentDataRole = PortDataRole.NONE;
/**
* Power Role of thte port.
*/
PortPowerRole currentPowerRole = PortPowerRole.NONE;
/**
* Mode in which the port is connected.
* Can be UFP or DFP or AUDIO_ACCESSORY or
* DEBUG_ACCESSORY.
*/
PortMode currentMode = PortMode.NONE;
/**
* True indicates that the port's mode can
* be changed. False otherwise.
*/
boolean canChangeMode;
/**
* True indicates that the port's data role
* can be changed. False otherwise.
* For example, true if Type-C PD PD_SWAP
* is supported.
*/
boolean canChangeDataRole;
/**
* True indicates that the port's power role
* can be changed. False otherwise.
* For example, true if Type-C PD PR_SWAP
* is supported.
*/
boolean canChangePowerRole;
/**
* Identifies the type of the local port.
*
* UFP - Indicates that port can only act as device for
* data and sink for power.
* DFP - Indicates the port can only act as host for data
* and source for power.
* DRP - Indicates can either act as UFP or DFP at a
* given point of time.
* AUDIO_ACCESSORY - Indicates that the port supports
* Audio Accessory mode.
* DEBUG_ACCESSORY - Indicates that the port supports
* Debug Accessory mode.
*/
PortMode[] supportedModes;
/**
* Contaminant presence protection modes supported by the port.
*/
ContaminantProtectionMode[] supportedContaminantProtectionModes;
/**
* Client can enable/disable contaminant presence protection through
* enableContaminantPresenceProtection when true.
*/
boolean supportsEnableContaminantPresenceProtection;
/**
* Contaminant presence protection modes currently active for the port.
*/
ContaminantProtectionStatus contaminantProtectionStatus = ContaminantProtectionStatus.NONE;
/**
* Client can enable/disable contaminant presence detection through
* enableContaminantPresenceDetection when true.
*/
boolean supportsEnableContaminantPresenceDetection;
/**
* Current status of contaminant detection algorithm.
*/
ContaminantDetectionStatus contaminantDetectionStatus = ContaminantDetectionStatus.NOT_SUPPORTED;
/**
* UsbData status of the port.
*/
boolean usbDataEnabled;
/**
* Denoted whether power transfer is limited in the port.
*/
boolean powerTransferLimited;
}

View File

@@ -0,0 +1,39 @@
/*
* 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;
@VintfStability
@Backing(type="int")
enum Status {
SUCCESS = 0,
/**
* error value when the HAL operation fails for reasons not listed here.
*/
ERROR = 1,
/**
* error value returned when input argument is invalid.
*/
INVALID_ARGUMENT = 2,
/**
* error value returned when role string is unrecognized.
*/
UNRECOGNIZED_ROLE = 3,
/**
* Error value returned when the operation is not supported.
*/
NOT_SUPPORTED = 4,
}

11
usb/aidl/conversion.log Normal file
View File

@@ -0,0 +1,11 @@
Notes relating to hidl2aidl conversion of android.hardware.usb@1.3 to android.hardware.usb (if any) follow:
Unhandled comments from android.hardware.usb@1.1::types follow. Consider using hidl-lint to locate these and fixup as many as possible.
// NOTE: suffix '_1_1' is for legacy ABI compatibility. It cannot be
// changed to 'PortMode' which the convention dictates.
// NOTE: suffix '_1_1' is for legacy ABI compatibility. It cannot be
// changed to 'PortStatus' which the convention dictates.
An unknown named type was found in translation: android.hardware.usb@1.0::PortStatus
An unknown named type was found in translation: android.hardware.usb@1.0::PortStatus
An unknown named type was found in translation: android.hardware.usb@1.0::PortStatus
END OF LOG

View File

@@ -0,0 +1,35 @@
//
// 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.
//
cc_binary {
name: "android.hardware.usb-service.example",
relative_install_path: "hw",
init_rc: ["android.hardware.usb-service.example.rc"],
vintf_fragments: ["android.hardware.usb-service.example.xml"],
vendor: true,
srcs: [
"service.cpp",
"Usb.cpp",
],
shared_libs: [
"android.hardware.usb-V1-ndk",
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
"libutils",
],
}

711
usb/aidl/default/Usb.cpp Normal file
View File

@@ -0,0 +1,711 @@
/*
* 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.
*/
#define LOG_TAG "android.hardware.usb.aidl-service"
#include <aidl/android/hardware/usb/PortRole.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <assert.h>
#include <dirent.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
#include <regex>
#include <thread>
#include <unordered_map>
#include <cutils/uevent.h>
#include <sys/epoll.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include "Usb.h"
using android::base::GetProperty;
using android::base::Trim;
namespace aidl {
namespace android {
namespace hardware {
namespace usb {
constexpr char kTypecPath[] = "/sys/class/typec/";
constexpr char kDataRoleNode[] = "/data_role";
constexpr char kPowerRoleNode[] = "/power_role";
// Set by the signal handler to destroy the thread
volatile bool destroyThread;
void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus);
ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable, int64_t in_transactionId) {
std::vector<PortStatus> currentPortStatus;
pthread_mutex_lock(&mLock);
if (mCallback != NULL) {
ScopedAStatus ret = mCallback->notifyEnableUsbDataStatus(
in_portName, true, in_enable ? Status::SUCCESS : Status::ERROR, in_transactionId);
if (!ret.isOk())
ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
} else {
ALOGE("Not notifying the userspace. Callback is not set");
}
pthread_mutex_unlock(&mLock);
queryVersionHelper(this, &currentPortStatus);
return ScopedAStatus::ok();
}
Status queryMoistureDetectionStatus(std::vector<PortStatus> *currentPortStatus) {
string enabled, status, path, DetectedPath;
for (int i = 0; i < currentPortStatus->size(); i++) {
(*currentPortStatus)[i].supportedContaminantProtectionModes
.push_back(ContaminantProtectionMode::NONE);
(*currentPortStatus)[i].contaminantProtectionStatus
= ContaminantProtectionStatus::NONE;
(*currentPortStatus)[i].contaminantDetectionStatus
= ContaminantDetectionStatus::NOT_SUPPORTED;
(*currentPortStatus)[i].supportsEnableContaminantPresenceDetection = false;
(*currentPortStatus)[i].supportsEnableContaminantPresenceProtection = false;
}
return Status::SUCCESS;
}
string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
string node(kTypecPath + portName);
switch (tag) {
case PortRole::dataRole:
return node + kDataRoleNode;
case PortRole::powerRole:
return node + kPowerRoleNode;
case PortRole::mode:
return node + "/port_type";
default:
return "";
}
}
string convertRoletoString(PortRole role) {
if (role.getTag() == PortRole::powerRole) {
if (role.get<PortRole::powerRole>() == PortPowerRole::SOURCE)
return "source";
else if (role.get<PortRole::powerRole>() == PortPowerRole::SINK)
return "sink";
} else if (role.getTag() == PortRole::dataRole) {
if (role.get<PortRole::dataRole>() == PortDataRole::HOST)
return "host";
if (role.get<PortRole::dataRole>() == PortDataRole::DEVICE)
return "device";
} else if (role.getTag() == PortRole::mode) {
if (role.get<PortRole::mode>() == PortMode::UFP)
return "sink";
if (role.get<PortRole::mode>() == PortMode::DFP)
return "source";
}
return "none";
}
void extractRole(string *roleName) {
std::size_t first, last;
first = roleName->find("[");
last = roleName->find("]");
if (first != string::npos && last != string::npos) {
*roleName = roleName->substr(first + 1, last - first - 1);
}
}
void switchToDrp(const string &portName) {
string filename = appendRoleNodeHelper(string(portName.c_str()), PortRole::mode);
FILE *fp;
if (filename != "") {
fp = fopen(filename.c_str(), "w");
if (fp != NULL) {
int ret = fputs("dual", fp);
fclose(fp);
if (ret == EOF)
ALOGE("Fatal: Error while switching back to drp");
} else {
ALOGE("Fatal: Cannot open file to switch back to drp");
}
} else {
ALOGE("Fatal: invalid node type");
}
}
bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb) {
string filename = appendRoleNodeHelper(string(portName.c_str()), in_role.getTag());
string written;
FILE *fp;
bool roleSwitch = false;
if (filename == "") {
ALOGE("Fatal: invalid node type");
return false;
}
fp = fopen(filename.c_str(), "w");
if (fp != NULL) {
// Hold the lock here to prevent loosing connected signals
// as once the file is written the partner added signal
// can arrive anytime.
pthread_mutex_lock(&usb->mPartnerLock);
usb->mPartnerUp = false;
int ret = fputs(convertRoletoString(in_role).c_str(), fp);
fclose(fp);
if (ret != EOF) {
struct timespec to;
struct timespec now;
wait_again:
clock_gettime(CLOCK_MONOTONIC, &now);
to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
to.tv_nsec = now.tv_nsec;
int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
// There are no uevent signals which implies role swap timed out.
if (err == ETIMEDOUT) {
ALOGI("uevents wait timedout");
// Validity check.
} else if (!usb->mPartnerUp) {
goto wait_again;
// Role switch succeeded since usb->mPartnerUp is true.
} else {
roleSwitch = true;
}
} else {
ALOGI("Role switch failed while wrting to file");
}
pthread_mutex_unlock(&usb->mPartnerLock);
}
if (!roleSwitch)
switchToDrp(string(portName.c_str()));
return roleSwitch;
}
Usb::Usb()
: mLock(PTHREAD_MUTEX_INITIALIZER),
mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
mPartnerUp(false)
{
pthread_condattr_t attr;
if (pthread_condattr_init(&attr)) {
ALOGE("pthread_condattr_init failed: %s", strerror(errno));
abort();
}
if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
abort();
}
if (pthread_cond_init(&mPartnerCV, &attr)) {
ALOGE("pthread_cond_init failed: %s", strerror(errno));
abort();
}
if (pthread_condattr_destroy(&attr)) {
ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
abort();
}
}
ScopedAStatus Usb::switchRole(const string& in_portName,
const PortRole& in_role, int64_t in_transactionId) {
string filename = appendRoleNodeHelper(string(in_portName.c_str()), in_role.getTag());
string written;
FILE *fp;
bool roleSwitch = false;
if (filename == "") {
ALOGE("Fatal: invalid node type");
return ScopedAStatus::ok();
}
pthread_mutex_lock(&mRoleSwitchLock);
ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(in_role).c_str());
if (in_role.getTag() == PortRole::mode) {
roleSwitch = switchMode(in_portName, in_role, this);
} else {
fp = fopen(filename.c_str(), "w");
if (fp != NULL) {
int ret = fputs(convertRoletoString(in_role).c_str(), fp);
fclose(fp);
if ((ret != EOF) && ReadFileToString(filename, &written)) {
written = Trim(written);
extractRole(&written);
ALOGI("written: %s", written.c_str());
if (written == convertRoletoString(in_role)) {
roleSwitch = true;
} else {
ALOGE("Role switch failed");
}
} else {
ALOGE("failed to update the new role");
}
} else {
ALOGE("fopen failed");
}
}
pthread_mutex_lock(&mLock);
if (mCallback != NULL) {
ScopedAStatus ret = mCallback->notifyRoleSwitchStatus(
in_portName, in_role, roleSwitch ? Status::SUCCESS : Status::ERROR, in_transactionId);
if (!ret.isOk())
ALOGE("RoleSwitchStatus error %s", ret.getDescription().c_str());
} else {
ALOGE("Not notifying the userspace. Callback is not set");
}
pthread_mutex_unlock(&mLock);
pthread_mutex_unlock(&mRoleSwitchLock);
return ScopedAStatus::ok();
}
ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool /*in_limit*/,
int64_t in_transactionId) {
std::vector<PortStatus> currentPortStatus;
pthread_mutex_lock(&mLock);
if (mCallback != NULL && in_transactionId >= 0) {
ScopedAStatus ret = mCallback->notifyLimitPowerTransferStatus(
in_portName, false, Status::NOT_SUPPORTED, in_transactionId);
if (!ret.isOk())
ALOGE("limitPowerTransfer error %s", ret.getDescription().c_str());
} else {
ALOGE("Not notifying the userspace. Callback is not set");
}
pthread_mutex_unlock(&mLock);
return ScopedAStatus::ok();
}
Status getAccessoryConnected(const string &portName, string *accessory) {
string filename = kTypecPath + portName + "-partner/accessory_mode";
if (!ReadFileToString(filename, accessory)) {
ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
return Status::ERROR;
}
*accessory = Trim(*accessory);
return Status::SUCCESS;
}
Status getCurrentRoleHelper(const string &portName, bool connected, PortRole *currentRole) {
string filename;
string roleName;
string accessory;
// Mode
if (currentRole->getTag() == PortRole::powerRole) {
filename = kTypecPath + portName + kPowerRoleNode;
currentRole->set<PortRole::powerRole>(PortPowerRole::NONE);
} else if (currentRole->getTag() == PortRole::dataRole) {
filename = kTypecPath + portName + kDataRoleNode;
currentRole->set<PortRole::dataRole>(PortDataRole::NONE);
} else if (currentRole->getTag() == PortRole::mode) {
filename = kTypecPath + portName + kDataRoleNode;
currentRole->set<PortRole::mode>(PortMode::NONE);
} else {
return Status::ERROR;
}
if (!connected)
return Status::SUCCESS;
if (currentRole->getTag() == PortRole::mode) {
if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
return Status::ERROR;
}
if (accessory == "analog_audio") {
currentRole->set<PortRole::mode>(PortMode::AUDIO_ACCESSORY);
return Status::SUCCESS;
} else if (accessory == "debug") {
currentRole->set<PortRole::mode>(PortMode::DEBUG_ACCESSORY);
return Status::SUCCESS;
}
}
if (!ReadFileToString(filename, &roleName)) {
ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
return Status::ERROR;
}
roleName = Trim(roleName);
extractRole(&roleName);
if (roleName == "source") {
currentRole->set<PortRole::powerRole>(PortPowerRole::SOURCE);
} else if (roleName == "sink") {
currentRole->set<PortRole::powerRole>(PortPowerRole::SINK);
} else if (roleName == "host") {
if (currentRole->getTag() == PortRole::dataRole)
currentRole->set<PortRole::dataRole>(PortDataRole::HOST);
else
currentRole->set<PortRole::mode>(PortMode::DFP);
} else if (roleName == "device") {
if (currentRole->getTag() == PortRole::dataRole)
currentRole->set<PortRole::dataRole>(PortDataRole::DEVICE);
else
currentRole->set<PortRole::mode>(PortMode::UFP);
} else if (roleName != "none") {
/* case for none has already been addressed.
* so we check if the role isn't none.
*/
return Status::UNRECOGNIZED_ROLE;
}
return Status::SUCCESS;
}
Status getTypeCPortNamesHelper(std::unordered_map<string, bool> *names) {
DIR *dp;
dp = opendir(kTypecPath);
if (dp != NULL) {
struct dirent *ep;
while ((ep = readdir(dp))) {
if (ep->d_type == DT_LNK) {
if (string::npos == string(ep->d_name).find("-partner")) {
std::unordered_map<string, bool>::const_iterator portName =
names->find(ep->d_name);
if (portName == names->end()) {
names->insert({ep->d_name, false});
}
} else {
(*names)[std::strtok(ep->d_name, "-")] = true;
}
}
}
closedir(dp);
return Status::SUCCESS;
}
ALOGE("Failed to open /sys/class/typec");
return Status::ERROR;
}
bool canSwitchRoleHelper(const string &portName) {
string filename = kTypecPath + portName + "-partner/supports_usb_power_delivery";
string supportsPD;
if (ReadFileToString(filename, &supportsPD)) {
supportsPD = Trim(supportsPD);
if (supportsPD == "yes") {
return true;
}
}
return false;
}
Status getPortStatusHelper(std::vector<PortStatus> *currentPortStatus) {
std::unordered_map<string, bool> names;
Status result = getTypeCPortNamesHelper(&names);
int i = -1;
if (result == Status::SUCCESS) {
currentPortStatus->resize(names.size());
for (std::pair<string, bool> port : names) {
i++;
ALOGI("%s", port.first.c_str());
(*currentPortStatus)[i].portName = port.first;
PortRole currentRole;
currentRole.set<PortRole::powerRole>(PortPowerRole::NONE);
if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS){
(*currentPortStatus)[i].currentPowerRole = currentRole.get<PortRole::powerRole>();
} else {
ALOGE("Error while retrieving portNames");
goto done;
}
currentRole.set<PortRole::dataRole>(PortDataRole::NONE);
if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
(*currentPortStatus)[i].currentDataRole = currentRole.get<PortRole::dataRole>();
} else {
ALOGE("Error while retrieving current port role");
goto done;
}
currentRole.set<PortRole::mode>(PortMode::NONE);
if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
(*currentPortStatus)[i].currentMode = currentRole.get<PortRole::mode>();
} else {
ALOGE("Error while retrieving current data role");
goto done;
}
(*currentPortStatus)[i].canChangeMode = true;
(*currentPortStatus)[i].canChangeDataRole =
port.second ? canSwitchRoleHelper(port.first) : false;
(*currentPortStatus)[i].canChangePowerRole =
port.second ? canSwitchRoleHelper(port.first) : false;
(*currentPortStatus)[i].supportedModes.push_back(PortMode::DRP);
(*currentPortStatus)[i].usbDataEnabled = true;
ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
"usbDataEnabled:%d",
i, port.first.c_str(), port.second,
(*currentPortStatus)[i].canChangeMode,
(*currentPortStatus)[i].canChangeDataRole,
(*currentPortStatus)[i].canChangePowerRole, 0);
}
return Status::SUCCESS;
}
done:
return Status::ERROR;
}
void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus) {
Status status;
pthread_mutex_lock(&usb->mLock);
status = getPortStatusHelper(currentPortStatus);
queryMoistureDetectionStatus(currentPortStatus);
if (usb->mCallback != NULL) {
ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
status);
if (!ret.isOk())
ALOGE("queryPortStatus error %s", ret.getDescription().c_str());
} else {
ALOGI("Notifying userspace skipped. Callback is NULL");
}
pthread_mutex_unlock(&usb->mLock);
}
ScopedAStatus Usb::queryPortStatus(int64_t in_transactionId) {
std::vector<PortStatus> currentPortStatus;
queryVersionHelper(this, &currentPortStatus);
pthread_mutex_lock(&mLock);
if (mCallback != NULL) {
ScopedAStatus ret = mCallback->notifyQueryPortStatus(
"all", Status::SUCCESS, in_transactionId);
if (!ret.isOk())
ALOGE("notifyQueryPortStatus error %s", ret.getDescription().c_str());
} else {
ALOGE("Not notifying the userspace. Callback is not set");
}
pthread_mutex_unlock(&mLock);
return ScopedAStatus::ok();
}
ScopedAStatus Usb::enableContaminantPresenceDetection(const string& in_portName,
bool /*in_enable*/, int64_t in_transactionId) {
std::vector<PortStatus> currentPortStatus;
pthread_mutex_lock(&mLock);
if (mCallback != NULL) {
ScopedAStatus ret = mCallback->notifyContaminantEnabledStatus(
in_portName, false, Status::ERROR, in_transactionId);
if (!ret.isOk())
ALOGE("enableContaminantPresenceDetection error %s", ret.getDescription().c_str());
} else {
ALOGE("Not notifying the userspace. Callback is not set");
}
pthread_mutex_unlock(&mLock);
queryVersionHelper(this, &currentPortStatus);
return ScopedAStatus::ok();
}
struct data {
int uevent_fd;
::aidl::android::hardware::usb::Usb *usb;
};
static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
char msg[UEVENT_MSG_LEN + 2];
char *cp;
int n;
n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0)
return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n + 1] = '\0';
cp = msg;
while (*cp) {
if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
ALOGI("partner added");
pthread_mutex_lock(&payload->usb->mPartnerLock);
payload->usb->mPartnerUp = true;
pthread_cond_signal(&payload->usb->mPartnerCV);
pthread_mutex_unlock(&payload->usb->mPartnerLock);
} else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_"))) {
std::vector<PortStatus> currentPortStatus;
queryVersionHelper(payload->usb, &currentPortStatus);
// Role switch is not in progress and port is in disconnected state
if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
for (unsigned long i = 0; i < currentPortStatus.size(); i++) {
DIR *dp =
opendir(string(kTypecPath +
string(currentPortStatus[i].portName.c_str()) +
"-partner").c_str());
if (dp == NULL) {
switchToDrp(currentPortStatus[i].portName);
} else {
closedir(dp);
}
}
pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
}
break;
} /* advance to after the next \0 */
while (*cp++) {
}
}
}
void *work(void *param) {
int epoll_fd, uevent_fd;
struct epoll_event ev;
int nevents = 0;
struct data payload;
uevent_fd = uevent_open_socket(UEVENT_MAX_EVENTS * UEVENT_MSG_LEN, true);
if (uevent_fd < 0) {
ALOGE("uevent_init: uevent_open_socket failed\n");
return NULL;
}
payload.uevent_fd = uevent_fd;
payload.usb = (::aidl::android::hardware::usb::Usb *)param;
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
ev.events = EPOLLIN;
ev.data.ptr = (void *)uevent_event;
epoll_fd = epoll_create(UEVENT_MAX_EVENTS);
if (epoll_fd == -1) {
ALOGE("epoll_create failed; errno=%d", errno);
goto error;
}
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
ALOGE("epoll_ctl failed; errno=%d", errno);
goto error;
}
while (!destroyThread) {
struct epoll_event events[UEVENT_MAX_EVENTS];
nevents = epoll_wait(epoll_fd, events, UEVENT_MAX_EVENTS, -1);
if (nevents == -1) {
if (errno == EINTR)
continue;
ALOGE("usb epoll_wait failed; errno=%d", errno);
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
&payload);
}
}
ALOGI("exiting worker thread");
error:
close(uevent_fd);
if (epoll_fd >= 0)
close(epoll_fd);
return NULL;
}
void sighandler(int sig) {
if (sig == SIGUSR1) {
destroyThread = true;
ALOGI("destroy set");
return;
}
signal(SIGUSR1, sighandler);
}
ScopedAStatus Usb::setCallback(
const shared_ptr<IUsbCallback>& in_callback) {
pthread_mutex_lock(&mLock);
if ((mCallback == NULL && in_callback == NULL) ||
(mCallback != NULL && in_callback != NULL)) {
mCallback = in_callback;
pthread_mutex_unlock(&mLock);
return ScopedAStatus::ok();
}
mCallback = in_callback;
ALOGI("registering callback");
if (mCallback == NULL) {
if (!pthread_kill(mPoll, SIGUSR1)) {
pthread_join(mPoll, NULL);
ALOGI("pthread destroyed");
}
pthread_mutex_unlock(&mLock);
return ScopedAStatus::ok();
}
destroyThread = false;
signal(SIGUSR1, sighandler);
/*
* Create a background thread if the old callback value is NULL
* and being updated with a new value.
*/
if (pthread_create(&mPoll, NULL, work, this)) {
ALOGE("pthread creation failed %d", errno);
mCallback = NULL;
}
pthread_mutex_unlock(&mLock);
return ScopedAStatus::ok();
}
} // namespace usb
} // namespace hardware
} // namespace android
} // aidl

78
usb/aidl/default/Usb.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* 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.
*/
#pragma once
#include <android-base/file.h>
#include <aidl/android/hardware/usb/BnUsb.h>
#include <aidl/android/hardware/usb/BnUsbCallback.h>
#include <utils/Log.h>
#define UEVENT_MSG_LEN 2048
#define UEVENT_MAX_EVENTS 64
// The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd.
// The -partner directory would not be created until this is done.
// Having a margin of ~3 secs for the directory and other related bookeeping
// structures created and uvent fired.
#define PORT_TYPE_TIMEOUT 8
namespace aidl {
namespace android {
namespace hardware {
namespace usb {
using ::aidl::android::hardware::usb::IUsbCallback;
using ::aidl::android::hardware::usb::PortRole;
using ::android::base::ReadFileToString;
using ::android::base::WriteStringToFile;
using ::android::sp;
using ::ndk::ScopedAStatus;
using ::std::shared_ptr;
using ::std::string;
struct Usb : public BnUsb {
Usb();
ScopedAStatus enableContaminantPresenceDetection(const std::string& in_portName,
bool in_enable, int64_t in_transactionId) override;
ScopedAStatus queryPortStatus(int64_t in_transactionId) override;
ScopedAStatus setCallback(const shared_ptr<IUsbCallback>& in_callback) override;
ScopedAStatus switchRole(const string& in_portName, const PortRole& in_role,
int64_t in_transactionId) override;
ScopedAStatus enableUsbData(const string& in_portName, bool in_enable,
int64_t in_transactionId) override;
ScopedAStatus limitPowerTransfer(const std::string& in_portName, bool in_limit,
int64_t in_transactionId)override;
shared_ptr<IUsbCallback> mCallback;
// Protects mCallback variable
pthread_mutex_t mLock;
// Protects roleSwitch operation
pthread_mutex_t mRoleSwitchLock;
// Threads waiting for the partner to come back wait here
pthread_cond_t mPartnerCV;
// lock protecting mPartnerCV
pthread_mutex_t mPartnerLock;
// Variable to signal partner coming back online after type switch
bool mPartnerUp;
private:
pthread_t mPoll;
};
} // namespace usb
} // namespace hardware
} // namespace android
} // aidl

View File

@@ -0,0 +1,4 @@
service vendor.usb_default /vendor/bin/hw/android.hardware.usb-service.example
class hal
user system
group system

View File

@@ -0,0 +1,10 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.usb</name>
<version>1</version>
<interface>
<name>IUsb</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View File

@@ -0,0 +1,35 @@
/*
* 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.
*/
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "Usb.h"
using ::aidl::android::hardware::usb::Usb;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Usb> usb = ndk::SharedRefBase::make<Usb>();
const std::string instance = std::string() + Usb::descriptor + "/default";
binder_status_t status = AServiceManager_addService(usb->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
return -1; // Should never be reached
}

43
usb/aidl/vts/Android.bp Normal file
View File

@@ -0,0 +1,43 @@
//
// 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_test {
name: "VtsAidlUsbTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: ["VtsAidlUsbTargetTest.cpp"],
shared_libs: [
"libbinder_ndk",
],
static_libs: [
"android.hardware.usb-V1-ndk",
],
test_suites: [
"general-tests",
"vts",
],
}

View File

@@ -0,0 +1,473 @@
/*
* Copyright (C) 2021 The Android Open Source Probject
*
* 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.
*/
#define LOG_TAG "UsbAidlTest"
#include <android-base/logging.h>
#include <aidl/android/hardware/usb/IUsb.h>
#include <aidl/android/hardware/usb/IUsbCallback.h>
#include <aidl/android/hardware/usb/BnUsbCallback.h>
#include <aidl/android/hardware/usb/PortDataRole.h>
#include <aidl/android/hardware/usb/PortMode.h>
#include <aidl/android/hardware/usb/PortPowerRole.h>
#include <aidl/android/hardware/usb/PortRole.h>
#include <aidl/android/hardware/usb/PortStatus.h>
#include <aidl/android/hardware/usb/Status.h>
#include <aidl/Vintf.h>
#include <aidl/Gtest.h>
#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <stdlib.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
#define TIMEOUT_PERIOD 10
using ::aidl::android::hardware::usb::BnUsbCallback;
using ::aidl::android::hardware::usb::IUsb;
using ::aidl::android::hardware::usb::IUsbCallback;
using ::aidl::android::hardware::usb::PortDataRole;
using ::aidl::android::hardware::usb::PortMode;
using ::aidl::android::hardware::usb::PortPowerRole;
using ::aidl::android::hardware::usb::PortRole;
using ::aidl::android::hardware::usb::PortStatus;
using ::aidl::android::hardware::usb::Status;
using ::ndk::ScopedAStatus;
using ::ndk::SpAIBinder;
using std::vector;
using std::shared_ptr;
using std::string;
// The main test class for the USB aidl hal
class UsbAidlTest : public testing::TestWithParam<std::string> {
public:
// Callback class for the USB aidl hal.
// Usb Hal will call this object upon role switch or port query.
class UsbCallback : public BnUsbCallback {
UsbAidlTest& parent_;
int cookie;
public:
UsbCallback(UsbAidlTest& parent, int cookie)
: parent_(parent), cookie(cookie){};
virtual ~UsbCallback() = default;
// Callback method for the port status.
ScopedAStatus notifyPortStatusChange(const vector<PortStatus>& currentPortStatus,
Status retval) override {
if (retval == Status::SUCCESS && currentPortStatus.size() > 0) {
parent_.usb_last_port_status.portName =
currentPortStatus[0].portName.c_str();
parent_.usb_last_port_status.currentDataRole =
currentPortStatus[0].currentDataRole;
parent_.usb_last_port_status.currentPowerRole =
currentPortStatus[0].currentPowerRole;
parent_.usb_last_port_status.currentMode =
currentPortStatus[0].currentMode;
}
parent_.usb_last_cookie = cookie;
return ScopedAStatus::ok();
}
// Callback method for the status of role switch operation.
ScopedAStatus notifyRoleSwitchStatus(const string& /*portName*/, const PortRole& newRole,
Status retval, int64_t transactionId) override {
parent_.usb_last_status = retval;
parent_.usb_last_cookie = cookie;
parent_.usb_last_port_role = newRole;
parent_.usb_role_switch_done = true;
parent_.last_transactionId = transactionId;
parent_.notify();
return ScopedAStatus::ok();
}
// Callback method for the status of enableUsbData operation
ScopedAStatus notifyEnableUsbDataStatus(const string& /*portName*/, bool /*enable*/,
Status /*retval*/, int64_t transactionId) override {
parent_.last_transactionId = transactionId;
parent_.usb_last_cookie = cookie;
parent_.enable_usb_data_done = true;
parent_.notify();
return ScopedAStatus::ok();
}
// Callback method for the status of enableContaminantPresenceDetection
ScopedAStatus notifyContaminantEnabledStatus(const string& /*portName*/, bool /*enable*/,
Status /*retval*/, int64_t transactionId) override {
parent_.last_transactionId = transactionId;
parent_.usb_last_cookie = cookie;
parent_.enable_contaminant_done = true;
parent_.notify();
return ScopedAStatus::ok();
}
// Callback method for the status of queryPortStatus operation
ScopedAStatus notifyQueryPortStatus(const string& /*portName*/, Status /*retval*/,
int64_t transactionId) override {
parent_.last_transactionId = transactionId;
parent_.notify();
return ScopedAStatus::ok();
}
// Callback method for the status of limitPowerTransfer operation
ScopedAStatus notifyLimitPowerTransferStatus(const string& /*portName*/, bool /*limit*/,
Status /*retval*/, int64_t transactionId) override {
parent_.last_transactionId = transactionId;
parent_.usb_last_cookie = cookie;
parent_.limit_power_transfer_done = true;
parent_.notify();
return ScopedAStatus::ok();
}
};
virtual void SetUp() override {
ALOGI("Setup");
usb = IUsb::fromBinder(
SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
ASSERT_NE(usb, nullptr);
usb_cb_2 = ::ndk::SharedRefBase::make<UsbCallback>(*this, 2);
ASSERT_NE(usb_cb_2, nullptr);
const auto& ret = usb->setCallback(usb_cb_2);
ASSERT_TRUE(ret.isOk());
}
virtual void TearDown() override { ALOGI("Teardown"); }
// Used as a mechanism to inform the test about data/event callback.
inline void notify() {
std::unique_lock<std::mutex> lock(usb_mtx);
usb_count++;
usb_cv.notify_one();
}
// Test code calls this function to wait for data/event callback.
inline std::cv_status wait() {
std::unique_lock<std::mutex> lock(usb_mtx);
std::cv_status status = std::cv_status::no_timeout;
auto now = std::chrono::system_clock::now();
while (usb_count == 0) {
status =
usb_cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
if (status == std::cv_status::timeout) {
ALOGI("timeout");
return status;
}
}
usb_count--;
return status;
}
// USB aidl hal Proxy
shared_ptr<IUsb> usb;
// Callback objects for usb aidl
// Methods of these objects are called to notify port status updates.
shared_ptr<IUsbCallback> usb_cb_1, usb_cb_2;
// The last conveyed status of the USB ports.
// Stores information of currentt_data_role, power_role for all the USB ports
PortStatus usb_last_port_status;
// Status of the last role switch operation.
Status usb_last_status;
// Port role information of the last role switch operation.
PortRole usb_last_port_role;
// Flag to indicate the invocation of role switch callback.
bool usb_role_switch_done;
// Flag to indicate the invocation of notifyContaminantEnabledStatus callback.
bool enable_contaminant_done;
// Flag to indicate the invocation of notifyEnableUsbDataStatus callback.
bool enable_usb_data_done;
// Flag to indicate the invocation of notifyLimitPowerTransferStatus callback.
bool limit_power_transfer_done;
// Stores the cookie of the last invoked usb callback object.
int usb_last_cookie;
// Last transaction ID that was recorded.
int64_t last_transactionId;
// synchronization primitives to coordinate between main test thread
// and the callback thread.
std::mutex usb_mtx;
std::condition_variable usb_cv;
int usb_count = 0;
};
/*
* Test to see if setCallback succeeds.
* Callback object is created and registered.
*/
TEST_P(UsbAidlTest, setCallback) {
ALOGI("UsbAidlTest setCallback start");
usb_cb_1 = ::ndk::SharedRefBase::make<UsbCallback>(*this, 1);
ASSERT_NE(usb_cb_1, nullptr);
const auto& ret = usb->setCallback(usb_cb_1);
ASSERT_TRUE(ret.isOk());
ALOGI("UsbAidlTest setCallback end");
}
/*
* Check to see if querying type-c
* port status succeeds.
* The callback parameters are checked to see if the transaction id
* matches.
*/
TEST_P(UsbAidlTest, queryPortStatus) {
ALOGI("UsbAidlTest queryPortStatus start");
int64_t transactionId = rand() % 10000;
const auto& ret = usb->queryPortStatus(transactionId);
ASSERT_TRUE(ret.isOk());
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
ALOGI("UsbAidlTest queryPortStatus end: %s", usb_last_port_status.portName.c_str());
}
/*
* Trying to switch a non-existent port should fail.
* This test case tried to switch the port with empty
* name which is expected to fail.
* The callback parameters are checked to see if the transaction id
* matches.
*/
TEST_P(UsbAidlTest, switchEmptyPort) {
ALOGI("UsbAidlTest switchEmptyPort start");
PortRole role;
role.set<PortRole::powerRole>(PortPowerRole::SOURCE);
int64_t transactionId = rand() % 10000;
const auto& ret = usb->switchRole("", role, transactionId);
ASSERT_TRUE(ret.isOk());
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(Status::ERROR, usb_last_status);
EXPECT_EQ(transactionId, last_transactionId);
EXPECT_EQ(2, usb_last_cookie);
ALOGI("UsbAidlTest switchEmptyPort end");
}
/*
* Test switching the power role of usb port.
* Test case queries the usb ports present in device.
* If there is at least one usb port, a power role switch
* to SOURCE is attempted for the port.
* The callback parameters are checked to see if the transaction id
* matches.
*/
TEST_P(UsbAidlTest, switchPowerRole) {
ALOGI("UsbAidlTest switchPowerRole start");
PortRole role;
role.set<PortRole::powerRole>(PortPowerRole::SOURCE);
int64_t transactionId = rand() % 10000;
const auto& ret = usb->queryPortStatus(transactionId);
ASSERT_TRUE(ret.isOk());
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
if (!usb_last_port_status.portName.empty()) {
string portBeingSwitched = usb_last_port_status.portName;
ALOGI("switchPower role portname:%s", portBeingSwitched.c_str());
usb_role_switch_done = false;
transactionId = rand() % 10000;
const auto& ret = usb->switchRole(portBeingSwitched, role, transactionId);
ASSERT_TRUE(ret.isOk());
std::cv_status waitStatus = wait();
while (waitStatus == std::cv_status::no_timeout &&
usb_role_switch_done == false)
waitStatus = wait();
EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
}
ALOGI("UsbAidlTest switchPowerRole end");
}
/*
* Test switching the data role of usb port.
* Test case queries the usb ports present in device.
* If there is at least one usb port, a data role switch
* to device is attempted for the port.
* The callback parameters are checked to see if transaction id
* matches.
*/
TEST_P(UsbAidlTest, switchDataRole) {
ALOGI("UsbAidlTest switchDataRole start");
PortRole role;
role.set<PortRole::dataRole>(PortDataRole::DEVICE);
int64_t transactionId = rand() % 10000;
const auto& ret = usb->queryPortStatus(transactionId);
ASSERT_TRUE(ret.isOk());
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
if (!usb_last_port_status.portName.empty()) {
string portBeingSwitched = usb_last_port_status.portName;
ALOGI("portname:%s", portBeingSwitched.c_str());
usb_role_switch_done = false;
transactionId = rand() % 10000;
const auto& ret = usb->switchRole(portBeingSwitched, role, transactionId);
ASSERT_TRUE(ret.isOk());
std::cv_status waitStatus = wait();
while (waitStatus == std::cv_status::no_timeout &&
usb_role_switch_done == false)
waitStatus = wait();
EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
}
ALOGI("UsbAidlTest switchDataRole end");
}
/*
* Test enabling contaminant presence detection of the port.
* Test case queries the usb ports present in device.
* If there is at least one usb port, enabling contaminant detection
* is attempted for the port.
* The callback parameters are checked to see if transaction id
* matches.
*/
TEST_P(UsbAidlTest, enableContaminantPresenceDetection) {
ALOGI("UsbAidlTest enableContaminantPresenceDetection start");
int64_t transactionId = rand() % 10000;
const auto& ret = usb->queryPortStatus(transactionId);
ASSERT_TRUE(ret.isOk());
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
if (!usb_last_port_status.portName.empty()) {
ALOGI("portname:%s", usb_last_port_status.portName.c_str());
enable_contaminant_done = false;
transactionId = rand() % 10000;
const auto& ret = usb->enableContaminantPresenceDetection(usb_last_port_status.portName,
true, transactionId);
ASSERT_TRUE(ret.isOk());
std::cv_status waitStatus = wait();
while (waitStatus == std::cv_status::no_timeout &&
enable_contaminant_done == false)
waitStatus = wait();
EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
}
ALOGI("UsbAidlTest enableContaminantPresenceDetection end");
}
/*
* Test enabling Usb data of the port.
* Test case queries the usb ports present in device.
* If there is at least one usb port, enabling Usb data is attempted
* for the port.
* The callback parameters are checked to see if transaction id
* matches.
*/
TEST_P(UsbAidlTest, enableUsbData) {
ALOGI("UsbAidlTest enableUsbData start");
int64_t transactionId = rand() % 10000;
const auto& ret = usb->queryPortStatus(transactionId);
ASSERT_TRUE(ret.isOk());
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
if (!usb_last_port_status.portName.empty()) {
ALOGI("portname:%s", usb_last_port_status.portName.c_str());
enable_usb_data_done = false;
transactionId = rand() % 10000;
const auto& ret = usb->enableUsbData(usb_last_port_status.portName, true, transactionId);
ASSERT_TRUE(ret.isOk());
std::cv_status waitStatus = wait();
while (waitStatus == std::cv_status::no_timeout &&
enable_usb_data_done == false)
waitStatus = wait();
EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
}
ALOGI("UsbAidlTest enableUsbData end");
}
/*
* Test enabling Usb data of the port.
* Test case queries the usb ports present in device.
* If there is at least one usb port, relaxing limit power transfer
* is attempted for the port.
* The callback parameters are checked to see if transaction id
* matches.
*/
TEST_P(UsbAidlTest, limitPowerTransfer) {
ALOGI("UsbAidlTest limitPowerTransfer start");
int64_t transactionId = rand() % 10000;
const auto& ret = usb->queryPortStatus(transactionId);
ASSERT_TRUE(ret.isOk());
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
if (!usb_last_port_status.portName.empty()) {
ALOGI("portname:%s", usb_last_port_status.portName.c_str());
limit_power_transfer_done = false;
transactionId = rand() % 10000;
const auto& ret = usb->limitPowerTransfer(usb_last_port_status.portName, false, transactionId);
ASSERT_TRUE(ret.isOk());
std::cv_status waitStatus = wait();
while (waitStatus == std::cv_status::no_timeout &&
limit_power_transfer_done == false)
waitStatus = wait();
EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
EXPECT_EQ(2, usb_last_cookie);
EXPECT_EQ(transactionId, last_transactionId);
}
ALOGI("UsbAidlTest limitPowerTransfer end");
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UsbAidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, UsbAidlTest,
testing::ValuesIn(::android::getAidlHalInstanceNames(IUsb::descriptor)),
::android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}