Merge "wifi: add API for setting roaming consortium selection"
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
index f035baf..ae57125 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
@@ -34,5 +34,6 @@
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalAudioV6_0TargetTest" />
+ <option name="native-test-timeout" value="5m" />
</test>
</configuration>
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
index 6635f31..55dbaf1 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
@@ -34,5 +34,6 @@
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalAudioV7_0TargetTest" />
+ <option name="native-test-timeout" value="5m" />
</test>
</configuration>
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
new file mode 100644
index 0000000..3c0aa13
--- /dev/null
+++ b/automotive/evs/aidl/Android.bp
@@ -0,0 +1,51 @@
+// 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 {
+ // 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"],
+}
+
+aidl_interface {
+ name: "android.hardware.automotive.evs",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/automotive/evs/*.aidl"
+ ],
+ stability: "vintf",
+ imports: [
+ "android.hardware.common-V2",
+ "android.hardware.graphics.common-V3",
+ ],
+ backend: {
+ java: {
+ // android.hardware.graphics.common package is not enabled
+ // for Java backend.
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ ndk: {
+ vndk: {
+ enabled: false,
+ },
+ min_sdk_version: "29"
+ },
+ },
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/BufferDesc.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/BufferDesc.aidl
index 7ef08d2..31acdb8 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/BufferDesc.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,13 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable BufferDesc {
+ android.hardware.graphics.common.HardwareBuffer buffer;
+ int pixelSizeBytes;
+ int bufferId;
+ @utf8InCpp String deviceId;
+ long timestamp;
+ byte[] metadata;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraDesc.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraDesc.aidl
index 7ef08d2..4dadeb8 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraDesc.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable CameraDesc {
+ @utf8InCpp String id;
+ int vendorFlags;
+ byte[] metadata;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraParam.aidl
similarity index 79%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraParam.aidl
index 7ef08d2..ae4ce77 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/CameraParam.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,19 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.automotive.evs;
+@Backing(type="int") @VintfStability
+enum CameraParam {
+ BRIGHTNESS = 0,
+ CONTRAST = 1,
+ AUTOGAIN = 2,
+ GAIN = 3,
+ AUTO_WHITE_BALANCE = 4,
+ WHITE_BALANCE_TEMPERATURE = 5,
+ SHARPNESS = 6,
+ AUTO_EXPOSURE = 7,
+ ABSOLUTE_EXPOSURE = 8,
+ ABSOLUTE_FOCUS = 9,
+ AUTO_FOCUS = 10,
+ ABSOLUTE_ZOOM = 11,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatus.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatus.aidl
index 7ef08d2..cc066ac 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatus.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable DeviceStatus {
+ @utf8InCpp String id;
+ android.hardware.automotive.evs.DeviceStatusType status;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatusType.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatusType.aidl
index 7ef08d2..d0f1d8e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DeviceStatusType.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.automotive.evs;
+@Backing(type="int") @VintfStability
+enum DeviceStatusType {
+ CAMERA_AVAILABLE = 0,
+ CAMERA_NOT_AVAILABLE = 1,
+ DISPLAY_AVAILABLE = 2,
+ DISPLAY_NOT_AVAILABLE = 3,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayDesc.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayDesc.aidl
index 7ef08d2..4ac029e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayDesc.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,12 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable DisplayDesc {
+ @utf8InCpp String id;
+ int width;
+ int height;
+ android.hardware.automotive.evs.Rotation orientation;
+ int vendorFlags;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayState.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayState.aidl
index 7ef08d2..a5f4309 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/DisplayState.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,12 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.automotive.evs;
+@Backing(type="int") @VintfStability
+enum DisplayState {
+ NOT_OPEN = 0,
+ NOT_VISIBLE = 1,
+ VISIBLE_ON_NEXT_FRAME = 2,
+ VISIBLE = 3,
+ DEAD = 4,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventDesc.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventDesc.aidl
index 7ef08d2..09b2b9d 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventDesc.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable EvsEventDesc {
+ android.hardware.automotive.evs.EvsEventType aType;
+ @utf8InCpp String deviceId;
+ int[] payload;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventType.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventType.aidl
index 7ef08d2..052a6b3 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsEventType.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,14 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.automotive.evs;
+@Backing(type="int") @VintfStability
+enum EvsEventType {
+ STREAM_STARTED = 0,
+ STREAM_STOPPED = 1,
+ FRAME_DROPPED = 2,
+ TIMEOUT = 3,
+ PARAMETER_CHANGED = 4,
+ MASTER_RELEASED = 5,
+ STREAM_ERROR = 6,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsResult.aidl
similarity index 79%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsResult.aidl
index 7ef08d2..a0418a9 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/EvsResult.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,18 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.automotive.evs;
+@Backing(type="int") @VintfStability
+enum EvsResult {
+ OK = 0,
+ INVALID_ARG = 1,
+ STREAM_ALREADY_RUNNING = 2,
+ BUFFER_NOT_AVAILABLE = 3,
+ OWNERSHIP_LOST = 4,
+ UNDERLYING_SERVICE_ERROR = 5,
+ PERMISSION_DENIED = 6,
+ RESOURCE_NOT_AVAILABLE = 7,
+ RESOURCE_BUSY = 8,
+ NOT_IMPLEMENTED = 9,
+ NOT_SUPPORTED = 10,
}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCamera.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCamera.aidl
new file mode 100644
index 0000000..ce1b97d
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCamera.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.automotive.evs;
+@VintfStability
+interface IEvsCamera {
+ void doneWithFrame(in android.hardware.automotive.evs.BufferDesc[] buffer);
+ void forcePrimaryClient(in android.hardware.automotive.evs.IEvsDisplay display);
+ android.hardware.automotive.evs.CameraDesc getCameraInfo();
+ byte[] getExtendedInfo(in int opaqueIdentifier);
+ int[] getIntParameter(in android.hardware.automotive.evs.CameraParam id);
+ android.hardware.automotive.evs.ParameterRange getIntParameterRange(in android.hardware.automotive.evs.CameraParam id);
+ android.hardware.automotive.evs.CameraParam[] getParameterList();
+ android.hardware.automotive.evs.CameraDesc getPhysicalCameraInfo(in String deviceId);
+ int importExternalBuffers(in android.hardware.automotive.evs.BufferDesc[] buffers);
+ void pauseVideoStream();
+ void resumeVideoStream();
+ void setExtendedInfo(in int opaqueIdentifier, in byte[] opaqueValue);
+ int[] setIntParameter(in android.hardware.automotive.evs.CameraParam id, in int value);
+ void setPrimaryClient();
+ void setMaxFramesInFlight(in int bufferCount);
+ void startVideoStream(in android.hardware.automotive.evs.IEvsCameraStream receiver);
+ void stopVideoStream();
+ void unsetPrimaryClient();
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCameraStream.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCameraStream.aidl
index 7ef08d2..6e2e64a 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsCameraStream.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IEvsCameraStream {
+ oneway void deliverFrame(in android.hardware.automotive.evs.BufferDesc[] buffer);
+ oneway void notify(in android.hardware.automotive.evs.EvsEventDesc event);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsDisplay.aidl
similarity index 76%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsDisplay.aidl
index 7ef08d2..9b538d4 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsDisplay.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,12 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IEvsDisplay {
+ android.hardware.automotive.evs.DisplayDesc getDisplayInfo();
+ android.hardware.automotive.evs.DisplayState getDisplayState();
+ android.hardware.automotive.evs.BufferDesc getTargetBuffer();
+ void returnTargetBufferForDisplay(in android.hardware.automotive.evs.BufferDesc buffer);
+ void setDisplayState(in android.hardware.automotive.evs.DisplayState state);
}
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumerator.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumerator.aidl
new file mode 100644
index 0000000..a79c68d
--- /dev/null
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumerator.aidl
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.automotive.evs;
+@VintfStability
+interface IEvsEnumerator {
+ void closeCamera(in android.hardware.automotive.evs.IEvsCamera carCamera);
+ void closeDisplay(in android.hardware.automotive.evs.IEvsDisplay display);
+ void closeUltrasonicsArray(in android.hardware.automotive.evs.IEvsUltrasonicsArray evsUltrasonicsArray);
+ android.hardware.automotive.evs.CameraDesc[] getCameraList();
+ byte[] getDisplayIdList();
+ android.hardware.automotive.evs.DisplayState getDisplayState();
+ android.hardware.automotive.evs.Stream[] getStreamList(in android.hardware.automotive.evs.CameraDesc description);
+ android.hardware.automotive.evs.UltrasonicsArrayDesc[] getUltrasonicsArrayList();
+ boolean isHardware();
+ android.hardware.automotive.evs.IEvsCamera openCamera(in String cameraId, in android.hardware.automotive.evs.Stream streamCfg);
+ android.hardware.automotive.evs.IEvsDisplay openDisplay(in byte id);
+ android.hardware.automotive.evs.IEvsUltrasonicsArray openUltrasonicsArray(in String ultrasonicsArrayId);
+ void registerStatusCallback(in android.hardware.automotive.evs.IEvsEnumeratorStatusCallback callback);
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
index 7ef08d2..c39a4e8 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,8 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IEvsEnumeratorStatusCallback {
+ oneway void deviceStatusChanged(in android.hardware.automotive.evs.DeviceStatus[] status);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
similarity index 77%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
index 7ef08d2..1183ab3 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,12 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IEvsUltrasonicsArray {
+ void doneWithDataFrame(in android.hardware.automotive.evs.UltrasonicsDataFrameDesc dataFrameDesc);
+ android.hardware.automotive.evs.UltrasonicsArrayDesc getUltrasonicArrayInfo();
+ void setMaxFramesInFlight(in int bufferCount);
+ void startStream(in android.hardware.automotive.evs.IEvsUltrasonicsArrayStream stream);
+ void stopStream();
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
index 7ef08d2..510b0a4 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IEvsUltrasonicsArrayStream {
+ oneway void deliverDataFrame(in android.hardware.automotive.evs.UltrasonicsDataFrameDesc dataFrameDesc);
+ oneway void notify(in android.hardware.automotive.evs.EvsEventDesc event);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/ParameterRange.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/ParameterRange.aidl
index 7ef08d2..44e9b59 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/ParameterRange.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable ParameterRange {
+ int min;
+ int max;
+ int step;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Rotation.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Rotation.aidl
index 7ef08d2..91971fc 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Rotation.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.automotive.evs;
+@Backing(type="int") @VintfStability
+enum Rotation {
+ ROTATION_0 = 0,
+ ROTATION_90 = 1,
+ ROTATION_180 = 2,
+ ROTATION_270 = 3,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/RotationQuaternion.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/RotationQuaternion.aidl
index 7ef08d2..d9c8b6e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/RotationQuaternion.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable RotationQuaternion {
+ float x;
+ float y;
+ float z;
+ float w;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/SensorPose.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/SensorPose.aidl
index 7ef08d2..4ead9ea 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/SensorPose.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable SensorPose {
+ android.hardware.automotive.evs.RotationQuaternion rotation;
+ android.hardware.automotive.evs.Translation translation;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
similarity index 81%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
index 7ef08d2..a780412 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,14 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable Stream {
+ int id;
+ android.hardware.automotive.evs.StreamType streamType;
+ int width;
+ int height;
+ android.hardware.graphics.common.PixelFormat format;
+ android.hardware.graphics.common.BufferUsage usage;
+ android.hardware.automotive.evs.Rotation rotation;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/StreamType.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/StreamType.aidl
index 7ef08d2..9819c89 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/StreamType.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.automotive.evs;
+@Backing(type="int") @VintfStability
+enum StreamType {
+ OUTPUT = 0,
+ INPUT = 1,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Translation.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Translation.aidl
index 7ef08d2..488d80f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Translation.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable Translation {
+ float x;
+ float y;
+ float z;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicSensor.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicSensor.aidl
index 7ef08d2..23f81f8 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicSensor.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable UltrasonicSensor {
+ android.hardware.automotive.evs.SensorPose pose;
+ float maxRangeMm;
+ float angleOfMeasurement;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
index 7ef08d2..4a98875 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable UltrasonicsArrayDesc {
+ @utf8InCpp String ultrasonicsArrayId;
+ int maxReadingsPerSensorCount;
+ int maxReceiversCount;
+ android.hardware.automotive.evs.UltrasonicSensor[] sensors;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
index 7ef08d2..35ec84b 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,13 @@
// 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.gnss.visibility_control;
+package android.hardware.automotive.evs;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable UltrasonicsDataFrameDesc {
+ long timestampNs;
+ int id;
+ byte[] transmittersIdList;
+ byte[] receiversIdList;
+ int[] receiversReadingsCountList;
+ android.hardware.common.Ashmem waveformsData;
}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/BufferDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/BufferDesc.aidl
new file mode 100644
index 0000000..0604abe
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/BufferDesc.aidl
@@ -0,0 +1,60 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.graphics.common.HardwareBuffer;
+
+/**
+ * Structure representing an image buffer through our APIs
+ *
+ * In addition to the handle to the graphics memory, we need to retain
+ * the properties of the buffer for easy reference and reconstruction of
+ * an ANativeWindowBuffer object on the remote side of API calls.
+ * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a
+ * texture via eglCreateImageKHR()).
+ */
+@VintfStability
+parcelable BufferDesc {
+ /**
+ * Stable AIDL counter part of AHardwareBuffer. Please see
+ * hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
+ * for more details.
+ */
+ HardwareBuffer buffer;
+ /**
+ * The size of a pixel in the units of bytes.
+ */
+ int pixelSizeBytes;
+ /**
+ * Opaque value from driver
+ */
+ int bufferId;
+ /**
+ * Unique identifier of the physical camera device that produces this buffer.
+ */
+ @utf8InCpp
+ String deviceId;
+ /**
+ * Time that this buffer is being filled in the units of microseconds and must be
+ * obtained from android::elapsedRealtimeNanos() or its equivalents.
+ */
+ long timestamp;
+ /**
+ * Frame metadata. This is opaque to EvsManager.
+ */
+ byte[] metadata;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/CameraDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/CameraDesc.aidl
new file mode 100644
index 0000000..2f500a7
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/CameraDesc.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * Structure describing the basic properties of an EVS camera.
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system.
+ */
+@VintfStability
+parcelable CameraDesc {
+ /**
+ * Unique identifier for camera devices. This may be a path to detected
+ * camera device; for example, "/dev/video0".
+ */
+ @utf8InCpp
+ String id;
+ /**
+ * Opaque value from driver. Vendor may use this field to store additional
+ * information; for example, sensor and bridge chip id.
+ */
+ int vendorFlags;
+ /**
+ * Store camera metadata such as lens characteristics.
+ */
+ byte[] metadata;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/CameraParam.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/CameraParam.aidl
new file mode 100644
index 0000000..15500b2
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/CameraParam.aidl
@@ -0,0 +1,75 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * EVS camera parameter
+ */
+@VintfStability
+@Backing(type="int")
+enum CameraParam {
+ /**
+ * The brightness of image frames
+ */
+ BRIGHTNESS,
+ /**
+ * The contrast of image frames
+ */
+ CONTRAST,
+ /**
+ * Automatic gain/exposure control
+ */
+ AUTOGAIN,
+ /**
+ * Gain control
+ */
+ GAIN,
+ /**
+ * Automatic Whitebalance
+ */
+ AUTO_WHITE_BALANCE,
+ /**
+ * Manual white balance setting as a color temperature in Kelvin.
+ */
+ WHITE_BALANCE_TEMPERATURE,
+ /**
+ * Image sharpness adjustment
+ */
+ SHARPNESS,
+ /**
+ * Auto Exposure Control modes; auto, manual, shutter priority, or
+ * aperture priority.
+ */
+ AUTO_EXPOSURE,
+ /**
+ * Manual exposure time of the camera
+ */
+ ABSOLUTE_EXPOSURE,
+ /**
+ * Sets the focal point of the camera to the specified position. This
+ * parameter may not be effective when auto focus is enabled.
+ */
+ ABSOLUTE_FOCUS,
+ /**
+ * Enables continuous automatic focus adjustments.
+ */
+ AUTO_FOCUS,
+ /**
+ * Specifies the objective lens focal length as an absolute value.
+ */
+ ABSOLUTE_ZOOM,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatus.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatus.aidl
new file mode 100644
index 0000000..535ace3
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatus.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.DeviceStatusType;
+
+/**
+ * The status of the devices, as sent by EVS HAL through the
+ * IEvsEnumeratorCallback::deviceStatusChanged() call.
+ */
+@VintfStability
+parcelable DeviceStatus {
+ /**
+ * The identifier of a device that has transitioned to a new status.
+ */
+ @utf8InCpp
+ String id;
+ /**
+ * A new status of this device
+ */
+ DeviceStatusType status;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatusType.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatusType.aidl
new file mode 100644
index 0000000..902b31b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DeviceStatusType.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * The status of the devices available through the EVS
+ */
+@VintfStability
+@Backing(type="int")
+enum DeviceStatusType {
+ /**
+ * A camera device is available and ready to be used.
+ */
+ CAMERA_AVAILABLE,
+ /**
+ * A camera device is not available; e.g. disconnected from the system.
+ */
+ CAMERA_NOT_AVAILABLE,
+ /**
+ * A display device is available and ready to be used.
+ */
+ DISPLAY_AVAILABLE,
+ /**
+ * A display device is not available; e.g. disconnected from the
+ * system.
+ */
+ DISPLAY_NOT_AVAILABLE,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DisplayDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayDesc.aidl
new file mode 100644
index 0000000..0b4243b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayDesc.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.Rotation;
+
+/**
+ * Structure describing the basic properties of an EVS display
+ *
+ * The HAL is responsible for filling out this structure to describe
+ * the EVS display. As an implementation detail, this may be a physical
+ * display or a virtual display that is overlaid or mixed with another
+ * presentation device.
+ */
+@VintfStability
+parcelable DisplayDesc {
+ /**
+ * Unique identifier for the display
+ */
+ @utf8InCpp
+ String id;
+ /**
+ * The width of the display
+ */
+ int width;
+ /**
+ * The height of the display
+ */
+ int height;
+ /**
+ * Counterclock-wise orientation of the display
+ */
+ Rotation orientation;
+ /**
+ * Opaque value from driver. Vendor may use this field to store additional
+ * information; for example, sensor and bridge chip id.
+ */
+ int vendorFlags;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/DisplayState.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayState.aidl
new file mode 100644
index 0000000..c242d2f
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/DisplayState.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * States for control of the EVS display
+ *
+ * The DisplayInfo structure describes the basic properties of an EVS display. Any EVS
+ * implementation is required to have one. The HAL is responsible for filling out this
+ * structure to describe the EVS display. As an implementation detail, this may be a
+ * physical display or a virtual display that is overlaid or mixed with another
+ * presentation device.
+ */
+@VintfStability
+@Backing(type="int")
+enum DisplayState {
+ /*
+ * Display has not been requested by any application yet
+ */
+ NOT_OPEN = 0,
+ /*
+ * Display is inhibited
+ */
+ NOT_VISIBLE,
+ /*
+ * Will become visible with next frame
+ */
+ VISIBLE_ON_NEXT_FRAME,
+ /*
+ * Display is currently active
+ */
+ VISIBLE,
+ /*
+ * Driver is in an undefined state. Interface should be closed.
+ */
+ DEAD,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
new file mode 100644
index 0000000..ebff98f
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.EvsEventType;
+
+/**
+ * Structure that describes informative events occurred during EVS is streaming
+ */
+@VintfStability
+parcelable EvsEventDesc {
+ /**
+ * Type of an informative event
+ */
+ EvsEventType aType;
+ /**
+ * Device identifier
+ */
+ @utf8InCpp
+ String deviceId;
+ /**
+ * Possible additional vendor information that is opaque to the EvsManager
+ */
+ int[] payload;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventType.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventType.aidl
new file mode 100644
index 0000000..3a493af
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventType.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * Types of informative streaming events
+ */
+@VintfStability
+@Backing(type="int")
+enum EvsEventType {
+ /**
+ * Video stream is started
+ */
+ STREAM_STARTED = 0,
+ /**
+ * Video stream is stopped
+ */
+ STREAM_STOPPED,
+ /**
+ * Video frame is dropped
+ */
+ FRAME_DROPPED,
+ /**
+ * Timeout happens
+ */
+ TIMEOUT,
+ /**
+ * Camera parameter is changed; payload contains a changed parameter ID and
+ * its value
+ */
+ PARAMETER_CHANGED,
+ /**
+ * Master role has become available
+ */
+ MASTER_RELEASED,
+ /**
+ * Any other erroneous streaming events
+ */
+ STREAM_ERROR,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/EvsResult.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsResult.aidl
new file mode 100644
index 0000000..c355be3
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsResult.aidl
@@ -0,0 +1,66 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * Error codes used in EVS HAL interface.
+ */
+@VintfStability
+@Backing(type="int")
+enum EvsResult {
+ OK = 0,
+ /**
+ * Given arguments are invalid
+ */
+ INVALID_ARG,
+ /**
+ * Requested stream is already running
+ */
+ STREAM_ALREADY_RUNNING,
+ /**
+ * Buffer is not available; e.g. failed to allocate
+ */
+ BUFFER_NOT_AVAILABLE,
+ /**
+ * Ownership has been expired or stolen by other clients
+ */
+ OWNERSHIP_LOST,
+ /**
+ * A dependent service fails to handle a request
+ */
+ UNDERLYING_SERVICE_ERROR,
+ /**
+ * Permission denied
+ */
+ PERMISSION_DENIED,
+ /**
+ * Either the camera or the display is not available
+ */
+ RESOURCE_NOT_AVAILABLE,
+ /**
+ * Device or resource busy
+ */
+ RESOURCE_BUSY,
+ /**
+ * A method is not implemented yet
+ */
+ NOT_IMPLEMENTED,
+ /**
+ * Requested functionality is not supported
+ */
+ NOT_SUPPORTED,
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCamera.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCamera.aidl
new file mode 100644
index 0000000..080dd75
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCamera.aidl
@@ -0,0 +1,248 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.BufferDesc;
+import android.hardware.automotive.evs.CameraDesc;
+import android.hardware.automotive.evs.CameraParam;
+import android.hardware.automotive.evs.IEvsCameraStream;
+import android.hardware.automotive.evs.IEvsDisplay;
+import android.hardware.automotive.evs.ParameterRange;
+
+/**
+ * Represents a single camera and is the primary interface for capturing images.
+ */
+@VintfStability
+interface IEvsCamera {
+ /**
+ * Returns frames that were delivered to the IEvsCameraStream.
+ *
+ * When done consuming a frame delivered to the IEvsCameraStream
+ * interface, it must be returned to the IEvsCamera for reuse.
+ * A small, finite number of buffers are available (possibly as small
+ * as one), and if the supply is exhausted, no further frames may be
+ * delivered until a buffer is returned.
+ *
+ * @param in buffer Buffers to be returned.
+ */
+ void doneWithFrame(in BufferDesc[] buffer);
+
+ /**
+ * Sets to be the primary client forcibly.
+ *
+ * The client, which owns the display, has a high priority and can take over
+ * a primary client role from other clients without the display.
+ *
+ * @param in display IEvsDisplay handle. If a given display is in either
+ * NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the
+ * calling client is considered as the high priority client
+ * and therefore allowed to take over a primary client role from
+ * existing primary client.
+ * @throws EvsResult::INVALID_ARG if a given display handle is null or invalid states.
+ */
+ void forcePrimaryClient(in IEvsDisplay display);
+
+ /**
+ * Returns the description of this camera.
+ *
+ * @return The description of this camera. This must be the same value as
+ * reported by IEvsEnumerator::getCameraList().
+ */
+ CameraDesc getCameraInfo();
+
+ /**
+ * Request driver specific information from the HAL implementation.
+ *
+ * The values allowed for opaqueIdentifier are driver specific,
+ * but no value passed in may crash the driver.
+ *
+ * @param in opaqueIdentifier An unique identifier of the information to
+ * request.
+ * @return Requested information. Zero-size vector is returned if the driver does
+ * not recognize a given identifier.
+ * @throws EvsResult::INVALID_ARG for any unrecognized opaqueIdentifier.
+ */
+ byte[] getExtendedInfo(in int opaqueIdentifier);
+
+ /**
+ * Retrieves values of given camera parameter. The driver must report
+ * EvsResult::INVALID_ARG if a request parameter is not supported.
+ *
+ * @param in id The identifier of camera parameter, CameraParam enum.
+ * @return Values of requested camera parameter, the same number of values as
+ * backing camera devices.
+ * @throws EvsResult::INVALID_ARG for any unrecognized parameter.
+ * EvsResult::UNDERLYING_SERVICE_ERROR for any other failures.
+ */
+ int[] getIntParameter(in CameraParam id);
+
+ /**
+ * Requests a valid value range of a camera parameter
+ *
+ * @param in id The identifier of camera parameter, CameraParam enum.
+ * @return ParameterRange of a requested CameraParam
+ */
+ ParameterRange getIntParameterRange(in CameraParam id);
+
+ /**
+ * Retrieves a list of parameters this camera supports.
+ *
+ * @return A list of CameraParam that this camera supports.
+ */
+ CameraParam[] getParameterList();
+
+ /**
+ * Returns the description of the physical camera device that backs this
+ * logical camera.
+ *
+ * If a requested device does not either exist or back this logical device,
+ * this method returns a null camera descriptor. And, if this is called on
+ * a physical camera device, this method is the same as getCameraInfo()
+ * method if a given device ID is matched. Otherwise, this will return a
+ * null camera descriptor.
+ *
+ * @param in deviceId Physical camera device identifier string.
+ * @return The description of a member physical camera device.
+ * This must be the same value as reported by IEvsEnumerator::getCameraList().
+ */
+ CameraDesc getPhysicalCameraInfo(in String deviceId);
+
+ /**
+ * Import external buffers to capture frames
+ *
+ * This API must be called with a physical camera device identifier.
+ *
+ * @param in buffers A list of buffers allocated by the caller. EvsCamera
+ * will use these buffers to capture frames, in addition to
+ * other buffers already in its buffer pool.
+ * @return The amount of buffer pool size changes after importing given buffers.
+ */
+ int importExternalBuffers(in BufferDesc[] buffers);
+
+ /**
+ * Requests to pause EVS camera stream events.
+ *
+ * Like stopVideoStream(), events may continue to arrive for some time
+ * after this call returns. Delivered frame buffers must be returned.
+ */
+ void pauseVideoStream();
+
+ /**
+ * Requests to resume EVS camera stream.
+ */
+ void resumeVideoStream();
+
+ /**
+ * Send a driver specific value to the HAL implementation.
+ *
+ * This extension is provided to facilitate car specific
+ * extensions, but no HAL implementation may require this call
+ * in order to function in a default state.
+ * INVALID_ARG is returned if the opaqueValue is not meaningful to
+ * the driver implementation.
+ *
+ * @param in opaqueIdentifier An unique identifier of the information to
+ * program.
+ * in opaqueValue A value to program.
+ * @throws EvsResult::INVALID_ARG if this call fails to set a parameter.
+ */
+ void setExtendedInfo(in int opaqueIdentifier, in byte[] opaqueValue);
+
+ /**
+ * Requests to set a camera parameter.
+ *
+ * Only a request from the primary client will be processed successfully.
+ * When this method is called on a logical camera device, it will be forwarded
+ * to each physical device and, if it fails to program any physical device,
+ * it will return an error code with the same number of effective values as
+ * the number of backing camera devices.
+ *
+ * @param in id The identifier of camera parameter, CameraParam enum.
+ * @param in value A desired parameter value.
+ * @return Programmed parameter values. This may differ from what the client
+ * gives if, for example, the driver does not support a target parameter.
+ * @throws EvsResult::INVALID_ARG if either the request is not made by the primary
+ * client, or a requested parameter is not supported.
+ * EvsResult::UNDERLYING_SERVICE_ERROR if it fails to program a value by any
+ * other reason.
+ */
+ int[] setIntParameter(in CameraParam id, in int value);
+
+ /**
+ * Requests to be the primary client.
+ *
+ * When multiple clients subscribe to a single camera hardware and one of
+ * them adjusts a camera parameter such as the contrast, it may disturb
+ * other clients' operations. Therefore, the client must call this method
+ * to be a primary client. Once it becomes a primary client, it will be able to
+ * change camera parameters until either it dies or explicitly gives up the
+ * role.
+ *
+ * @throws EvsResult::OWNERSHIP_LOST if there is already the primary client.
+ */
+ void setPrimaryClient();
+
+ /**
+ * Specifies the depth of the buffer chain the camera is asked to support.
+ *
+ * Up to this many frames may be held concurrently by the client of IEvsCamera.
+ * If this many frames have been delivered to the receiver without being returned
+ * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse.
+ * It is legal for this call to come at any time, even while streams are already running,
+ * in which case buffers should be added or removed from the chain as appropriate.
+ * If no call is made to this entry point, the IEvsCamera must support at least one
+ * frame by default. More is acceptable.
+ *
+ * @param in bufferCount Number of buffers the client of IEvsCamera may hold concurrently.
+ * @throws EvsResult::BUFFER_NOT_AVAILABLE if the client cannot increase the max frames.
+ * EvsResult::INVALID_ARG if the client cannot decrease the max frames.
+ * EvsResult::OWNERSHIP_LOST if we lost an ownership of a target camera.
+ */
+ void setMaxFramesInFlight(in int bufferCount);
+
+ /**
+ * Request to start EVS camera stream from this camera.
+ *
+ * The IEvsCameraStream must begin receiving calls with various events
+ * including new image frame ready until stopVideoStream() is called.
+ *
+ * @param in receiver IEvsCameraStream implementation.
+ * @throws EvsResult::OWNERSHIP_LOST if we lost an ownership of a target camera.
+ * EvsResult::STREAM_ALREADY_RUNNING if a video stream has been started already.
+ * EvsResult::BUFFER_NOT_AVAILABLE if it fails to secure a minimum number of
+ * buffers to run a video stream.
+ * EvsResult::UNDERLYING_SERVICE_ERROR for all other failures.
+ */
+ void startVideoStream(in IEvsCameraStream receiver);
+
+ /**
+ * Stop the delivery of EVS camera frames.
+ *
+ * Because delivery is asynchronous, frames may continue to arrive for
+ * some time after this call returns. Each must be returned until the
+ * closure of the stream is signaled to the IEvsCameraStream.
+ * This function cannot fail and is simply ignored if the stream isn't running.
+ */
+ void stopVideoStream();
+
+ /**
+ * Retires from the primary client role.
+ *
+ * @throws EvsResult::INVALID_ARG if the caller client is not a primary client.
+ */
+ void unsetPrimaryClient();
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
new file mode 100644
index 0000000..2c2b44c
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.BufferDesc;
+import android.hardware.automotive.evs.EvsEventDesc;
+import android.hardware.graphics.common.HardwareBuffer;
+
+/**
+ * Implemented on client side to receive asynchronous streaming event deliveries.
+ */
+@VintfStability
+oneway interface IEvsCameraStream {
+ /**
+ * Receives calls from the HAL each time video frames is ready for inspection.
+ * Buffer handles received by this method must be returned via calls to
+ * IEvsCamera::doneWithFrame(). When the video stream is stopped via a call
+ * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
+ * some time as the pipeline drains. Each frame must still be returned.
+ * When the last frame in the stream has been delivered, STREAM_STOPPED
+ * event must be delivered. No further frame deliveries may happen
+ * thereafter.
+ *
+ * A camera device will deliver the same number of frames as number of
+ * backing physical camera devices; it means, a physical camera device
+ * sends always a single frame and a logical camera device sends multiple
+ * frames as many as number of backing physical camera devices.
+ *
+ * @param in buffer Buffer descriptors of delivered image frames.
+ */
+ void deliverFrame(in BufferDesc[] buffer);
+
+ /**
+ * Receives calls from the HAL each time an event happens.
+ *
+ * @param in event EVS event with possible event information.
+ */
+ void notify(in EvsEventDesc event);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsDisplay.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsDisplay.aidl
new file mode 100644
index 0000000..8d57014
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsDisplay.aidl
@@ -0,0 +1,94 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.BufferDesc;
+import android.hardware.automotive.evs.DisplayDesc;
+import android.hardware.automotive.evs.DisplayState;
+
+/**
+ * Represents a single display.
+ */
+@VintfStability
+interface IEvsDisplay {
+ /**
+ * Returns the description of this display.
+ *
+ * @return The information of this display including id, current mode, current state,
+ * and additional vendor-specific information.
+ * @throws EvsResult::UNDERLYING_SERVICE_ERROR if it fails to read a display information.
+ */
+ DisplayDesc getDisplayInfo();
+
+ /**
+ * This call requests the current state of the display
+ *
+ * The HAL implementation should report the actual current state, which might
+ * transiently differ from the most recently requested state. Note, however, that
+ * the logic responsible for changing display states should generally live above
+ * the device layer, making it undesirable for the HAL implementation to spontaneously
+ * change display states.
+ *
+ * @return Current DisplayState of this Display.
+ */
+ DisplayState getDisplayState();
+
+ /**
+ * This call returns a handle to a frame buffer associated with the display.
+ *
+ * @return A handle to a frame buffer. The returned buffer may be locked and
+ * written to by software and/or GL. This buffer must be returned via
+ * a call to returnTargetBufferForDisplay() even if the display is no
+ * longer visible.
+ * @throws EvsResult::OWNERSHIP_LOST if a display is in DisplayState::DEAD.
+ * EvsResult::BUFFER_NOT_AVAILABLE if no buffer is available.
+ * EvsResult::UNDERLYING_SERVICE_ERROR for any other failures.
+ */
+ BufferDesc getTargetBuffer();
+
+ /**
+ * This call tells the display that the buffer is ready for display.
+ *
+ * The buffer is no longer valid for use by the client after this call.
+ * There is no maximum time the caller may hold onto the buffer before making this
+ * call. The buffer may be returned at any time and in any DisplayState, but all
+ * buffers are expected to be returned before the IEvsDisplay interface is destroyed.
+ *
+ * @param in buffer A buffer handle to the frame that is ready for display.
+ * @throws EvsResult::INVALID_ARG if a given buffer is unknown or invalid.
+ * EvsResult::OWNERSHIP_LOST if a display is in DisplayState::DEAD.
+ * EvsResult::UNDERLYING_SERVICE_ERROR for any other failures.
+ */
+ void returnTargetBufferForDisplay(in BufferDesc buffer);
+
+ /**
+ * Clients may set the display state to express their desired state.
+ *
+ * The HAL implementation must gracefully accept a request for any state while in
+ * any other state, although the response may be to defer or ignore the request. The display
+ * is defined to start in the NOT_VISIBLE state upon initialization. The client is
+ * then expected to request the VISIBLE_ON_NEXT_FRAME state, and then begin providing
+ * video. When the display is no longer required, the client is expected to request
+ * the NOT_VISIBLE state after passing the last video frame.
+ * Returns INVALID_ARG if the requested state is not a recognized value.
+ *
+ * @param in state Desired new DisplayState.
+ * @throws EvsResult::INVALID_ARG if a given state is invalid.
+ * EvsResult::OWNERSHIP_LOST if a display is in DisplayState::DEAD.
+ */
+ void setDisplayState(in DisplayState state);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumerator.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumerator.aidl
new file mode 100644
index 0000000..8e380e0
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumerator.aidl
@@ -0,0 +1,166 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.CameraDesc;
+import android.hardware.automotive.evs.DisplayState;
+import android.hardware.automotive.evs.IEvsCamera;
+import android.hardware.automotive.evs.IEvsDisplay;
+import android.hardware.automotive.evs.IEvsEnumeratorStatusCallback;
+import android.hardware.automotive.evs.IEvsUltrasonicsArray;
+import android.hardware.automotive.evs.Stream;
+import android.hardware.automotive.evs.UltrasonicsArrayDesc;
+
+/**
+ * Provides the mechanism for EVS camera and ultrasonics array discovery
+ */
+@VintfStability
+interface IEvsEnumerator {
+ /**
+ * Return the specified IEvsCamera interface as no longer in use
+ *
+ * When the IEvsCamera object is no longer required, it must be released.
+ * NOTE: Video streaming must be cleanly stopped before making this call.
+ *
+ * @param in carCamera EvsCamera object to be closed.
+ * @throws EvsResult::INVALID_ARG if a given camera object is invalid.
+ */
+ void closeCamera(in IEvsCamera carCamera);
+
+ /**
+ * Return the specified IEvsDisplay interface as no longer in use
+ *
+ * When the IEvsDisplay object is no longer required, it must be released.
+ * NOTE: All buffers must have been returned to the display before making this call.
+ *
+ * @param in display EvsDisplay object to be closed.
+ */
+ void closeDisplay(in IEvsDisplay display);
+
+ /**
+ * Return the specified IEvsUltrasonicsArray interface as no longer in use
+ *
+ * When the IEvsUltrasonicsArray object is no longer required, it must be released.
+ * NOTE: Data streaming must be cleanly stopped before making this call.
+ *
+ * @param in evsUltrasonicsArray EvsUltrasonics array object to be closed.
+ */
+ void closeUltrasonicsArray(in IEvsUltrasonicsArray evsUltrasonicsArray);
+
+ /**
+ * Returns a list of all EVS cameras available to the system
+ *
+ * @return A list of cameras availale for EVS service.
+ * @throws EvsResult::PERMISSION_DENIED if the process is not permitted to enumerate
+ * camera devices.
+ */
+ CameraDesc[] getCameraList();
+
+ /**
+ * Returns a list of all EVS displays available to the system
+ *
+ * @return Identifiers of available displays.
+ */
+ byte[] getDisplayIdList();
+
+ /**
+ * This call requests the current state of the display
+ *
+ * If there is no open display, this returns DisplayState::NOT_OPEN. otherwise, it returns
+ * the actual state of the active display. This call is replicated on the IEvsEnumerator
+ * interface in order to allow secondary clients to monitor the state of the EVS display
+ * without acquiring exclusive ownership of the display.
+ *
+ * @return Current DisplayState of this Display.
+ * @throws EvsResult::OWNERSHIP_LOST if current display is inactive
+ * EvsResult::PERMISSION_DENIED if the process is not permitted to do this operation.
+ */
+ DisplayState getDisplayState();
+
+ /**
+ * Return a list of the stream configurations a target camera device supports
+ *
+ * @param in description A target camera descriptor
+ * @return A list of stream configurations supported by a given camera device
+ */
+ Stream[] getStreamList(in CameraDesc description);
+
+ /**
+ * Returns a list of all ultrasonics array available to the system.
+ * Will return an empty vector if ultrasonics is not supported.
+ *
+ * @return A list of ultrasonics available for EVS service.
+ */
+ UltrasonicsArrayDesc[] getUltrasonicsArrayList();
+
+ /**
+ * Tells whether this is EvsManager or HAL implementation.
+ *
+ * @return False for EvsManager implementations and true for all others.
+ */
+ boolean isHardware();
+
+ /**
+ * Gets the IEvsCamera associated with a cameraId from a CameraDesc
+ *
+ * Given a camera's unique cameraId from CameraDesc, returns the
+ * IEvsCamera interface associated with the specified camera. When
+ * done using the camera, the caller may release it by calling closeCamera().
+ *
+ * @param in cameraId A unique identifier of the camera.
+ * @param in streamCfg A stream configuration the client wants to use.
+ * @return EvsCamera object associated with a given cameraId.
+ * Returned object would be null if a camera device does not support a
+ * given stream configuration or is already configured differently by
+ * another client.
+ * @throws EvsResult::PERMISSION_DENIED if the process is not permitted to use camera
+ * devices.
+ * EveResult::INVALID_ARG if it fails to open a camera with a given id.
+ */
+ IEvsCamera openCamera(in String cameraId, in Stream streamCfg);
+
+ /**
+ * Get exclusive access to IEvsDisplay for the system
+ *
+ * There can be more than one EVS display objects for the system and this function
+ * requests access to the display identified by a given ID. If the target EVS display
+ * is not available or is already in use the old instance shall be closed and give
+ * the new caller exclusive access.
+ * When done using the display, the caller may release it by calling closeDisplay().
+ *
+ * @param in id Target display identifier.
+ * @return EvsDisplay object to be used.
+ * @throws EvsResult::INVALID_ARG if no display with a given id exists
+ */
+ IEvsDisplay openDisplay(in byte id);
+
+ /**
+ * Gets the IEvsUltrasonicsArray associated with a ultrasonicsArrayId from a
+ * UltrasonicsDataDesc
+ *
+ * @param in ultrasonicsArrayId A unique identifier of the ultrasonic array.
+ * @return IEvsUltrasonicsArray object associated with a given ultrasonicsArrayId.
+ */
+ IEvsUltrasonicsArray openUltrasonicsArray(in String ultrasonicsArrayId);
+
+ /**
+ * Registers a callback to listen to devices' status changes
+ *
+ * @param in callback IEvsEnumeratorStatusCallback implementation
+ */
+ void registerStatusCallback(in IEvsEnumeratorStatusCallback callback);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
new file mode 100644
index 0000000..26ccf72
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.DeviceStatus;
+
+/**
+ * Implemented on client side to receive asynchronous notifications from
+ * IEvsEnumreator.
+ */
+@VintfStability
+oneway interface IEvsEnumeratorStatusCallback {
+ /**
+ * Receives calls from the HAL each time a status of camera devices is
+ * changed.
+ *
+ * @param in status A list of newly updated device status
+ */
+ void deviceStatusChanged(in DeviceStatus[] status);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
new file mode 100644
index 0000000..40de313
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.aidl
@@ -0,0 +1,79 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.IEvsUltrasonicsArrayStream;
+import android.hardware.automotive.evs.UltrasonicsArrayDesc;
+import android.hardware.automotive.evs.UltrasonicsDataFrameDesc;
+
+/**
+ * HAL interface for ultrasonics sensor array.
+ */
+@VintfStability
+interface IEvsUltrasonicsArray {
+ /**
+ * Notifies the UltrasonicsDataDesc is consumed that was received from
+ * IEvsUltrasonicsArrayStream
+ *
+ * @param in dataFrameDesc Ultrasonics data descriptor
+ */
+ void doneWithDataFrame(in UltrasonicsDataFrameDesc dataFrameDesc);
+
+ /**
+ * Returns the ultrasonic sensor array information
+ *
+ * @throws The description of this ultrasonic array. This must be the same
+ * value as reported by IEvsEnumerator::getUltrasonicsArrayList().
+ */
+ UltrasonicsArrayDesc getUltrasonicArrayInfo();
+
+ /**
+ * Specifies the depth of the buffer chain the ultrasonic sensors is
+ * asked to support
+ *
+ * Up to this many data frames may be held concurrently by the client of IEvsUltrasonicsArray.
+ * If this many frames have been delivered to the receiver without being returned
+ * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse.
+ * It is legal for this call to come at any time, even while streams are already running,
+ * in which case buffers should be added or removed from the chain as appropriate.
+ * If no call is made to this entry point, the IEvsUltrasonicsArray must support at least one
+ * data frame by default. More is acceptable.
+ *
+ * @param in bufferCount Number of buffers the client of IEvsUltrasonicsArray may hold
+ * concurrently.
+ * @throws EvsResult::INVALID_ARG on invalid bufferCount.
+ */
+ void setMaxFramesInFlight(in int bufferCount);
+
+ /**
+ * Requests to start the stream
+ *
+ * @param in stream Implementation of IEvsUltrasonicsArrayStream.
+ * @throws EvsResult::STREAM_ALREADY_RUNNING if stream is already running
+ */
+ void startStream(in IEvsUltrasonicsArrayStream stream);
+
+ /**
+ * Requests to stop the delivery of the ultrasonic array data frames
+ *
+ * Because delivery is asynchronous, frames may continue to arrive for
+ * some time after this call returns. Each must be returned until the
+ * closure of the stream is signaled to the IEvsCameraStream.
+ * This function cannot fail and is ignored if the stream isn't running.
+ */
+ void stopStream();
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
new file mode 100644
index 0000000..bc31a6b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsUltrasonicsArrayStream.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.EvsEventDesc;
+import android.hardware.automotive.evs.UltrasonicsDataFrameDesc;
+
+/**
+ * Implemented on client side to receive asynchronous ultrasonic data
+ * deliveries.
+ */
+@VintfStability
+interface IEvsUltrasonicsArrayStream {
+ /**
+ * Receives calls from the HAL each time a data frame is ready
+ *
+ * @param in dataFrameDesc Ultrasonic array data frame descriptor
+ */
+ oneway void deliverDataFrame(in UltrasonicsDataFrameDesc dataFrameDesc);
+
+ /**
+ * Receives calls from the HAL each time an event happens
+ *
+ * @param in event Event EVS event with possible event information
+ */
+ oneway void notify(in EvsEventDesc event);
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/ParameterRange.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/ParameterRange.aidl
new file mode 100644
index 0000000..b08fcbd
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/ParameterRange.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * Represent a valid range of CameraParam
+ */
+@VintfStability
+parcelable ParameterRange {
+ /**
+ * Lower bound of a valid value range
+ */
+ int min;
+ /**
+ * Upper bound of a valid value range
+ */
+ int max;
+ /**
+ * A value of unit increment
+ */
+ int step;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/Rotation.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/Rotation.aidl
new file mode 100644
index 0000000..dede39e
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/Rotation.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * Rotation:
+ *
+ * The required counterclockwise rotation of EVS camera stream and display.
+ */
+@VintfStability
+@Backing(type="int")
+enum Rotation {
+ /** No rotation */
+ ROTATION_0 = 0,
+ /** Rotate by 90 degree counterclockwise */
+ ROTATION_90 = 1,
+ /** Rotate by 180 degree counterclockwise */
+ ROTATION_180 = 2,
+ /** Rotate by 270 degree counterclockwise */
+ ROTATION_270 = 3
+
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/RotationQuaternion.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/RotationQuaternion.aidl
new file mode 100644
index 0000000..b80343b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/RotationQuaternion.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * Structure for rotation expressed as quaternions.
+ * Convention used: Unit quaternion with hamilton convention.
+ */
+@VintfStability
+parcelable RotationQuaternion {
+ float x;
+ float y;
+ float z;
+ float w;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/SensorPose.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/SensorPose.aidl
new file mode 100644
index 0000000..26c3339
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/SensorPose.aidl
@@ -0,0 +1,64 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.RotationQuaternion;
+import android.hardware.automotive.evs.Translation;
+
+/**
+ * Provides the orientation and location of a car sensor relative to the android automotive
+ * coordinate system:
+ * https://source.android.com/devices/sensors/sensor-types#auto_axes
+ * The sensor pose defines the transformation to be applied to the android automotive axes to
+ * obtain the sensor local axes.
+ * The pose consists of rotation, (specified as a quaternions) and translation
+ * (vector with x, y, z).
+ * This rotation and translation applied to the sensor data in the sensor's local coordinate
+ * system transform the data to the automotive coordinate system.
+ * i.e. loc = ( Rot * Psensor ) + Trans
+ * Here loc is a point in automotive coordinate system and Psensor is a point in the sensor's
+ * coordinate system.
+ * Example:
+ * For a sensor on the front bumper and on the left corner of the car with its X axis pointing to
+ * the front, the sensor is located at (-2, 4, 0) meters w.r.t android automotive axes and the
+ * sensor local axes has a rotation of 90 degrees counter-clockwise w.r.t android automotive axes
+ * when viewing the car from top on the +Z axis side:
+ *
+ * ↑X sensor
+ * Y←∘______
+ * | | front
+ * | car |
+ * | ↑Y |
+ * | ∘→X | rear
+ * |______|
+ *
+ * For this example the rotation and translation will be:
+ * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion.
+ * Translation = (-2, 4, 0) in meters = (-2000, 4000, 0) in milli-meters.
+ * Note: Every sensor type must specify its own pose.
+ */
+@VintfStability
+parcelable SensorPose {
+ /**
+ * Rotation part of the sensor pose, expressed as a unit quaternion.
+ */
+ RotationQuaternion rotation;
+ /**
+ * Translation part of the sensor pose, in (x, y, z) format with milli-meter units.
+ */
+ Translation translation;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl
new file mode 100644
index 0000000..ae5c7f0
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl
@@ -0,0 +1,75 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.Rotation;
+import android.hardware.automotive.evs.StreamType;
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+/**
+ * Stream:
+ *
+ * Structure that describes a EVS Camera stream
+ */
+@VintfStability
+parcelable Stream {
+ /**
+ * Stream ID - a non-negative integer identifier for a stream.
+ *
+ * The identical stream ID must reference the same stream, with the same
+ * width/height/format, across consecutive calls to configureStreams.
+ *
+ * If previously-used stream ID is not used in a new call to
+ * configureStreams, then that stream is no longer active. Such a stream ID
+ * may be reused in a future configureStreams with a new
+ * width/height/format.
+ *
+ */
+ int id;
+ /**
+ * The type of the stream (input vs output, etc).
+ */
+ StreamType streamType;
+ /**
+ * The width in pixels of the buffers in this stream.
+ */
+ int width;
+ /**
+ * The height in pixels of the buffers in this stream.
+ */
+ int height;
+ /**
+ * The frame rate of this stream in frames-per-second
+ /
+ int framerate;
+ /**
+ * The pixel format form the buffers in this stream.
+ */
+ PixelFormat format;
+ /**
+ * The gralloc usage flags for this stream, as needed by the consumer of
+ * the stream.
+ */
+ BufferUsage usage;
+ /**
+ * The required output rotation of the stream.
+ *
+ * This must be inspected by HAL along with stream with and height.
+ */
+ Rotation rotation;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/StreamType.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/StreamType.aidl
new file mode 100644
index 0000000..c028a5c
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/StreamType.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * StreamType:
+ *
+ * The type of the camera stream, which defines whether the EVS client device is
+ * the producer or the consumer for that stream, and how the buffers of the
+ * stream relate to the other streams.
+ */
+@VintfStability
+@Backing(type="int")
+enum StreamType {
+ /**
+ * This stream is an output stream; the EVS HAL device must fill buffers
+ * from this stream with newly captured or reprocessed image data.
+ */
+ OUTPUT = 0,
+
+ /**
+ * This stream is an input stream; the EVS HAL device must read buffers
+ * from this stream and send them through the camera processing pipeline,
+ * as if the buffer was a newly captured image from the imager.
+ */
+ INPUT = 1
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/Translation.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/Translation.aidl
new file mode 100644
index 0000000..14b14db
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/Translation.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.automotive.evs;
+
+/**
+ * Structure for translation with x, y and z units.
+ */
+@VintfStability
+parcelable Translation {
+ float x;
+ float y;
+ float z;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicSensor.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicSensor.aidl
new file mode 100644
index 0000000..712411b
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicSensor.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.SensorPose;
+
+/**
+ * Structure that contains all information of an ultrasonic sensor.
+ */
+@VintfStability
+parcelable UltrasonicSensor {
+ /**
+ * Pose provides the orientation and location of the ultrasonic sensor within the car.
+ * The +Y axis points along the center of the beam spread the X axis to the right and the Z
+ * axis in the up direction.
+ */
+ SensorPose pose;
+ /**
+ * Maximum range of the sensor in milli-metres.
+ */
+ float maxRangeMm;
+ /**
+ * Half-angle of the angle of measurement of the sensor, relative to the
+ * sensor’s x axis, in radians.
+ */
+ float angleOfMeasurement;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
new file mode 100644
index 0000000..d4f0663
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.automotive.evs.UltrasonicSensor;
+
+/**
+ * Structure identifies and describes an ultrasonics array in the car.
+ *
+ * A ultrasonics array represents a group of ultrasonic sensors within the
+ * car. These may be sensors that are physically connected to the same hardware
+ * control unit or represent a logical group of sensors like front and back.
+ * The HAL is responsible for filling out this structure for each Ultrasonics
+ * Array.
+ */
+@VintfStability
+parcelable UltrasonicsArrayDesc {
+ /**
+ * Unique identifier for the ultrasonic array. This may be a path or name of the
+ * physical control device or a string identifying a logical group of sensors forming an array
+ * such as "front_array" and "back_array".
+ */
+ @utf8InCpp
+ String ultrasonicsArrayId;
+ /**
+ * Maximum number of readings (points on waveform) provided per sensor in
+ * each data frame. Used by client to pre-allocate required memory buffer for
+ * incoming data.
+ */
+ int maxReadingsPerSensorCount;
+ /**
+ * Maximum number of receiver sensors in a data frame. Must be between 1
+ * and sensorCount. Used by client to pre-allocate required memory buffer for
+ * incoming data.
+ */
+ int maxReceiversCount;
+ /**
+ * The order of sensors specified must be in clockwise order around the car, starting
+ * from front left-most sensor.
+ */
+ UltrasonicSensor[] sensors;
+}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
new file mode 100644
index 0000000..e546db9
--- /dev/null
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.aidl
@@ -0,0 +1,82 @@
+/*
+ * 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.automotive.evs;
+
+import android.hardware.common.Ashmem;
+
+/**
+ * Structure that describes the data frame received from an ultrasonics array.
+ *
+ * Each data frame returned consists of received waveform signals from a subset
+ * of sensors in an array as indicated by the receiversIdList. The signal is
+ * transmitted at a particular time instant indicated by timestampNs from a
+ * subset of sensors in the array as provided in the transmittersIdList.
+ */
+@VintfStability
+parcelable UltrasonicsDataFrameDesc {
+ /**
+ * Timestamp of the start of the transmit signal for this data frame.
+ * Timestamp unit is nanoseconds and is obtained from android::elapsedRealtimeNanos().
+ * timeOfFlight readings are future-deltas to this timestamp.
+ */
+ long timestampNs;
+ /**
+ * Identifier of data frame. Used by implementation for managing multiple frames in flight.
+ */
+ int id;
+ /**
+ * List of indexes of sensors in range [0, sensorCount - 1] that
+ * transmitted the signal for this data frame.
+ */
+ byte[] transmittersIdList;
+ /**
+ * List of indexes of sensors in range [0, sensorCount - 1] that received
+ * the signal. The order of ids must match the order of the waveforms in the
+ * waveformsData.
+ * Size of list is upper bound by maxReceiversCount.
+ */
+ byte[] receiversIdList;
+ /**
+ * List of the number of readings corresponding to each ultrasonics sensor in
+ * the receiversIdList. Order of the readings count must match the order in
+ * receiversIdList.
+ * Size of list is upper bound by maxReadingsPerSensorCount.
+ */
+ int[] receiversReadingsCountList;
+ /**
+ * Shared memory object containing the waveforms data. Contains one waveform
+ * for each sensor specified in receiversIdList, in order.
+ * Each waveform is represented by a number of readings, which are sample
+ * points on the waveform. The number of readings for each waveform is as
+ * specified in the receiversReadingsCountList.
+ * Each reading is a pair of time Of flight and resonance.
+ * Time of flight (float): Time between transmit and receive signal in nanoseconds.
+ * Resonance (float): Resonance at time on waveform in range [0.0, 1.0].
+ *
+ * The structure of shared memory (example with 2 waveforms, each with 2 readings):
+ *
+ * Byte: | 0 | 1-4 | 5-8 | 9-12 | 13-16 || 17 | 18-21 | 22-25 | 26-29 | 30-33 |
+ * Data: | RecId1 | TOF1 | RES1 | TOF2 | RES2 || RecId2 | TOF1 | RES1 | TOF2 | RES2 |
+ * | Waveform1 || Waveform2 |
+ * Here:
+ * RecId : Receiver's Id. Order matches the receiversIdList, type uint8_t
+ * TOF : Time of flight, type float (4 bytes)
+ * RES : Resonance, type float (4 bytes)
+ * Note: All readings and waveforms are contigious with no padding.
+ */
+ Ashmem waveformsData;
+}
diff --git a/automotive/evs/aidl/impl/Android.bp b/automotive/evs/aidl/impl/Android.bp
new file mode 100644
index 0000000..7eb0116
--- /dev/null
+++ b/automotive/evs/aidl/impl/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+ name: "EvsHalDefaults",
+ static_libs: [
+ "android.hardware.automotive.evs-V1-ndk",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.graphics.common-V3-ndk",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+}
diff --git a/automotive/evs/aidl/impl/default/Android.bp b/automotive/evs/aidl/impl/default/Android.bp
new file mode 100644
index 0000000..dbe0314
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/Android.bp
@@ -0,0 +1,36 @@
+// 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 {
+ // 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_binary {
+ name: "android.hardware.automotive.evs-aidl-default-service",
+ defaults: ["EvsHalDefaults"],
+ local_include_dirs: ["include"],
+ vintf_fragments: ["evs-default-service.xml"],
+ init_rc: ["evs-default-service.rc"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: ["src/*.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+}
diff --git a/automotive/evs/aidl/impl/default/evs-default-service.rc b/automotive/evs/aidl/impl/default/evs-default-service.rc
new file mode 100644
index 0000000..ea8e689
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/evs-default-service.rc
@@ -0,0 +1,5 @@
+service vendor.evs-hal-default /vendor/bin/hw/android.hardware.automotive.evs-aidl-default-service
+ class early_hal
+ user automotive_evs
+ group automotive_evs
+ disabled
diff --git a/automotive/evs/aidl/impl/default/evs-default-service.xml b/automotive/evs/aidl/impl/default/evs-default-service.xml
new file mode 100644
index 0000000..96ff9f6
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/evs-default-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.automotive.evs</name>
+ <transport>hwbinder</transport>
+ <version>1</version>
+ <interface>
+ <name>IEvsEnumerator</name>
+ <instance>hw/0</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/automotive/evs/aidl/impl/default/include/DefaultEvsEnumerator.h b/automotive/evs/aidl/impl/default/include/DefaultEvsEnumerator.h
new file mode 100644
index 0000000..8bcd867
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/DefaultEvsEnumerator.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_automotive_evs_aidl_impl_evshal_include_DefaultEvsHal_H_
+#define android_hardware_automotive_evs_aidl_impl_evshal_include_DefaultEvsHal_H_
+
+#include <aidl/android/hardware/automotive/evs/BnEvsEnumerator.h>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class DefaultEvsEnumerator final
+ : public ::aidl::android::hardware::automotive::evs::BnEvsEnumerator {
+ ::ndk::ScopedAStatus isHardware(bool* flag) override;
+ ::ndk::ScopedAStatus openCamera(
+ const std::string& cameraId,
+ const ::aidl::android::hardware::automotive::evs::Stream& streamConfig,
+ std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera>* obj) override;
+ ::ndk::ScopedAStatus closeCamera(
+ const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera>& obj)
+ override;
+ ::ndk::ScopedAStatus getCameraList(
+ std::vector<::aidl::android::hardware::automotive::evs::CameraDesc>* list) override;
+ ::ndk::ScopedAStatus getStreamList(
+ const ::aidl::android::hardware::automotive::evs::CameraDesc& desc,
+ std::vector<::aidl::android::hardware::automotive::evs::Stream>* _aidl_return) override;
+ ::ndk::ScopedAStatus openDisplay(
+ int8_t displayId,
+ std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>* obj) override;
+ ::ndk::ScopedAStatus closeDisplay(
+ const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>& obj)
+ override;
+ ::ndk::ScopedAStatus getDisplayIdList(std::vector<uint8_t>* list) override;
+ ::ndk::ScopedAStatus getDisplayState(
+ ::aidl::android::hardware::automotive::evs::DisplayState* state) override;
+ ::ndk::ScopedAStatus registerStatusCallback(
+ const std::shared_ptr<
+ ::aidl::android::hardware::automotive::evs::IEvsEnumeratorStatusCallback>&
+ callback) override;
+ ::ndk::ScopedAStatus openUltrasonicsArray(
+ const std::string& id,
+ std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>* obj)
+ override;
+ ::ndk::ScopedAStatus closeUltrasonicsArray(
+ const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>&
+ arr) override;
+ ::ndk::ScopedAStatus getUltrasonicsArrayList(
+ std::vector<::aidl::android::hardware::automotive::evs::UltrasonicsArrayDesc>* list)
+ override;
+};
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
+
+#endif // android_hardware_automotive_evs_aidl_impl_evshal_include_DefaultEvsHal_H_
diff --git a/automotive/evs/aidl/impl/default/src/DefaultEvsEnumerator.cpp b/automotive/evs/aidl/impl/default/src/DefaultEvsEnumerator.cpp
new file mode 100644
index 0000000..2ff6d59
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/DefaultEvsEnumerator.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+// TODO(b/203661081): Remove below lines to disable compiler warnings.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+
+#define LOG_TAG "DefaultEvsEnumerator"
+
+#include <DefaultEvsEnumerator.h>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+using ::ndk::ScopedAStatus;
+
+ScopedAStatus DefaultEvsEnumerator::isHardware(bool* flag) {
+ // This returns true always.
+ *flag = true;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::openCamera(const std::string& cameraId,
+ const Stream& streamConfig,
+ std::shared_ptr<IEvsCamera>* obj) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::closeCamera(const std::shared_ptr<IEvsCamera>& obj) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getCameraList(std::vector<CameraDesc>* list) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getStreamList(const CameraDesc& desc,
+ std::vector<Stream>* _aidl_return) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::openDisplay(int8_t displayId,
+ std::shared_ptr<IEvsDisplay>* obj) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::closeDisplay(const std::shared_ptr<IEvsDisplay>& state) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getDisplayIdList(std::vector<uint8_t>* list) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getDisplayState(DisplayState* state) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::registerStatusCallback(
+ const std::shared_ptr<IEvsEnumeratorStatusCallback>& callback) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::openUltrasonicsArray(
+ const std::string& id, std::shared_ptr<IEvsUltrasonicsArray>* obj) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::closeUltrasonicsArray(
+ const std::shared_ptr<IEvsUltrasonicsArray>& obj) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DefaultEvsEnumerator::getUltrasonicsArrayList(
+ std::vector<UltrasonicsArrayDesc>* list) {
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
+
+#pragma clang diagnostic pop
diff --git a/automotive/evs/aidl/impl/default/src/service.cpp b/automotive/evs/aidl/impl/default/src/service.cpp
new file mode 100644
index 0000000..0a0913f
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/service.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "EvsService"
+
+#include <DefaultEvsEnumerator.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+using ::aidl::android::hardware::automotive::evs::implementation::DefaultEvsEnumerator;
+
+int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
+ std::shared_ptr<DefaultEvsEnumerator> vhal = ndk::SharedRefBase::make<DefaultEvsEnumerator>();
+
+ ALOGI("Registering as service...");
+ binder_exception_t err =
+ AServiceManager_addService(vhal->asBinder().get(), "android.hardware.automotive.evs");
+ if (err != EX_NONE) {
+ ALOGE("failed to register android.hardware.automotive.evs service, exception: %d", err);
+ return 1;
+ }
+
+ if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+ ALOGE("%s", "failed to set thread pool max thread count");
+ return 1;
+ }
+ ABinderProcess_startThreadPool();
+
+ ALOGI("Evs Service Ready");
+
+ ABinderProcess_joinThreadPool();
+
+ ALOGI("Evs Service Exiting");
+
+ return 0;
+}
diff --git a/automotive/evs/aidl/vts/Android.bp b/automotive/evs/aidl/vts/Android.bp
new file mode 100644
index 0000000..980c6d5
--- /dev/null
+++ b/automotive/evs/aidl/vts/Android.bp
@@ -0,0 +1,53 @@
+//
+// 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{
+ // 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:
+ "VtsHalEvsTargetTest",
+ srcs: [
+ "*.cpp",
+ ],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcamera_metadata",
+ "libui",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@common-default-lib",
+ "android.hardware.automotive.evs-V1-ndk",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.graphics.common-V3-ndk",
+ "libaidlcommonsupport",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/automotive/evs/aidl/vts/FrameHandler.cpp b/automotive/evs/aidl/vts/FrameHandler.cpp
new file mode 100644
index 0000000..bab832b
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandler.cpp
@@ -0,0 +1,358 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+
+#include "FrameHandler.h"
+#include "FormatConvert.h"
+
+#include <aidl/android/hardware/graphics/common/HardwareBufferDescription.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+
+using ::aidl::android::hardware::automotive::evs::BufferDesc;
+using ::aidl::android::hardware::automotive::evs::CameraDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::IEvsCamera;
+using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
+using ::aidl::android::hardware::graphics::common::HardwareBufferDescription;
+using ::ndk::ScopedAStatus;
+using std::chrono_literals::operator""s;
+
+FrameHandler::FrameHandler(const std::shared_ptr<IEvsCamera>& pCamera, const CameraDesc& cameraInfo,
+ const std::shared_ptr<IEvsDisplay>& pDisplay, BufferControlFlag mode)
+ : mCamera(pCamera), mCameraInfo(cameraInfo), mDisplay(pDisplay), mReturnMode(mode) {
+ // Nothing but member initialization here.
+}
+
+void FrameHandler::shutdown() {
+ // Make sure we're not still streaming
+ blockingStopStream();
+
+ // At this point, the receiver thread is no longer running, so we can safely drop
+ // our remote object references so they can be freed
+ mCamera = nullptr;
+ mDisplay = nullptr;
+}
+
+bool FrameHandler::startStream() {
+ // Tell the camera to start streaming
+ auto status = mCamera->startVideoStream(ref<FrameHandler>());
+ if (!status.isOk()) {
+ return false;
+ }
+
+ // Mark ourselves as running
+ mLock.lock();
+ mRunning = true;
+ mLock.unlock();
+
+ return true;
+}
+
+void FrameHandler::asyncStopStream() {
+ // Tell the camera to stop streaming.
+ // This will result in a null frame being delivered when the stream actually stops.
+ mCamera->stopVideoStream();
+}
+
+void FrameHandler::blockingStopStream() {
+ // Tell the stream to stop
+ asyncStopStream();
+
+ // Wait until the stream has actually stopped
+ std::unique_lock<std::mutex> lock(mEventLock);
+ if (mRunning) {
+ mEventSignal.wait(lock, [this]() { return !mRunning; });
+ }
+}
+
+bool FrameHandler::returnHeldBuffer() {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ // Return the oldest buffer we're holding
+ if (mHeldBuffers.empty()) {
+ // No buffers are currently held
+ return false;
+ }
+
+ std::vector<BufferDesc> buffers = std::move(mHeldBuffers.front());
+ mHeldBuffers.pop();
+ mCamera->doneWithFrame(buffers);
+
+ return true;
+}
+
+bool FrameHandler::isRunning() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mRunning;
+}
+
+void FrameHandler::waitForFrameCount(unsigned frameCount) {
+ // Wait until we've seen at least the requested number of frames (could be more)
+ std::unique_lock<std::mutex> lock(mLock);
+ mFrameSignal.wait(lock, [this, frameCount]() { return mFramesReceived >= frameCount; });
+}
+
+void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ if (received) {
+ *received = mFramesReceived;
+ }
+ if (displayed) {
+ *displayed = mFramesDisplayed;
+ }
+}
+
+ScopedAStatus FrameHandler::deliverFrame(const std::vector<BufferDesc>& buffers) {
+ mLock.lock();
+ // For VTS tests, FrameHandler uses a single frame among delivered frames.
+ auto bufferIdx = mFramesDisplayed % buffers.size();
+ auto& buffer = buffers[bufferIdx];
+ mLock.unlock();
+
+ // Store a dimension of a received frame.
+ mFrameWidth = buffer.buffer.description.width;
+ mFrameHeight = buffer.buffer.description.height;
+
+ // If we were given an opened display at construction time, then send the received
+ // image back down the camera.
+ bool displayed = false;
+ if (mDisplay) {
+ // Get the output buffer we'll use to display the imagery
+ BufferDesc tgtBuffer;
+ auto status = mDisplay->getTargetBuffer(&tgtBuffer);
+ if (!status.isOk()) {
+ printf("Didn't get target buffer - frame lost\n");
+ LOG(ERROR) << "Didn't get requested output buffer -- skipping this frame.";
+ } else {
+ // Copy the contents of the of buffer.memHandle into tgtBuffer
+ copyBufferContents(tgtBuffer, buffer);
+
+ // Send the target buffer back for display
+ auto status = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+ if (!status.isOk()) {
+ printf("AIDL error on display buffer (%d)- frame lost\n",
+ status.getServiceSpecificError());
+ LOG(ERROR) << "Error making the remote function call. AIDL said "
+ << status.getServiceSpecificError();
+ } else {
+ // Everything looks good!
+ // Keep track so tests or watch dogs can monitor progress
+ displayed = true;
+ }
+ }
+ }
+
+ mLock.lock();
+ // increases counters
+ ++mFramesReceived;
+ mFramesDisplayed += (int)displayed;
+ mLock.unlock();
+ mFrameSignal.notify_all();
+
+ switch (mReturnMode) {
+ case eAutoReturn:
+ // Send the camera buffer back now that the client has seen it
+ LOG(DEBUG) << "Calling doneWithFrame";
+ mCamera->doneWithFrame(buffers);
+ break;
+ case eNoAutoReturn:
+ // Hang onto the buffer handles for now -- the client will return it explicitly later
+ // mHeldBuffers.push(buffers);
+ break;
+ }
+
+ LOG(DEBUG) << "Frame handling complete";
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus FrameHandler::notify(const EvsEventDesc& event) {
+ // Local flag we use to keep track of when the stream is stopping
+ std::unique_lock<std::mutex> lock(mEventLock);
+ mLatestEventDesc.aType = event.aType;
+ mLatestEventDesc.payload[0] = event.payload[0];
+ mLatestEventDesc.payload[1] = event.payload[1];
+ if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
+ // Signal that the last frame has been received and the stream is stopped
+ mRunning = false;
+ } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) {
+ LOG(DEBUG) << "Camera parameter " << mLatestEventDesc.payload[0] << " is changed to "
+ << mLatestEventDesc.payload[1];
+ } else {
+ LOG(DEBUG) << "Received an event " << eventToString(mLatestEventDesc.aType);
+ }
+ lock.unlock();
+ mEventSignal.notify_one();
+
+ return ScopedAStatus::ok();
+}
+
+bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, const BufferDesc& srcBuffer) {
+ bool success = true;
+ const HardwareBufferDescription* pSrcDesc =
+ reinterpret_cast<const HardwareBufferDescription*>(&srcBuffer.buffer.description);
+ const HardwareBufferDescription* pTgtDesc =
+ reinterpret_cast<const HardwareBufferDescription*>(&tgtBuffer.buffer.description);
+
+ // Make sure we don't run off the end of either buffer
+ const unsigned width = std::min(pTgtDesc->width, pSrcDesc->width);
+ const unsigned height = std::min(pTgtDesc->height, pSrcDesc->height);
+
+ // FIXME: We duplicate file descriptors twice below; consider using TAKE_HANDLE
+ // instead of CLONE_HANDLE.
+ buffer_handle_t target = ::android::dupFromAidl(tgtBuffer.buffer.handle);
+ ::android::sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(
+ target, android::GraphicBuffer::CLONE_HANDLE, pTgtDesc->width, pTgtDesc->height,
+ static_cast<android::PixelFormat>(pTgtDesc->format), pTgtDesc->layers,
+ static_cast<uint64_t>(pTgtDesc->usage), pTgtDesc->stride);
+
+ buffer_handle_t source = ::android::dupFromAidl(srcBuffer.buffer.handle);
+ ::android::sp<android::GraphicBuffer> src = new android::GraphicBuffer(
+ source, android::GraphicBuffer::CLONE_HANDLE, pSrcDesc->width, pSrcDesc->height,
+ static_cast<android::PixelFormat>(pSrcDesc->format), pSrcDesc->layers,
+ static_cast<uint64_t>(pSrcDesc->usage), pSrcDesc->stride);
+
+ // Lock our source buffer for reading (current expectation are for this to be NV21 format)
+ uint8_t* srcPixels = nullptr;
+ src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
+
+ // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format)
+ uint32_t* tgtPixels = nullptr;
+ tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
+
+ if (srcPixels && tgtPixels) {
+ using namespace ::android::hardware::automotive::evs::common;
+ if (static_cast<android_pixel_format_t>(pTgtDesc->format) == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+ HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
+ Utils::copyNV21toRGB32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+ } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+ HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+ Utils::copyYV12toRGB32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+ } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+ HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+ Utils::copyYUYVtoRGB32(width, height, srcPixels, pSrcDesc->stride, tgtPixels,
+ pTgtDesc->stride);
+ } else if (pSrcDesc->format == pTgtDesc->format) { // 32bit RGBA
+ Utils::copyMatchedInterleavedFormats(width, height, srcPixels, pSrcDesc->stride,
+ tgtPixels, pTgtDesc->stride,
+ tgtBuffer.pixelSizeBytes);
+ } else {
+ LOG(ERROR) << "Camera buffer format is not supported";
+ success = false;
+ }
+ } else if (static_cast<android_pixel_format_t>(pTgtDesc->format) ==
+ HAL_PIXEL_FORMAT_BGRA_8888) {
+ if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+ HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
+ Utils::copyNV21toBGR32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+ } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+ HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+ Utils::copyYV12toBGR32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+ } else if (static_cast<android_pixel_format_t>(pSrcDesc->format) ==
+ HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+ Utils::copyYUYVtoBGR32(width, height, srcPixels, pSrcDesc->stride, tgtPixels,
+ pTgtDesc->stride);
+ } else if (pSrcDesc->format == pTgtDesc->format) { // 32bit RGBA
+ Utils::copyMatchedInterleavedFormats(width, height, srcPixels, pSrcDesc->stride,
+ tgtPixels, pTgtDesc->stride,
+ tgtBuffer.pixelSizeBytes);
+ } else {
+ LOG(ERROR) << "Camera buffer format is not supported";
+ success = false;
+ }
+ } else {
+ // We always expect 32 bit RGB for the display output for now. Is there a need for 565?
+ LOG(ERROR) << "Diplay buffer is always expected to be 32bit RGBA";
+ success = false;
+ }
+ } else {
+ LOG(ERROR) << "Failed to lock buffer contents for contents transfer";
+ success = false;
+ }
+
+ if (srcPixels) {
+ src->unlock();
+ }
+ if (tgtPixels) {
+ tgt->unlock();
+ }
+
+ return success;
+}
+
+void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) {
+ if (width) {
+ *width = mFrameWidth;
+ }
+
+ if (height) {
+ *height = mFrameHeight;
+ }
+}
+
+bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent, EvsEventDesc& aReceivedEvent,
+ bool ignorePayload) {
+ // Wait until we get an expected parameter change event.
+ std::unique_lock<std::mutex> lock(mEventLock);
+ auto now = std::chrono::system_clock::now();
+ bool found = false;
+ while (!found) {
+ bool result = mEventSignal.wait_until(
+ lock, now + 5s, [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found]() {
+ found = (mLatestEventDesc.aType == aTargetEvent.aType) &&
+ (ignorePayload ||
+ (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] &&
+ mLatestEventDesc.payload[1] == aTargetEvent.payload[1]));
+
+ aReceivedEvent.aType = mLatestEventDesc.aType;
+ aReceivedEvent.payload[0] = mLatestEventDesc.payload[0];
+ aReceivedEvent.payload[1] = mLatestEventDesc.payload[1];
+ return found;
+ });
+
+ if (!result) {
+ LOG(WARNING) << "A timer is expired before a target event has happened.";
+ break;
+ }
+ }
+
+ return found;
+}
+
+const char* FrameHandler::eventToString(const EvsEventType aType) {
+ switch (aType) {
+ case EvsEventType::STREAM_STARTED:
+ return "STREAM_STARTED";
+ case EvsEventType::STREAM_STOPPED:
+ return "STREAM_STOPPED";
+ case EvsEventType::FRAME_DROPPED:
+ return "FRAME_DROPPED";
+ case EvsEventType::TIMEOUT:
+ return "TIMEOUT";
+ case EvsEventType::PARAMETER_CHANGED:
+ return "PARAMETER_CHANGED";
+ case EvsEventType::MASTER_RELEASED:
+ return "MASTER_RELEASED";
+ default:
+ return "Unknown";
+ }
+}
diff --git a/automotive/evs/aidl/vts/FrameHandler.h b/automotive/evs/aidl/vts/FrameHandler.h
new file mode 100644
index 0000000..0b959ab
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandler.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef AUTOMOTIVE_EVS_VTS_FRAMEHANDLER_H
+#define AUTOMOTIVE_EVS_VTS_FRAMEHANDLER_H
+
+#include <aidl/android/hardware/automotive/evs/BnEvsCameraStream.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+
+#include <mutex>
+#include <queue>
+
+/*
+ * FrameHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation. Given an
+ * IEvsDisplay instance at startup, it will forward the received imagery to the display,
+ * providing a trivial implementation of a rear vew camera type application.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class FrameHandler : public ::aidl::android::hardware::automotive::evs::BnEvsCameraStream {
+ public:
+ enum BufferControlFlag {
+ eAutoReturn,
+ eNoAutoReturn,
+ };
+
+ FrameHandler(
+ const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera>& pCamera,
+ const ::aidl::android::hardware::automotive::evs::CameraDesc& cameraInfo,
+ const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
+ pDisplay,
+ BufferControlFlag mode = eAutoReturn);
+ virtual ~FrameHandler() {
+ if (mCamera != nullptr) {
+ /* shutdown a camera explicitly */
+ shutdown();
+ }
+ }
+
+ void shutdown();
+ bool startStream();
+ void asyncStopStream();
+ void blockingStopStream();
+ bool returnHeldBuffer();
+ bool isRunning();
+ void waitForFrameCount(unsigned frameCount);
+ bool waitForEvent(const ::aidl::android::hardware::automotive::evs::EvsEventDesc& aTargetEvent,
+ ::aidl::android::hardware::automotive::evs::EvsEventDesc& aReceivedEvent,
+ bool ignorePayload = false);
+ void getFramesCounters(unsigned* received, unsigned* displayed);
+ void getFrameDimension(unsigned* width, unsigned* height);
+
+ private:
+ // Methods from ::aidl::android::hardware::automotive::evs::IEvsCameraStream follow.
+ ::ndk::ScopedAStatus deliverFrame(
+ const std::vector<::aidl::android::hardware::automotive::evs::BufferDesc>& buffer)
+ override;
+ ::ndk::ScopedAStatus notify(
+ const ::aidl::android::hardware::automotive::evs::EvsEventDesc& event) override;
+
+ // Local implementation details
+ bool copyBufferContents(
+ const ::aidl::android::hardware::automotive::evs::BufferDesc& tgtBuffer,
+ const ::aidl::android::hardware::automotive::evs::BufferDesc& srcBuffer);
+ const char* eventToString(const ::aidl::android::hardware::automotive::evs::EvsEventType aType);
+
+ std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera> mCamera;
+ ::aidl::android::hardware::automotive::evs::CameraDesc mCameraInfo;
+ std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay> mDisplay;
+ BufferControlFlag mReturnMode;
+
+ // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface,
+ // we need to protect all member variables that may be modified while we're streaming
+ // (ie: those below)
+ std::mutex mLock;
+ std::mutex mEventLock;
+ std::condition_variable mEventSignal;
+ std::condition_variable mFrameSignal;
+ std::queue<std::vector<::aidl::android::hardware::automotive::evs::BufferDesc>> mHeldBuffers;
+
+ bool mRunning = false;
+ unsigned mFramesReceived = 0; // Simple counter -- rolls over eventually!
+ unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually!
+ unsigned mFrameWidth = 0;
+ unsigned mFrameHeight = 0;
+ ::aidl::android::hardware::automotive::evs::EvsEventDesc mLatestEventDesc;
+};
+
+#endif // AUTOMOTIVE_EVS_VTS_FRAMEHANDLER_H
diff --git a/automotive/evs/aidl/vts/FrameHandlerUltrasonics.cpp b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.cpp
new file mode 100644
index 0000000..650f0ed
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 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.
+ */
+
+#include "FrameHandlerUltrasonics.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventType.h>
+#include <aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.h>
+#include <aidl/android/hardware/automotive/evs/UltrasonicsDataFrameDesc.h>
+#include <android-base/logging.h>
+
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray;
+using ::aidl::android::hardware::automotive::evs::UltrasonicsDataFrameDesc;
+using ::ndk::ScopedAStatus;
+
+namespace {
+
+// Struct used by SerializeWaveformData().
+struct WaveformData {
+ uint8_t receiverId;
+ std::vector<std::pair<float, float>> readings;
+};
+
+} // namespace
+
+FrameHandlerUltrasonics::FrameHandlerUltrasonics(
+ const std::shared_ptr<IEvsUltrasonicsArray>& pArray)
+ : mEvsUltrasonicsArray(pArray), mReceiveFramesCount(0) {
+ // Nothing but member initialization
+}
+
+ScopedAStatus FrameHandlerUltrasonics::notify(const EvsEventDesc& evsEvent) {
+ switch (evsEvent.aType) {
+ case EvsEventType::STREAM_STARTED:
+ case EvsEventType::STREAM_STOPPED:
+ case EvsEventType::FRAME_DROPPED:
+ case EvsEventType::TIMEOUT:
+ mReceivedEvents.emplace_back(evsEvent);
+ break;
+ default:
+ LOG(ERROR) << "Received unexpected event";
+ }
+
+ return ScopedAStatus::ok();
+}
+
+// De-serializes shared memory to vector of WaveformData.
+// TODO(b/149950362): Add a common library for serializing and deserializing waveform data.
+std::vector<WaveformData> DeSerializeWaveformData(std::vector<uint32_t> recvReadingsCountList,
+ uint8_t* pData) {
+ std::vector<WaveformData> waveformDataList(recvReadingsCountList.size());
+
+ for (int i = 0; i < waveformDataList.size(); i++) {
+ // Set Id
+ memcpy(&waveformDataList[i].receiverId, pData, sizeof(uint8_t));
+ pData += sizeof(uint8_t);
+
+ waveformDataList[i].readings.resize(recvReadingsCountList[i]);
+
+ for (auto& reading : waveformDataList[i].readings) {
+ // Set the time of flight.
+ memcpy(&reading.first, pData, sizeof(float));
+ pData += sizeof(float);
+
+ // Set the resonance.
+ memcpy(&reading.second, pData, sizeof(float));
+ pData += sizeof(float);
+ }
+ }
+ return waveformDataList;
+}
+
+bool DataFrameValidator(const UltrasonicsDataFrameDesc& /*dataFrameDesc*/) {
+ // TODO(b/214026378): implement a method to validate an ultrasonics data frame
+ (void)DeSerializeWaveformData;
+ return true;
+}
+
+ScopedAStatus FrameHandlerUltrasonics::deliverDataFrame(
+ const UltrasonicsDataFrameDesc& dataFrameDesc) {
+ LOG(DEBUG) << "FrameHandlerUltrasonics::receiveFrames";
+
+ mReceiveFramesCount++;
+
+ if (!DataFrameValidator(dataFrameDesc)) {
+ mAllFramesValid = false;
+ }
+
+ // Send done with data frame.
+ mEvsUltrasonicsArray->doneWithDataFrame(dataFrameDesc);
+ return ScopedAStatus::ok();
+}
+
+bool FrameHandlerUltrasonics::checkEventReceived(const EvsEventDesc& evsEvent) {
+ LOG(DEBUG) << "FrameHandlerUltrasonics::checkEventReceived";
+ int size = mReceivedEvents.size(); // work around
+ LOG(DEBUG) << "Received event number: " << size;
+ auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), evsEvent);
+ return iter != mReceivedEvents.end();
+}
+
+int FrameHandlerUltrasonics::getReceiveFramesCount() {
+ return mReceiveFramesCount;
+}
+
+bool FrameHandlerUltrasonics::areAllFramesValid() {
+ return mAllFramesValid;
+}
diff --git a/automotive/evs/aidl/vts/FrameHandlerUltrasonics.h b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.h
new file mode 100644
index 0000000..f853a00
--- /dev/null
+++ b/automotive/evs/aidl/vts/FrameHandlerUltrasonics.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef AUTOMOTIVE_EVS_VTS_FRAMEHANDLERULTRASONICS_H
+#define AUTOMOTIVE_EVS_VTS_FRAMEHANDLERULTRASONICS_H
+
+#include <aidl/android/hardware/automotive/evs/BnEvsUltrasonicsArrayStream.h>
+#include <aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.h>
+
+#include <vector>
+
+class FrameHandlerUltrasonics
+ : public ::aidl::android::hardware::automotive::evs::BnEvsUltrasonicsArrayStream {
+ public:
+ FrameHandlerUltrasonics(
+ const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>&
+ pArray);
+
+ // Implementation for ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArrayStream
+ ::ndk::ScopedAStatus notify(
+ const ::aidl::android::hardware::automotive::evs::EvsEventDesc& event) override;
+ ::ndk::ScopedAStatus deliverDataFrame(
+ const ::aidl::android::hardware::automotive::evs::UltrasonicsDataFrameDesc& desc)
+ override;
+
+ bool checkEventReceived(
+ const ::aidl::android::hardware::automotive::evs::EvsEventDesc& evsEvent);
+ int getReceiveFramesCount();
+ bool areAllFramesValid();
+
+ private:
+ std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray>
+ mEvsUltrasonicsArray;
+ std::vector<::aidl::android::hardware::automotive::evs::EvsEventDesc> mReceivedEvents;
+ int mReceiveFramesCount;
+ bool mAllFramesValid = true;
+};
+
+#endif // AUTOMOTIVE_EVS_VTS_FRAMEHANDLERULTRASONICS_H
diff --git a/automotive/evs/aidl/vts/OWNERS b/automotive/evs/aidl/vts/OWNERS
new file mode 100644
index 0000000..a104f50
--- /dev/null
+++ b/automotive/evs/aidl/vts/OWNERS
@@ -0,0 +1,3 @@
+#Bug component : 853002
+ankitarora@google.com
+changyeon@google.com
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
new file mode 100644
index 0000000..c709d40
--- /dev/null
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -0,0 +1,2170 @@
+/*
+ * 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.
+ */
+
+#include "FrameHandler.h"
+#include "FrameHandlerUltrasonics.h"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraParam.h>
+#include <aidl/android/hardware/automotive/evs/DisplayDesc.h>
+#include <aidl/android/hardware/automotive/evs/DisplayState.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventType.h>
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.h>
+#include <aidl/android/hardware/automotive/evs/ParameterRange.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <aidl/android/hardware/automotive/evs/UltrasonicsArrayDesc.h>
+#include <aidl/android/hardware/common/NativeHandle.h>
+#include <aidl/android/hardware/graphics/common/HardwareBufferDescription.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+#include <system/camera_metadata.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <utils/Timers.h>
+
+#include <deque>
+#include <thread>
+#include <unordered_set>
+
+namespace {
+
+// These values are called out in the EVS design doc (as of Mar 8, 2017)
+constexpr int kMaxStreamStartMilliseconds = 500;
+constexpr int kMinimumFramesPerSecond = 10;
+constexpr int kSecondsToMilliseconds = 1000;
+constexpr int kMillisecondsToMicroseconds = 1000;
+constexpr float kNanoToMilliseconds = 0.000001f;
+constexpr float kNanoToSeconds = 0.000000001f;
+
+/*
+ * Please note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+typedef struct {
+ int32_t id;
+ int32_t width;
+ int32_t height;
+ int32_t format;
+ int32_t direction;
+ int32_t framerate;
+} RawStreamConfig;
+constexpr size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
+
+} // namespace
+
+using ::aidl::android::hardware::automotive::evs::BufferDesc;
+using ::aidl::android::hardware::automotive::evs::CameraDesc;
+using ::aidl::android::hardware::automotive::evs::CameraParam;
+using ::aidl::android::hardware::automotive::evs::DisplayDesc;
+using ::aidl::android::hardware::automotive::evs::DisplayState;
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::EvsResult;
+using ::aidl::android::hardware::automotive::evs::IEvsCamera;
+using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray;
+using ::aidl::android::hardware::automotive::evs::ParameterRange;
+using ::aidl::android::hardware::automotive::evs::Stream;
+using ::aidl::android::hardware::automotive::evs::UltrasonicsArrayDesc;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::HardwareBufferDescription;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using std::chrono_literals::operator""s;
+
+// The main test class for EVS
+class EvsAidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure we can connect to the enumerator
+ std::string service_name = GetParam();
+ AIBinder* binder = AServiceManager_waitForService(service_name.data());
+ ASSERT_NE(binder, nullptr);
+ mEnumerator = IEvsEnumerator::fromBinder(::ndk::SpAIBinder(binder));
+ LOG(INFO) << "Test target service: " << service_name;
+
+ ASSERT_TRUE(mEnumerator->isHardware(&mIsHwModule).isOk());
+ }
+
+ virtual void TearDown() override {
+ // Attempt to close any active camera
+ for (auto&& cam : mActiveCameras) {
+ if (cam != nullptr) {
+ mEnumerator->closeCamera(cam);
+ }
+ }
+ mActiveCameras.clear();
+ }
+
+ protected:
+ void loadCameraList() {
+ // SetUp() must run first!
+ ASSERT_NE(mEnumerator, nullptr);
+
+ // Get the camera list
+ ASSERT_TRUE(mEnumerator->getCameraList(&mCameraInfo).isOk())
+ << "Failed to get a list of available cameras";
+ LOG(INFO) << "We have " << mCameraInfo.size() << " cameras.";
+ }
+
+ void loadUltrasonicsArrayList() {
+ // SetUp() must run first!
+ ASSERT_NE(mEnumerator, nullptr);
+
+ // Get the ultrasonics array list
+ ASSERT_TRUE(mEnumerator->getUltrasonicsArrayList(&mUltrasonicsArraysInfo).isOk())
+ << "Failed to get a list of available ultrasonics arrays";
+ LOG(INFO) << "We have " << mCameraInfo.size() << " ultrasonics arrays.";
+ }
+
+ bool isLogicalCamera(const camera_metadata_t* metadata) {
+ if (metadata == nullptr) {
+ // A logical camera device must have a valid camera metadata.
+ return false;
+ }
+
+ // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
+ camera_metadata_ro_entry_t entry;
+ int rc = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ &entry);
+ if (rc != 0) {
+ // No capabilities are found.
+ return false;
+ }
+
+ for (size_t i = 0; i < entry.count; ++i) {
+ uint8_t cap = entry.data.u8[i];
+ if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ std::unordered_set<std::string> getPhysicalCameraIds(const std::string& id, bool& flag) {
+ std::unordered_set<std::string> physicalCameras;
+ const auto it = std::find_if(mCameraInfo.begin(), mCameraInfo.end(),
+ [&id](const CameraDesc& desc) { return id == desc.id; });
+ if (it == mCameraInfo.end()) {
+ // Unknown camera is requested. Return an empty list.
+ return physicalCameras;
+ }
+
+ const camera_metadata_t* metadata = reinterpret_cast<camera_metadata_t*>(&it->metadata[0]);
+ flag = isLogicalCamera(metadata);
+ if (!flag) {
+ // EVS assumes that the device w/o a valid metadata is a physical
+ // device.
+ LOG(INFO) << id << " is not a logical camera device.";
+ physicalCameras.insert(id);
+ return physicalCameras;
+ }
+
+ // Look for physical camera identifiers
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(metadata, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+ &entry);
+ if (rc != 0) {
+ LOG(ERROR) << "No physical camera ID is found for a logical camera device";
+ }
+
+ const uint8_t* ids = entry.data.u8;
+ size_t start = 0;
+ for (size_t i = 0; i < entry.count; ++i) {
+ if (ids[i] == '\0') {
+ if (start != i) {
+ std::string id(reinterpret_cast<const char*>(ids + start));
+ physicalCameras.insert(id);
+ }
+ start = i + 1;
+ }
+ }
+
+ LOG(INFO) << id << " consists of " << physicalCameras.size() << " physical camera devices";
+ return physicalCameras;
+ }
+
+ Stream getFirstStreamConfiguration(camera_metadata_t* metadata) {
+ Stream targetCfg = {};
+ camera_metadata_entry_t streamCfgs;
+ if (!find_camera_metadata_entry(metadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
+ for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+ targetCfg.format = static_cast<PixelFormat>(ptr->format);
+ break;
+ }
+ ++ptr;
+ }
+ }
+
+ return targetCfg;
+ }
+
+ // Every test needs access to the service
+ std::shared_ptr<IEvsEnumerator> mEnumerator;
+ // Empty unless/util loadCameraList() is called
+ std::vector<CameraDesc> mCameraInfo;
+ // boolean to tell current module under testing is HW module implementation
+ // or not
+ bool mIsHwModule;
+ // A list of active camera handles that are need to be cleaned up
+ std::deque<std::shared_ptr<IEvsCamera>> mActiveCameras;
+ // Empty unless/util loadUltrasonicsArrayList() is called
+ std::vector<UltrasonicsArrayDesc> mUltrasonicsArraysInfo;
+ // A list of active ultrasonics array handles that are to be cleaned up
+ std::deque<std::weak_ptr<IEvsUltrasonicsArray>> mActiveUltrasonicsArrays;
+};
+
+// Test cases, their implementations, and corresponding requirements are
+// documented at go/aae-evs-public-api-test.
+
+/*
+ * CameraOpenClean:
+ * Opens each camera reported by the enumerator and then explicitly closes it via a
+ * call to closeCamera. Then repeats the test to ensure all cameras can be reopened.
+ */
+TEST_P(EvsAidlTest, CameraOpenClean) {
+ LOG(INFO) << "Starting CameraOpenClean test";
+
+ // Get the camera list
+ loadCameraList();
+
+ // Open and close each camera twice
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ LOG(INFO) << "Skip a logical device, " << cam.id << " for HW target.";
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ for (int pass = 0; pass < 2; pass++) {
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ ASSERT_NE(pCam, nullptr);
+
+ CameraDesc cameraInfo;
+ for (auto&& devName : devices) {
+ ASSERT_TRUE(pCam->getPhysicalCameraInfo(devName, &cameraInfo).isOk());
+ EXPECT_EQ(devName, cameraInfo.id);
+ }
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam);
+
+ // Verify that this camera self-identifies correctly
+ ASSERT_TRUE(pCam->getCameraInfo(&cameraInfo).isOk());
+ EXPECT_EQ(cam.id, cameraInfo.id);
+
+ // Verify methods for extended info
+ const auto id = 0xFFFFFFFF; // meaningless id
+ std::vector<uint8_t> values;
+ auto status = pCam->setExtendedInfo(id, values);
+ if (isLogicalCam) {
+ EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+ static_cast<int>(EvsResult::NOT_SUPPORTED));
+ } else {
+ EXPECT_TRUE(status.isOk());
+ }
+
+ status = pCam->getExtendedInfo(id, &values);
+ if (isLogicalCam) {
+ EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+ static_cast<int>(EvsResult::NOT_SUPPORTED));
+ } else {
+ EXPECT_TRUE(status.isOk());
+ }
+
+ // Explicitly close the camera so resources are released right away
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.clear();
+ }
+ }
+}
+
+/*
+ * CameraOpenAggressive:
+ * Opens each camera reported by the enumerator twice in a row without an intervening closeCamera
+ * call. This ensures that the intended "aggressive open" behavior works. This is necessary for
+ * the system to be tolerant of shutdown/restart race conditions.
+ */
+TEST_P(EvsAidlTest, CameraOpenAggressive) {
+ LOG(INFO) << "Starting CameraOpenAggressive test";
+
+ // Get the camera list
+ loadCameraList();
+
+ // Open and close each camera twice
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ LOG(INFO) << "Skip a logical device, " << cam.id << " for HW target.";
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ mActiveCameras.clear();
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ EXPECT_NE(pCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam);
+
+ // Verify that this camera self-identifies correctly
+ CameraDesc cameraInfo;
+ ASSERT_TRUE(pCam->getCameraInfo(&cameraInfo).isOk());
+ EXPECT_EQ(cam.id, cameraInfo.id);
+
+ std::shared_ptr<IEvsCamera> pCam2;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam2).isOk());
+ EXPECT_NE(pCam2, nullptr);
+ EXPECT_NE(pCam, pCam2);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam2);
+
+ auto status = pCam->setMaxFramesInFlight(2);
+ if (mIsHwModule) {
+ // Verify that the old camera rejects calls via HW module.
+ EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+ static_cast<int>(EvsResult::OWNERSHIP_LOST));
+ } else {
+ // default implementation supports multiple clients.
+ EXPECT_TRUE(status.isOk());
+ }
+
+ // Close the superseded camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.pop_front();
+
+ // Verify that the second camera instance self-identifies correctly
+ ASSERT_TRUE(pCam2->getCameraInfo(&cameraInfo).isOk());
+ EXPECT_EQ(cam.id, cameraInfo.id);
+
+ // Close the second camera instance
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam2).isOk());
+ mActiveCameras.pop_front();
+ }
+
+ // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests
+ sleep(1); // I hate that this is an arbitrary time to wait. :( b/36122635
+}
+
+/*
+ * CameraStreamPerformance:
+ * Measure and qualify the stream start up time and streaming frame rate of each reported camera
+ */
+TEST_P(EvsAidlTest, CameraStreamPerformance) {
+ LOG(INFO) << "Starting CameraStreamPerformance test";
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ LOG(INFO) << "Skip a logical device " << cam.id;
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ EXPECT_NE(pCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam);
+
+ // Set up a frame receiver object which will fire up its own thread
+ std::shared_ptr<FrameHandler> frameHandler =
+ std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Start the camera's video stream
+ nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+ ASSERT_TRUE(frameHandler->startStream());
+
+ // Ensure the first frame arrived within the expected time
+ frameHandler->waitForFrameCount(1);
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start;
+
+ // Extra delays are expected when we attempt to start a video stream on
+ // the logical camera device. The amount of delay is expected the
+ // number of physical camera devices multiplied by
+ // kMaxStreamStartMilliseconds at most.
+ EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame),
+ kMaxStreamStartMilliseconds * devices.size());
+ printf("%s: Measured time to first frame %0.2f ms\n", cam.id.data(),
+ timeToFirstFrame * kNanoToMilliseconds);
+ LOG(INFO) << cam.id << ": Measured time to first frame " << std::scientific
+ << timeToFirstFrame * kNanoToMilliseconds << " ms.";
+
+ // Check aspect ratio
+ unsigned width = 0, height = 0;
+ frameHandler->getFrameDimension(&width, &height);
+ EXPECT_GE(width, height);
+
+ // Wait a bit, then ensure we get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Even when the camera pointer goes out of scope, the FrameHandler object will
+ // keep the stream alive unless we tell it to shutdown.
+ // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+ // we have to break that cycle in order for either of them to get cleaned up.
+ frameHandler->shutdown();
+
+ unsigned framesReceived = 0;
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ framesReceived = framesReceived - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond = framesReceived / (runTime * kNanoToSeconds);
+ printf("Measured camera rate %3.2f fps\n", framesPerSecond);
+ LOG(INFO) << "Measured camera rate " << std::scientific << framesPerSecond << " fps.";
+ EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.clear();
+ }
+}
+
+/*
+ * CameraStreamBuffering:
+ * Ensure the camera implementation behaves properly when the client holds onto buffers for more
+ * than one frame time. The camera must cleanly skip frames until the client is ready again.
+ */
+TEST_P(EvsAidlTest, CameraStreamBuffering) {
+ LOG(INFO) << "Starting CameraStreamBuffering test";
+
+ // Arbitrary constant (should be > 1 and not too big)
+ static const unsigned int kBuffersToHold = 6;
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ LOG(INFO) << "Skip a logical device " << cam.id << " for HW target.";
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ EXPECT_NE(pCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam);
+
+ // Ask for a very large number of buffers in flight to ensure it errors correctly
+ auto badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
+ EXPECT_TRUE(!badResult.isOk() && badResult.getServiceSpecificError() ==
+ static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
+
+ // Now ask for exactly two buffers in flight as we'll test behavior in that case
+ ASSERT_TRUE(pCam->setMaxFramesInFlight(kBuffersToHold).isOk());
+
+ // Set up a frame receiver object which will fire up its own thread.
+ std::shared_ptr<FrameHandler> frameHandler =
+ std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eNoAutoReturn);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler->startStream());
+
+ // Check that the video stream stalls once we've gotten exactly the number of buffers
+ // we requested since we told the frameHandler not to return them.
+ sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case
+ unsigned framesReceived = 0;
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+
+ // Give back one buffer
+ ASSERT_TRUE(frameHandler->returnHeldBuffer());
+
+ // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+ // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+ usleep(110 * kMillisecondsToMicroseconds);
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ EXPECT_EQ(kBuffersToHold + 1, framesReceived) << "Stream should've resumed";
+
+ // Even when the camera pointer goes out of scope, the FrameHandler object will
+ // keep the stream alive unless we tell it to shutdown.
+ // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+ // we have to break that cycle in order for either of them to get cleaned up.
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.clear();
+ }
+}
+
+/*
+ * CameraToDisplayRoundTrip:
+ * End to end test of data flowing from the camera to the display. Each delivered frame of camera
+ * imagery is simply copied to the display buffer and presented on screen. This is the one test
+ * which a human could observe to see the operation of the system on the physical display.
+ */
+TEST_P(EvsAidlTest, CameraToDisplayRoundTrip) {
+ LOG(INFO) << "Starting CameraToDisplayRoundTrip test";
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request available display IDs
+ uint8_t targetDisplayId = 0;
+ std::vector<uint8_t> displayIds;
+ ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+ EXPECT_GT(displayIds.size(), 0);
+ targetDisplayId = displayIds[0];
+
+ // Request exclusive access to the first EVS display
+ std::shared_ptr<IEvsDisplay> pDisplay;
+ ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+ EXPECT_NE(pDisplay, nullptr);
+ LOG(INFO) << "Display " << targetDisplayId << " is in use.";
+
+ // Get the display descriptor
+ DisplayDesc displayDesc;
+ ASSERT_TRUE(pDisplay->getDisplayInfo(&displayDesc).isOk());
+ LOG(INFO) << " Resolution: " << displayDesc.width << "x" << displayDesc.height;
+ ASSERT_GT(displayDesc.width, 0);
+ ASSERT_GT(displayDesc.height, 0);
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ LOG(INFO) << "Skip a logical device " << cam.id << " for HW target.";
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ EXPECT_NE(pCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam);
+
+ // Set up a frame receiver object which will fire up its own thread.
+ std::shared_ptr<FrameHandler> frameHandler =
+ std::make_shared<FrameHandler>(pCam, cam, pDisplay, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Activate the display
+ ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME).isOk());
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler->startStream());
+
+ // Wait a while to let the data flow
+ static const int kSecondsToWait = 5;
+ const int streamTimeMs =
+ kSecondsToWait * kSecondsToMilliseconds - kMaxStreamStartMilliseconds;
+ const unsigned minimumFramesExpected =
+ streamTimeMs * kMinimumFramesPerSecond / kSecondsToMilliseconds;
+ sleep(kSecondsToWait);
+ unsigned framesReceived = 0;
+ unsigned framesDisplayed = 0;
+ frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+ EXPECT_EQ(framesReceived, framesDisplayed);
+ EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::NOT_VISIBLE).isOk());
+
+ // Shut down the streamer
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.clear();
+ }
+
+ // Explicitly release the display
+ ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+}
+
+/*
+ * MultiCameraStream:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera.
+ */
+TEST_P(EvsAidlTest, MultiCameraStream) {
+ LOG(INFO) << "Starting MultiCameraStream test";
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ // Create two camera clients.
+ std::shared_ptr<IEvsCamera> pCam0;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam0).isOk());
+ EXPECT_NE(pCam0, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam0);
+
+ std::shared_ptr<IEvsCamera> pCam1;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+ EXPECT_NE(pCam1, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam1);
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ std::shared_ptr<FrameHandler> frameHandler0 =
+ std::make_shared<FrameHandler>(pCam0, cam, nullptr, FrameHandler::eAutoReturn);
+ std::shared_ptr<FrameHandler> frameHandler1 =
+ std::make_shared<FrameHandler>(pCam1, cam, nullptr, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandler0, nullptr);
+ EXPECT_NE(frameHandler1, nullptr);
+
+ // Start the camera's video stream via client 0
+ ASSERT_TRUE(frameHandler0->startStream());
+ ASSERT_TRUE(frameHandler1->startStream());
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Wait a bit, then ensure both clients get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived0 = 0, framesReceived1 = 0;
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+ framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for
+ framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+ float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+ LOG(INFO) << "Measured camera rate " << std::scientific << framesPerSecond0 << " fps and "
+ << framesPerSecond1 << " fps";
+ EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+ EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+ // Shutdown one client
+ frameHandler0->shutdown();
+
+ // Read frame counters again
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+ // Wait a bit again
+ sleep(5);
+ unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+ frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+ EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+ EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+ // Shutdown another
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
+ mActiveCameras.clear();
+
+ // TODO(b/145459970, b/145457727): below sleep() is added to ensure the
+ // destruction of active camera objects; this may be related with two
+ // issues.
+ sleep(1);
+ }
+}
+
+/*
+ * CameraParameter:
+ * Verify that a client can adjust a camera parameter.
+ */
+TEST_P(EvsAidlTest, CameraParameter) {
+ LOG(INFO) << "Starting CameraParameter test";
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ LOG(INFO) << "Skip a logical device " << cam.id;
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ // Create a camera client
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ EXPECT_NE(pCam, nullptr);
+
+ // Store a camera
+ mActiveCameras.push_back(pCam);
+
+ // Get the parameter list
+ std::vector<CameraParam> cmds;
+ ASSERT_TRUE(pCam->getParameterList(&cmds).isOk());
+ if (cmds.size() < 1) {
+ continue;
+ }
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ std::shared_ptr<FrameHandler> frameHandler =
+ std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler->startStream());
+
+ // Ensure the stream starts
+ frameHandler->waitForFrameCount(1);
+
+ // Set current client is the primary client
+ ASSERT_TRUE(pCam->setPrimaryClient().isOk());
+ for (auto& cmd : cmds) {
+ // Get a valid parameter value range
+ ParameterRange range;
+ ASSERT_TRUE(pCam->getIntParameterRange(cmd, &range).isOk());
+
+ std::vector<int32_t> values;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ ASSERT_TRUE(pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(v, 0);
+ }
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal]
+ int32_t val0 = range.min + (std::rand() % (range.max - range.min));
+
+ // Rounding down
+ val0 = val0 - (val0 % range.step);
+ values.clear();
+ ASSERT_TRUE(pCam->setIntParameter(cmd, val0, &values).isOk());
+
+ values.clear();
+ ASSERT_TRUE(pCam->getIntParameter(cmd, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(val0, v) << "Values are not matched.";
+ }
+ }
+ ASSERT_TRUE(pCam->unsetPrimaryClient().isOk());
+
+ // Shutdown
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.clear();
+ }
+}
+
+/*
+ * CameraPrimaryClientRelease
+ * Verify that non-primary client gets notified when the primary client either
+ * terminates or releases a role.
+ */
+TEST_P(EvsAidlTest, CameraPrimaryClientRelease) {
+ LOG(INFO) << "Starting CameraPrimaryClientRelease test";
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ LOG(INFO) << "Skip a logical device " << cam.id;
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ // Create two camera clients.
+ std::shared_ptr<IEvsCamera> pPrimaryCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pPrimaryCam).isOk());
+ EXPECT_NE(pPrimaryCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pPrimaryCam);
+
+ std::shared_ptr<IEvsCamera> pSecondaryCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pSecondaryCam).isOk());
+ EXPECT_NE(pSecondaryCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pSecondaryCam);
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ std::shared_ptr<FrameHandler> frameHandlerPrimary = std::make_shared<FrameHandler>(
+ pPrimaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+ std::shared_ptr<FrameHandler> frameHandlerSecondary = std::make_shared<FrameHandler>(
+ pSecondaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandlerPrimary, nullptr);
+ EXPECT_NE(frameHandlerSecondary, nullptr);
+
+ // Set one client as the primary client
+ ASSERT_TRUE(pPrimaryCam->setPrimaryClient().isOk());
+
+ // Try to set another client as the primary client.
+ ASSERT_FALSE(pSecondaryCam->setPrimaryClient().isOk());
+
+ // Start the camera's video stream via a primary client client.
+ ASSERT_TRUE(frameHandlerPrimary->startStream());
+
+ // Ensure the stream starts
+ frameHandlerPrimary->waitForFrameCount(1);
+
+ // Start the camera's video stream via another client
+ ASSERT_TRUE(frameHandlerSecondary->startStream());
+
+ // Ensure the stream starts
+ frameHandlerSecondary->waitForFrameCount(1);
+
+ // Non-primary client expects to receive a primary client role relesed
+ // notification.
+ EvsEventDesc aTargetEvent = {};
+ EvsEventDesc aNotification = {};
+
+ bool listening = false;
+ std::mutex eventLock;
+ std::condition_variable eventCond;
+ std::thread listener =
+ std::thread([&aNotification, &frameHandlerSecondary, &listening, &eventCond]() {
+ // Notify that a listening thread is running.
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification, true)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a listening thread starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ timer += 1s;
+ eventCond.wait_until(lock, timer);
+ }
+ lock.unlock();
+
+ // Release a primary client role.
+ ASSERT_TRUE(pPrimaryCam->unsetPrimaryClient().isOk());
+
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast<EvsEventType>(aNotification.aType));
+
+ // Non-primary becomes a primary client.
+ ASSERT_TRUE(pSecondaryCam->setPrimaryClient().isOk());
+
+ // Previous primary client fails to become a primary client.
+ ASSERT_FALSE(pPrimaryCam->setPrimaryClient().isOk());
+
+ listening = false;
+ listener = std::thread([&aNotification, &frameHandlerPrimary, &listening, &eventCond]() {
+ // Notify that a listening thread is running.
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification, true)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a listening thread starts.
+ timer = std::chrono::system_clock::now();
+ lock.lock();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Closing current primary client.
+ frameHandlerSecondary->shutdown();
+
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast<EvsEventType>(aNotification.aType));
+
+ // Closing streams.
+ frameHandlerPrimary->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pPrimaryCam).isOk());
+ ASSERT_TRUE(mEnumerator->closeCamera(pSecondaryCam).isOk());
+ mActiveCameras.clear();
+ }
+}
+
+/*
+ * MultiCameraParameter:
+ * Verify that primary and non-primary clients behave as expected when they try to adjust
+ * camera parameters.
+ */
+TEST_P(EvsAidlTest, MultiCameraParameter) {
+ LOG(INFO) << "Starting MultiCameraParameter test";
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ LOG(INFO) << "Skip a logical device " << cam.id;
+ continue;
+ }
+
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ // Create two camera clients.
+ std::shared_ptr<IEvsCamera> pPrimaryCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pPrimaryCam).isOk());
+ EXPECT_NE(pPrimaryCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pPrimaryCam);
+
+ std::shared_ptr<IEvsCamera> pSecondaryCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pSecondaryCam).isOk());
+ EXPECT_NE(pSecondaryCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pSecondaryCam);
+
+ // Get the parameter list
+ std::vector<CameraParam> camPrimaryCmds, camSecondaryCmds;
+ ASSERT_TRUE(pPrimaryCam->getParameterList(&camPrimaryCmds).isOk());
+ ASSERT_TRUE(pSecondaryCam->getParameterList(&camSecondaryCmds).isOk());
+ if (camPrimaryCmds.size() < 1 || camSecondaryCmds.size() < 1) {
+ // Skip a camera device if it does not support any parameter.
+ continue;
+ }
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ std::shared_ptr<FrameHandler> frameHandlerPrimary = std::make_shared<FrameHandler>(
+ pPrimaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+ std::shared_ptr<FrameHandler> frameHandlerSecondary = std::make_shared<FrameHandler>(
+ pSecondaryCam, cam, nullptr, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandlerPrimary, nullptr);
+ EXPECT_NE(frameHandlerSecondary, nullptr);
+
+ // Set one client as the primary client.
+ ASSERT_TRUE(pPrimaryCam->setPrimaryClient().isOk());
+
+ // Try to set another client as the primary client.
+ ASSERT_FALSE(pSecondaryCam->setPrimaryClient().isOk());
+
+ // Start the camera's video stream via a primary client client.
+ ASSERT_TRUE(frameHandlerPrimary->startStream());
+
+ // Ensure the stream starts
+ frameHandlerPrimary->waitForFrameCount(1);
+
+ // Start the camera's video stream via another client
+ ASSERT_TRUE(frameHandlerSecondary->startStream());
+
+ // Ensure the stream starts
+ frameHandlerSecondary->waitForFrameCount(1);
+
+ int32_t val0 = 0;
+ std::vector<int32_t> values;
+ EvsEventDesc aNotification0 = {};
+ EvsEventDesc aNotification1 = {};
+ for (auto& cmd : camPrimaryCmds) {
+ // Get a valid parameter value range
+ ParameterRange range;
+ ASSERT_TRUE(pPrimaryCam->getIntParameterRange(cmd, &range).isOk());
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ values.clear();
+ ASSERT_TRUE(
+ pPrimaryCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(v, 0);
+ }
+ }
+
+ // Calculate a parameter value to program.
+ val0 = range.min + (std::rand() % (range.max - range.min));
+ val0 = val0 - (val0 % range.step);
+
+ // Prepare and start event listeners.
+ bool listening0 = false;
+ bool listening1 = false;
+ std::condition_variable eventCond;
+ std::thread listener0 = std::thread([cmd, val0, &aNotification0, &frameHandlerPrimary,
+ &listening0, &listening1, &eventCond]() {
+ listening0 = true;
+ if (listening1) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+ std::thread listener1 = std::thread([cmd, val0, &aNotification1, &frameHandlerSecondary,
+ &listening0, &listening1, &eventCond]() {
+ listening1 = true;
+ if (listening0) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a listening thread starts.
+ std::mutex eventLock;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening0 || !listening1) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to program a parameter
+ values.clear();
+ ASSERT_TRUE(pPrimaryCam->setIntParameter(cmd, val0, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(val0, v) << "Values are not matched.";
+ }
+
+ // Join a listening thread.
+ if (listener0.joinable()) {
+ listener0.join();
+ }
+ if (listener1.joinable()) {
+ listener1.join();
+ }
+
+ // Verify a change notification
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification0.aType));
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification1.aType));
+ ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification0.payload[0]));
+ ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification1.payload[0]));
+ for (auto&& v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification0.payload[1]));
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification1.payload[1]));
+ }
+
+ // Clients expects to receive a parameter change notification
+ // whenever a primary client client adjusts it.
+ values.clear();
+ ASSERT_TRUE(pPrimaryCam->getIntParameter(cmd, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(val0, v) << "Values are not matched.";
+ }
+ }
+
+ // Try to adjust a parameter via non-primary client
+ values.clear();
+ ASSERT_FALSE(pSecondaryCam->setIntParameter(camSecondaryCmds[0], val0, &values).isOk());
+
+ // Non-primary client attempts to be a primary client
+ ASSERT_FALSE(pSecondaryCam->setPrimaryClient().isOk());
+
+ // Primary client retires from a primary client role
+ bool listening = false;
+ std::condition_variable eventCond;
+ std::thread listener =
+ std::thread([&aNotification0, &frameHandlerSecondary, &listening, &eventCond]() {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification0, true)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ std::mutex eventLock;
+ auto timer = std::chrono::system_clock::now();
+ std::unique_lock<std::mutex> lock(eventLock);
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ ASSERT_TRUE(pPrimaryCam->unsetPrimaryClient().isOk());
+
+ if (listener.joinable()) {
+ listener.join();
+ }
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED, static_cast<EvsEventType>(aNotification0.aType));
+
+ // Try to adjust a parameter after being retired
+ values.clear();
+ ASSERT_FALSE(pPrimaryCam->setIntParameter(camPrimaryCmds[0], val0, &values).isOk());
+
+ // Non-primary client becomes a primary client
+ ASSERT_TRUE(pSecondaryCam->setPrimaryClient().isOk());
+
+ // Try to adjust a parameter via new primary client
+ for (auto& cmd : camSecondaryCmds) {
+ // Get a valid parameter value range
+ ParameterRange range;
+ ASSERT_TRUE(pSecondaryCam->getIntParameterRange(cmd, &range).isOk());
+
+ values.clear();
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ values.clear();
+ ASSERT_TRUE(
+ pSecondaryCam->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(v, 0);
+ }
+ }
+
+ // Calculate a parameter value to program. This is being rounding down.
+ val0 = range.min + (std::rand() % (range.max - range.min));
+ val0 = val0 - (val0 % range.step);
+
+ // Prepare and start event listeners.
+ bool listening0 = false;
+ bool listening1 = false;
+ std::condition_variable eventCond;
+ std::thread listener0 = std::thread([&]() {
+ listening0 = true;
+ if (listening1) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+ std::thread listener1 = std::thread([&]() {
+ listening1 = true;
+ if (listening0) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a listening thread starts.
+ std::mutex eventLock;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening0 || !listening1) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to program a parameter
+ values.clear();
+ ASSERT_TRUE(pSecondaryCam->setIntParameter(cmd, val0, &values).isOk());
+
+ // Clients expects to receive a parameter change notification
+ // whenever a primary client client adjusts it.
+ values.clear();
+ ASSERT_TRUE(pSecondaryCam->getIntParameter(cmd, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(val0, v) << "Values are not matched.";
+ }
+
+ // Join a listening thread.
+ if (listener0.joinable()) {
+ listener0.join();
+ }
+ if (listener1.joinable()) {
+ listener1.join();
+ }
+
+ // Verify a change notification
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification0.aType));
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification1.aType));
+ ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification0.payload[0]));
+ ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification1.payload[0]));
+ for (auto&& v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification0.payload[1]));
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification1.payload[1]));
+ }
+ }
+
+ // New primary client retires from the role
+ ASSERT_TRUE(pSecondaryCam->unsetPrimaryClient().isOk());
+
+ // Shutdown
+ frameHandlerPrimary->shutdown();
+ frameHandlerSecondary->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pPrimaryCam).isOk());
+ ASSERT_TRUE(mEnumerator->closeCamera(pSecondaryCam).isOk());
+ mActiveCameras.clear();
+ }
+}
+
+/*
+ * HighPriorityCameraClient:
+ * EVS client, which owns the display, is priortized and therefore can take over
+ * a primary client role from other EVS clients without the display.
+ */
+TEST_P(EvsAidlTest, HighPriorityCameraClient) {
+ LOG(INFO) << "Starting HighPriorityCameraClient test";
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request available display IDs
+ uint8_t targetDisplayId = 0;
+ std::vector<uint8_t> displayIds;
+ ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+ EXPECT_GT(displayIds.size(), 0);
+ targetDisplayId = displayIds[0];
+
+ // Request exclusive access to the EVS display
+ std::shared_ptr<IEvsDisplay> pDisplay;
+ ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+ EXPECT_NE(pDisplay, nullptr);
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ // Create two clients
+ std::shared_ptr<IEvsCamera> pCam0;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam0).isOk());
+ EXPECT_NE(pCam0, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam0);
+
+ std::shared_ptr<IEvsCamera> pCam1;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+ EXPECT_NE(pCam1, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam1);
+
+ // Get the parameter list; this test will use the first command in both
+ // lists.
+ std::vector<CameraParam> cam0Cmds, cam1Cmds;
+ ASSERT_TRUE(pCam0->getParameterList(&cam0Cmds).isOk());
+ ASSERT_TRUE(pCam1->getParameterList(&cam1Cmds).isOk());
+ if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) {
+ // Cannot execute this test.
+ return;
+ }
+
+ // Set up a frame receiver object which will fire up its own thread.
+ std::shared_ptr<FrameHandler> frameHandler0 =
+ std::make_shared<FrameHandler>(pCam0, cam, nullptr, FrameHandler::eAutoReturn);
+ std::shared_ptr<FrameHandler> frameHandler1 =
+ std::make_shared<FrameHandler>(pCam1, cam, nullptr, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandler0, nullptr);
+ EXPECT_NE(frameHandler1, nullptr);
+
+ // Activate the display
+ ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME).isOk());
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler0->startStream());
+ ASSERT_TRUE(frameHandler1->startStream());
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ // Client 1 becomes a primary client and programs a parameter.
+
+ // Get a valid parameter value range
+ ParameterRange range;
+ ASSERT_TRUE(pCam1->getIntParameterRange(cam1Cmds[0], &range).isOk());
+
+ // Client1 becomes a primary client
+ ASSERT_TRUE(pCam1->setPrimaryClient().isOk());
+
+ std::vector<int32_t> values;
+ EvsEventDesc aTargetEvent = {};
+ EvsEventDesc aNotification = {};
+ bool listening = false;
+ std::mutex eventLock;
+ std::condition_variable eventCond;
+ if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ std::thread listener =
+ std::thread([&frameHandler0, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+ aTargetEvent.payload[1] = 0;
+ if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a lister starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to turn off auto-focus
+ ASSERT_TRUE(pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(v, 0);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Make sure AUTO_FOCUS is off.
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal] after
+ // rounding it down.
+ int32_t val0 = range.min + (std::rand() % (range.max - range.min));
+ val0 = val0 - (val0 % range.step);
+
+ std::thread listener = std::thread(
+ [&frameHandler1, &aNotification, &listening, &eventCond, &cam1Cmds, val0] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a lister starts.
+ listening = false;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ values.clear();
+ ASSERT_TRUE(pCam1->setIntParameter(cam1Cmds[0], val0, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(val0, v);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify a change notification
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]), cam1Cmds[0]);
+ for (auto&& v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+ }
+
+ listener = std::thread([&frameHandler1, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a lister starts.
+ listening = false;
+ lock.lock();
+ timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Client 0 steals a primary client role
+ ASSERT_TRUE(pCam0->forcePrimaryClient(pDisplay).isOk());
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::MASTER_RELEASED);
+
+ // Client 0 programs a parameter
+ val0 = range.min + (std::rand() % (range.max - range.min));
+
+ // Rounding down
+ val0 = val0 - (val0 % range.step);
+
+ if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ std::thread listener =
+ std::thread([&frameHandler1, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+ aTargetEvent.payload[1] = 0;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a lister starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to turn off auto-focus
+ values.clear();
+ ASSERT_TRUE(pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0, &values).isOk());
+ for (auto&& v : values) {
+ EXPECT_EQ(v, 0);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Make sure AUTO_FOCUS is off.
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ }
+
+ listener = std::thread(
+ [&frameHandler0, &aNotification, &listening, &eventCond, &cam0Cmds, val0] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
+ }
+ });
+
+ // Wait until a lister starts.
+ listening = false;
+ timer = std::chrono::system_clock::now();
+ lock.lock();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ values.clear();
+ ASSERT_TRUE(pCam0->setIntParameter(cam0Cmds[0], val0, &values).isOk());
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+ // Verify a change notification
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]), cam0Cmds[0]);
+ for (auto&& v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+ }
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::NOT_VISIBLE).isOk());
+
+ // Shut down the streamer
+ frameHandler0->shutdown();
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
+ mActiveCameras.clear();
+ }
+
+ // Explicitly release the display
+ ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+}
+
+/*
+ * CameraUseStreamConfigToDisplay:
+ * End to end test of data flowing from the camera to the display. Similar to
+ * CameraToDisplayRoundTrip test case but this case retrieves available stream
+ * configurations from EVS and uses one of them to start a video stream.
+ */
+TEST_P(EvsAidlTest, CameraUseStreamConfigToDisplay) {
+ LOG(INFO) << "Starting CameraUseStreamConfigToDisplay test";
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request available display IDs
+ uint8_t targetDisplayId = 0;
+ std::vector<uint8_t> displayIds;
+ ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+ EXPECT_GT(displayIds.size(), 0);
+ targetDisplayId = displayIds[0];
+
+ // Request exclusive access to the EVS display
+ std::shared_ptr<IEvsDisplay> pDisplay;
+ ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+ EXPECT_NE(pDisplay, nullptr);
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
+ for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (ptr->width * ptr->height > maxArea && ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format = static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ // Current EVS camera does not provide stream configurations in the
+ // metadata.
+ continue;
+ }
+
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ EXPECT_NE(pCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam);
+
+ // Set up a frame receiver object which will fire up its own thread.
+ std::shared_ptr<FrameHandler> frameHandler =
+ std::make_shared<FrameHandler>(pCam, cam, pDisplay, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Activate the display
+ ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME).isOk());
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler->startStream());
+
+ // Wait a while to let the data flow
+ static const int kSecondsToWait = 5;
+ const int streamTimeMs =
+ kSecondsToWait * kSecondsToMilliseconds - kMaxStreamStartMilliseconds;
+ const unsigned minimumFramesExpected =
+ streamTimeMs * kMinimumFramesPerSecond / kSecondsToMilliseconds;
+ sleep(kSecondsToWait);
+ unsigned framesReceived = 0;
+ unsigned framesDisplayed = 0;
+ frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+ EXPECT_EQ(framesReceived, framesDisplayed);
+ EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ ASSERT_TRUE(pDisplay->setDisplayState(DisplayState::NOT_VISIBLE).isOk());
+
+ // Shut down the streamer
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.clear();
+ }
+
+ // Explicitly release the display
+ ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+}
+
+/*
+ * MultiCameraStreamUseConfig:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera with same configuration.
+ */
+TEST_P(EvsAidlTest, MultiCameraStreamUseConfig) {
+ LOG(INFO) << "Starting MultiCameraStream test";
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
+ for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (ptr->width * ptr->height > maxArea && ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format = static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ LOG(INFO) << "Device " << cam.id
+ << " does not provide a list of supported stream configurations, skipped";
+ continue;
+ }
+
+ // Create the first camera client with a selected stream configuration.
+ std::shared_ptr<IEvsCamera> pCam0;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam0).isOk());
+ EXPECT_NE(pCam0, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam0);
+
+ // Try to create the second camera client with different stream
+ // configuration.
+ int32_t id = targetCfg.id;
+ targetCfg.id += 1; // EVS manager sees only the stream id.
+ std::shared_ptr<IEvsCamera> pCam1;
+ ASSERT_FALSE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+
+ // Try again with same stream configuration.
+ targetCfg.id = id;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam1).isOk());
+ EXPECT_NE(pCam1, nullptr);
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ std::shared_ptr<FrameHandler> frameHandler0 =
+ std::make_shared<FrameHandler>(pCam0, cam, nullptr, FrameHandler::eAutoReturn);
+ std::shared_ptr<FrameHandler> frameHandler1 =
+ std::make_shared<FrameHandler>(pCam1, cam, nullptr, FrameHandler::eAutoReturn);
+ EXPECT_NE(frameHandler0, nullptr);
+ EXPECT_NE(frameHandler1, nullptr);
+
+ // Start the camera's video stream via client 0
+ ASSERT_TRUE(frameHandler0->startStream());
+ ASSERT_TRUE(frameHandler1->startStream());
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Wait a bit, then ensure both clients get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived0 = 0, framesReceived1 = 0;
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+ framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for
+ framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+ float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+ LOG(INFO) << "Measured camera rate " << std::scientific << framesPerSecond0 << " fps and "
+ << framesPerSecond1 << " fps";
+ EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+ EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+ // Shutdown one client
+ frameHandler0->shutdown();
+
+ // Read frame counters again
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+ // Wait a bit again
+ sleep(5);
+ unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+ frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+ EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+ EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+ // Shutdown another
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
+ mActiveCameras.clear();
+ }
+}
+
+/*
+ * LogicalCameraMetadata:
+ * Opens logical camera reported by the enumerator and validate its metadata by
+ * checking its capability and locating supporting physical camera device
+ * identifiers.
+ */
+TEST_P(EvsAidlTest, LogicalCameraMetadata) {
+ LOG(INFO) << "Starting LogicalCameraMetadata test";
+
+ // Get the camera list
+ loadCameraList();
+
+ // Open and close each camera twice
+ for (auto&& cam : mCameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.id, isLogicalCam);
+ if (isLogicalCam) {
+ ASSERT_GE(devices.size(), 1) << "Logical camera device must have at least one physical "
+ "camera device ID in its metadata.";
+ }
+ }
+}
+
+/*
+ * CameraStreamExternalBuffering:
+ * This is same with CameraStreamBuffering except frame buffers are allocated by
+ * the test client and then imported by EVS framework.
+ */
+TEST_P(EvsAidlTest, CameraStreamExternalBuffering) {
+ LOG(INFO) << "Starting CameraStreamExternalBuffering test";
+
+ // Arbitrary constant (should be > 1 and not too big)
+ static const unsigned int kBuffersToHold = 3;
+
+ // Get the camera list
+ loadCameraList();
+
+ // Acquire the graphics buffer allocator
+ android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
+ const auto usage =
+ GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+ // Test each reported camera
+ for (auto&& cam : mCameraInfo) {
+ // Read a target resolution from the metadata
+ Stream targetCfg = getFirstStreamConfiguration(
+ reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ // Allocate buffers to use
+ std::vector<BufferDesc> buffers;
+ buffers.resize(kBuffersToHold);
+ for (auto i = 0; i < kBuffersToHold; ++i) {
+ unsigned pixelsPerLine;
+ buffer_handle_t memHandle = nullptr;
+ android::status_t result =
+ alloc.allocate(targetCfg.width, targetCfg.height,
+ static_cast<android::PixelFormat>(targetCfg.format),
+ /* layerCount = */ 1, usage, &memHandle, &pixelsPerLine,
+ /* graphicBufferId = */ 0,
+ /* requestorName = */ "CameraStreamExternalBufferingTest");
+ if (result != android::NO_ERROR) {
+ LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
+ // Release previous allocated buffers
+ for (auto j = 0; j < i; j++) {
+ alloc.free(::android::dupFromAidl(buffers[i].buffer.handle));
+ }
+ return;
+ } else {
+ BufferDesc buf;
+ HardwareBufferDescription* pDesc =
+ reinterpret_cast<HardwareBufferDescription*>(&buf.buffer.description);
+ pDesc->width = targetCfg.width;
+ pDesc->height = targetCfg.height;
+ pDesc->layers = 1;
+ pDesc->format = targetCfg.format;
+ pDesc->usage = static_cast<BufferUsage>(usage);
+ pDesc->stride = pixelsPerLine;
+ buf.buffer.handle = ::android::dupToAidl(memHandle);
+ buf.bufferId = i; // Unique number to identify this buffer
+ buffers[i] = std::move(buf);
+ }
+ }
+
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.id, isLogicalCam);
+
+ std::shared_ptr<IEvsCamera> pCam;
+ ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
+ EXPECT_NE(pCam, nullptr);
+
+ // Store a camera handle for a clean-up
+ mActiveCameras.push_back(pCam);
+
+ // Request to import buffers
+ int delta = 0;
+ auto status = pCam->importExternalBuffers(buffers, &delta);
+ if (isLogicalCam) {
+ ASSERT_FALSE(status.isOk());
+ continue;
+ }
+
+ ASSERT_TRUE(status.isOk());
+ EXPECT_GE(delta, kBuffersToHold);
+
+ // Set up a frame receiver object which will fire up its own thread.
+ std::shared_ptr<FrameHandler> frameHandler =
+ std::make_shared<FrameHandler>(pCam, cam, nullptr, FrameHandler::eNoAutoReturn);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler->startStream());
+
+ // Check that the video stream stalls once we've gotten exactly the number of buffers
+ // we requested since we told the frameHandler not to return them.
+ sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case
+ unsigned framesReceived = 0;
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ ASSERT_LE(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+
+ // Give back one buffer
+ EXPECT_TRUE(frameHandler->returnHeldBuffer());
+
+ // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+ // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+ unsigned framesReceivedAfter = 0;
+ usleep(110 * kMillisecondsToMicroseconds);
+ frameHandler->getFramesCounters(&framesReceivedAfter, nullptr);
+ EXPECT_EQ(framesReceived + 1, framesReceivedAfter) << "Stream should've resumed";
+
+ // Even when the camera pointer goes out of scope, the FrameHandler object will
+ // keep the stream alive unless we tell it to shutdown.
+ // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+ // we have to break that cycle in order for either of them to get cleaned up.
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
+ mActiveCameras.clear();
+ // Release buffers
+ for (auto& b : buffers) {
+ alloc.free(::android::dupFromAidl(b.buffer.handle));
+ }
+ buffers.resize(0);
+ }
+}
+
+/*
+ * UltrasonicsArrayOpenClean:
+ * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a
+ * call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays
+ * can be reopened.
+ */
+TEST_P(EvsAidlTest, UltrasonicsArrayOpenClean) {
+ LOG(INFO) << "Starting UltrasonicsArrayOpenClean test";
+
+ // Get the ultrasonics array list
+ loadUltrasonicsArrayList();
+
+ // Open and close each ultrasonics array twice
+ for (auto&& ultraInfo : mUltrasonicsArraysInfo) {
+ for (int pass = 0; pass < 2; pass++) {
+ std::shared_ptr<IEvsUltrasonicsArray> pUltrasonicsArray;
+ ASSERT_TRUE(
+ mEnumerator
+ ->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId, &pUltrasonicsArray)
+ .isOk());
+ EXPECT_NE(pUltrasonicsArray, nullptr);
+
+ // Verify that this ultrasonics array self-identifies correctly
+ UltrasonicsArrayDesc desc;
+ ASSERT_TRUE(pUltrasonicsArray->getUltrasonicArrayInfo(&desc).isOk());
+ EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId);
+ LOG(DEBUG) << "Found ultrasonics array " << ultraInfo.ultrasonicsArrayId;
+
+ // Explicitly close the ultrasonics array so resources are released right away
+ ASSERT_TRUE(mEnumerator->closeUltrasonicsArray(pUltrasonicsArray).isOk());
+ }
+ }
+}
+
+// Starts a stream and verifies all data received is valid.
+TEST_P(EvsAidlTest, UltrasonicsVerifyStreamData) {
+ LOG(INFO) << "Starting UltrasonicsVerifyStreamData";
+
+ // Get the ultrasonics array list
+ loadUltrasonicsArrayList();
+
+ // For each ultrasonics array.
+ for (auto&& ultraInfo : mUltrasonicsArraysInfo) {
+ LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
+
+ std::shared_ptr<IEvsUltrasonicsArray> pUltrasonicsArray;
+ ASSERT_TRUE(
+ mEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId, &pUltrasonicsArray)
+ .isOk());
+ EXPECT_NE(pUltrasonicsArray, nullptr);
+
+ std::shared_ptr<FrameHandlerUltrasonics> frameHandler =
+ std::make_shared<FrameHandlerUltrasonics>(pUltrasonicsArray);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Start stream.
+ ASSERT_TRUE(pUltrasonicsArray->startStream(frameHandler).isOk());
+
+ // Wait 5 seconds to receive frames.
+ sleep(5);
+
+ // Stop stream.
+ ASSERT_TRUE(pUltrasonicsArray->stopStream().isOk());
+
+ EXPECT_GT(frameHandler->getReceiveFramesCount(), 0);
+ EXPECT_TRUE(frameHandler->areAllFramesValid());
+
+ // Explicitly close the ultrasonics array so resources are released right away
+ ASSERT_TRUE(mEnumerator->closeUltrasonicsArray(pUltrasonicsArray).isOk());
+ }
+}
+
+// Sets frames in flight before and after start of stream and verfies success.
+TEST_P(EvsAidlTest, UltrasonicsSetFramesInFlight) {
+ LOG(INFO) << "Starting UltrasonicsSetFramesInFlight";
+
+ // Get the ultrasonics array list
+ loadUltrasonicsArrayList();
+
+ // For each ultrasonics array.
+ for (auto&& ultraInfo : mUltrasonicsArraysInfo) {
+ LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
+
+ std::shared_ptr<IEvsUltrasonicsArray> pUltrasonicsArray;
+ ASSERT_TRUE(
+ mEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId, &pUltrasonicsArray)
+ .isOk());
+ EXPECT_NE(pUltrasonicsArray, nullptr);
+
+ ASSERT_TRUE(pUltrasonicsArray->setMaxFramesInFlight(10).isOk());
+
+ std::shared_ptr<FrameHandlerUltrasonics> frameHandler =
+ std::make_shared<FrameHandlerUltrasonics>(pUltrasonicsArray);
+ EXPECT_NE(frameHandler, nullptr);
+
+ // Start stream.
+ ASSERT_TRUE(pUltrasonicsArray->startStream(frameHandler).isOk());
+ ASSERT_TRUE(pUltrasonicsArray->setMaxFramesInFlight(5).isOk());
+
+ // Stop stream.
+ ASSERT_TRUE(pUltrasonicsArray->stopStream().isOk());
+
+ // Explicitly close the ultrasonics array so resources are released right away
+ ASSERT_TRUE(mEnumerator->closeUltrasonicsArray(pUltrasonicsArray).isOk());
+ }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EvsAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, EvsAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IEvsEnumerator::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
deleted file mode 100644
index 58daca6..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-syntax = "proto2";
-
-package vhal_proto;
-
-// CMD messages are from workstation --> VHAL
-// RESP messages are from VHAL --> workstation
-enum MsgType {
- GET_CONFIG_CMD = 0;
- GET_CONFIG_RESP = 1;
- GET_CONFIG_ALL_CMD = 2;
- GET_CONFIG_ALL_RESP = 3;
- GET_PROPERTY_CMD = 4;
- GET_PROPERTY_RESP = 5;
- GET_PROPERTY_ALL_CMD = 6;
- GET_PROPERTY_ALL_RESP = 7;
- SET_PROPERTY_CMD = 8;
- SET_PROPERTY_RESP = 9;
- SET_PROPERTY_ASYNC = 10;
- DEBUG_CMD = 11;
- DEBUG_RESP = 12;
-}
-enum Status {
- RESULT_OK = 0;
- ERROR_UNKNOWN = 1;
- ERROR_UNIMPLEMENTED_CMD = 2;
- ERROR_INVALID_PROPERTY = 3;
- ERROR_INVALID_AREA_ID = 4;
- ERROR_PROPERTY_UNINITIALIZED = 5;
- ERROR_WRITE_ONLY_PROPERTY = 6;
- ERROR_MEMORY_ALLOC_FAILED = 7;
- ERROR_INVALID_OPERATION = 8;
-}
-
-enum VehiclePropStatus {
- AVAILABLE = 0;
- UNAVAILABLE = 1;
- ERROR = 2;
-}
-
-message VehicleAreaConfig {
- required int32 area_id = 1;
- optional sint32 min_int32_value = 2;
- optional sint32 max_int32_value = 3;
- optional sint64 min_int64_value = 4;
- optional sint64 max_int64_value = 5;
- optional float min_float_value = 6;
- optional float max_float_value = 7;
-}
-
-message VehiclePropConfig {
- required int32 prop = 1;
- optional int32 access = 2;
- optional int32 change_mode = 3;
- optional int32 value_type = 4;
- optional int32 supported_areas = 5; // Deprecated - DO NOT USE
- repeated VehicleAreaConfig area_configs = 6;
- optional int32 config_flags = 7;
- repeated int32 config_array = 8;
- optional string config_string = 9;
- optional float min_sample_rate = 10;
- optional float max_sample_rate = 11;
-};
-
-message VehiclePropValue {
- // common data
- required int32 prop = 1;
- optional int32 value_type = 2;
- optional int64 timestamp = 3; // required for valid data from HAL, skipped for set
- optional VehiclePropStatus status = 10; // required for valid data from HAL, skipped for set
-
- // values
- optional int32 area_id = 4;
- repeated sint32 int32_values = 5; // this also covers boolean value.
- repeated sint64 int64_values = 6;
- repeated float float_values = 7;
- optional string string_value = 8;
- optional bytes bytes_value = 9;
-};
-
-// This structure is used to notify what values to get from the Vehicle HAL
-message VehiclePropGet {
- required int32 prop = 1;
- optional int32 area_id = 2;
-};
-
-message EmulatorMessage {
- required MsgType msg_type = 1;
- optional Status status = 2; // Only for RESP messages
- repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands
- repeated VehiclePropConfig config = 4;
- repeated VehiclePropValue value = 5;
- repeated string debug_commands = 6; // Required for debug command
- optional string debug_result = 7; // Required for debug RESP messages
-};
diff --git a/automotive/vehicle/OWNERS b/automotive/vehicle/OWNERS
new file mode 100644
index 0000000..429ec39
--- /dev/null
+++ b/automotive/vehicle/OWNERS
@@ -0,0 +1,3 @@
+ericjeong@google.com
+keunyoung@google.com
+shanyu@google.com
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index cab184b..578d045 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -23,7 +23,9 @@
#include <IVehicleHardware.h>
#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
+#include <android-base/parseint.h>
#include <android-base/result.h>
+#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <map>
@@ -37,7 +39,7 @@
namespace vehicle {
namespace fake {
-class FakeVehicleHardware final : public IVehicleHardware {
+class FakeVehicleHardware : public IVehicleHardware {
public:
FakeVehicleHardware();
@@ -78,13 +80,21 @@
void registerOnPropertySetErrorEvent(
std::unique_ptr<const PropertySetErrorCallback> callback) override;
+ protected:
+ // mValuePool is also used in mServerSidePropStore.
+ const std::shared_ptr<VehiclePropValuePool> mValuePool;
+ const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
+
+ ::android::base::Result<VehiclePropValuePool::RecyclableType> getValue(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+ ::android::base::Result<void> setValue(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+
private:
// Expose private methods to unit test.
friend class FakeVehicleHardwareTestHelper;
- // mValuePool is also used in mServerSidePropStore.
- const std::shared_ptr<VehiclePropValuePool> mValuePool;
- const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
const std::unique_ptr<FakeUserHal> mFakeUserHal;
std::mutex mCallbackLock;
@@ -120,6 +130,35 @@
::android::base::Result<VehiclePropValuePool::RecyclableType> getUserHalProp(
const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
bool isHvacPropAndHvacNotAvailable(int32_t propId);
+
+ std::string dumpAllProperties();
+ std::string dumpOnePropertyByConfig(
+ int rowNumber,
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config);
+ std::string dumpOnePropertyById(int32_t propId, int32_t areaId);
+ std::string dumpHelp();
+ std::string dumpListProperties();
+ std::string dumpSpecificProperty(const std::vector<std::string>& options);
+ std::string dumpSetProperties(const std::vector<std::string>& options);
+
+ template <typename T>
+ ::android::base::Result<T> safelyParseInt(int index, const std::string& s) {
+ T out;
+ if (!::android::base::ParseInt(s, &out)) {
+ return ::android::base::Error() << ::android::base::StringPrintf(
+ "non-integer argument at index %d: %s\n", index, s.c_str());
+ }
+ return out;
+ }
+ ::android::base::Result<float> safelyParseFloat(int index, const std::string& s);
+ std::vector<std::string> getOptionValues(const std::vector<std::string>& options,
+ size_t* index);
+ ::android::base::Result<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
+ parseSetPropOptions(const std::vector<std::string>& options);
+ ::android::base::Result<std::vector<uint8_t>> parseHexString(const std::string& s);
+
+ ::android::base::Result<void> checkArgumentsSize(const std::vector<std::string>& options,
+ size_t minSize);
};
} // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index e75f0e7..097257e 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#define LOG_TAG "FakeVehicleHardware"
+#define FAKE_VEHICLEHARDWARE_DEBUG false // STOPSHIP if true.
+
#include "FakeVehicleHardware.h"
#include <DefaultConfig.h>
@@ -22,7 +25,9 @@
#include <PropertyUtils.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
+#include <android-base/parsedouble.h>
#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
@@ -56,12 +61,31 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::EqualsIgnoreCase;
using ::android::base::Error;
+using ::android::base::ParseFloat;
using ::android::base::Result;
+using ::android::base::StartsWith;
+using ::android::base::StringPrintf;
const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";
+// A list of supported options for "--set" command.
+const std::unordered_set<std::string> SET_PROP_OPTIONS = {
+ // integer.
+ "-i",
+ // 64bit integer.
+ "-i64",
+ // float.
+ "-f",
+ // string.
+ "-s",
+ // bytes in hex format, e.g. 0xDEADBEEF.
+ "-b",
+ // Area id in integer.
+ "-a"};
+
} // namespace
void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
@@ -381,44 +405,26 @@
StatusCode FakeVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
const std::vector<SetValueRequest>& requests) {
- std::vector<VehiclePropValue> updatedValues;
std::vector<SetValueResult> results;
for (auto& request : requests) {
const VehiclePropValue& value = request.value;
int propId = value.prop;
- ALOGD("Set value for property ID: %d", propId);
+ if (FAKE_VEHICLEHARDWARE_DEBUG) {
+ ALOGD("Set value for property ID: %d", propId);
+ }
SetValueResult setValueResult;
setValueResult.requestId = request.requestId;
- setValueResult.status = StatusCode::OK;
- bool isSpecialValue = false;
- auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
-
- if (isSpecialValue) {
- if (!setSpecialValueResult.ok()) {
- ALOGE("failed to set special value for property ID: %d, error: %s, status: %d",
- propId, getErrorMsg(setSpecialValueResult).c_str(),
- getIntErrorCode(setSpecialValueResult));
- setValueResult.status = getErrorCode(setSpecialValueResult);
- }
-
- // Special values are already handled.
- results.push_back(std::move(setValueResult));
- continue;
+ if (auto result = setValue(value); !result.ok()) {
+ ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(),
+ getIntErrorCode(result));
+ setValueResult.status = getErrorCode(result);
+ } else {
+ setValueResult.status = StatusCode::OK;
}
- auto updatedValue = mValuePool->obtain(value);
- int64_t timestamp = elapsedRealtimeNano();
- updatedValue->timestamp = timestamp;
-
- auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
- if (!writeResult.ok()) {
- ALOGE("failed to write value into property store, error: %s, code: %d",
- getErrorMsg(writeResult).c_str(), getIntErrorCode(writeResult));
- setValueResult.status = getErrorCode(writeResult);
- }
results.push_back(std::move(setValueResult));
}
@@ -429,61 +435,378 @@
return StatusCode::OK;
}
+Result<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
+ bool isSpecialValue = false;
+ auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
+
+ if (isSpecialValue) {
+ if (!setSpecialValueResult.ok()) {
+ return Error(getIntErrorCode(setSpecialValueResult))
+ << StringPrintf("failed to set special value for property ID: %d, error: %s",
+ value.prop, getErrorMsg(setSpecialValueResult).c_str());
+ }
+ return {};
+ }
+
+ auto updatedValue = mValuePool->obtain(value);
+ int64_t timestamp = elapsedRealtimeNano();
+ updatedValue->timestamp = timestamp;
+
+ auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+ if (!writeResult.ok()) {
+ return Error(getIntErrorCode(writeResult))
+ << StringPrintf("failed to write value into property store, error: %s",
+ getErrorMsg(writeResult).c_str());
+ }
+
+ return {};
+}
+
StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
const std::vector<GetValueRequest>& requests) const {
std::vector<GetValueResult> results;
for (auto& request : requests) {
const VehiclePropValue& value = request.prop;
- ALOGD("getValues(%d)", value.prop);
+
+ if (FAKE_VEHICLEHARDWARE_DEBUG) {
+ ALOGD("getValues(%d)", value.prop);
+ }
GetValueResult getValueResult;
getValueResult.requestId = request.requestId;
- bool isSpecialValue = false;
- auto result = maybeGetSpecialValue(value, &isSpecialValue);
- if (isSpecialValue) {
- if (!result.ok()) {
- ALOGE("failed to get special value: %d, error: %s, code: %d", value.prop,
- getErrorMsg(result).c_str(), getIntErrorCode(result));
- getValueResult.status = getErrorCode(result);
- } else {
- getValueResult.status = StatusCode::OK;
- getValueResult.prop = *result.value();
- }
- results.push_back(std::move(getValueResult));
- continue;
- }
-
- auto readResult = mServerSidePropStore->readValue(value);
- if (!readResult.ok()) {
- StatusCode errorCode = getErrorCode(readResult);
- if (errorCode == StatusCode::NOT_AVAILABLE) {
- ALOGW("%s", "value has not been set yet");
- } else {
- ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(readResult).c_str(),
- toInt(errorCode));
- }
- getValueResult.status = errorCode;
+ auto result = getValue(value);
+ if (!result.ok()) {
+ ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(result).c_str(),
+ getIntErrorCode(result));
+ getValueResult.status = getErrorCode(result);
} else {
getValueResult.status = StatusCode::OK;
- getValueResult.prop = *readResult.value();
+ getValueResult.prop = *result.value();
}
results.push_back(std::move(getValueResult));
}
+ // In a real VHAL implementation, getValue would be async and we would call the callback after
+ // we actually received the values from vehicle bus. Here we are getting the result
+ // synchronously so we could call the callback here.
(*callback)(std::move(results));
return StatusCode::OK;
}
-DumpResult FakeVehicleHardware::dump(const std::vector<std::string>&) {
+Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::getValue(
+ const VehiclePropValue& value) const {
+ bool isSpecialValue = false;
+ auto result = maybeGetSpecialValue(value, &isSpecialValue);
+ if (isSpecialValue) {
+ if (!result.ok()) {
+ return Error(getIntErrorCode(result))
+ << StringPrintf("failed to get special value: %d, error: %s", value.prop,
+ getErrorMsg(result).c_str());
+ } else {
+ return std::move(result);
+ }
+ }
+
+ auto readResult = mServerSidePropStore->readValue(value);
+ if (!readResult.ok()) {
+ StatusCode errorCode = getErrorCode(readResult);
+ if (errorCode == StatusCode::NOT_AVAILABLE) {
+ return Error(toInt(errorCode)) << "value has not been set yet";
+ } else {
+ return Error(toInt(errorCode))
+ << "failed to get value, error: " << getErrorMsg(readResult);
+ }
+ }
+
+ return std::move(readResult);
+}
+
+DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
DumpResult result;
- // TODO(b/201830716): Implement this.
+ result.callerShouldDumpState = false;
+ if (options.size() == 0) {
+ // We only want caller to dump default state when there is no options.
+ result.callerShouldDumpState = true;
+ result.buffer = dumpAllProperties();
+ return result;
+ }
+ std::string option = options[0];
+ if (EqualsIgnoreCase(option, "--help")) {
+ result.buffer = dumpHelp();
+ return result;
+ } else if (EqualsIgnoreCase(option, "--list")) {
+ result.buffer = dumpListProperties();
+ } else if (EqualsIgnoreCase(option, "--get")) {
+ result.buffer = dumpSpecificProperty(options);
+ } else if (EqualsIgnoreCase(option, "--set")) {
+ result.buffer = dumpSetProperties(options);
+ } else {
+ result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
+ }
return result;
}
+std::string FakeVehicleHardware::dumpHelp() {
+ return "Usage: \n\n"
+ "[no args]: dumps (id and value) all supported properties \n"
+ "--help: shows this help\n"
+ "--list: lists the ids of all supported properties\n"
+ "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n"
+ "--set <PROP> [-i INT_VALUE [INT_VALUE ...]] [-i64 INT64_VALUE [INT64_VALUE ...]] "
+ "[-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
+ "[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. "
+ "Notice that the string, bytes and area value can be set just once, while the other can"
+ " have multiple values (so they're used in the respective array), "
+ "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n";
+}
+
+std::string FakeVehicleHardware::dumpAllProperties() {
+ auto configs = mServerSidePropStore->getAllConfigs();
+ if (configs.size() == 0) {
+ return "no properties to dump\n";
+ }
+ std::string msg = StringPrintf("dumping %zu properties\n", configs.size());
+ int rowNumber = 1;
+ for (const VehiclePropConfig& config : configs) {
+ msg += dumpOnePropertyByConfig(rowNumber++, config);
+ }
+ return msg;
+}
+
+std::string FakeVehicleHardware::dumpOnePropertyByConfig(int rowNumber,
+ const VehiclePropConfig& config) {
+ size_t numberAreas = config.areaConfigs.size();
+ std::string msg = "";
+ if (numberAreas == 0) {
+ msg += StringPrintf("%d: ", rowNumber);
+ msg += dumpOnePropertyById(config.prop, /* areaId= */ 0);
+ return msg;
+ }
+ for (size_t j = 0; j < numberAreas; ++j) {
+ if (numberAreas > 1) {
+ msg += StringPrintf("%d-%zu: ", rowNumber, j);
+ } else {
+ msg += StringPrintf("%d: ", rowNumber);
+ }
+ msg += dumpOnePropertyById(config.prop, config.areaConfigs[j].areaId);
+ }
+ return msg;
+}
+
+std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
+ VehiclePropValue value = {
+ .prop = propId,
+ .areaId = areaId,
+ };
+ bool isSpecialValue = false;
+ auto result = maybeGetSpecialValue(value, &isSpecialValue);
+ if (!isSpecialValue) {
+ result = mServerSidePropStore->readValue(value);
+ }
+ if (!result.ok()) {
+ return StringPrintf("failed to read property value: %d, error: %s, code: %d\n", propId,
+ getErrorMsg(result).c_str(), getIntErrorCode(result));
+
+ } else {
+ return result.value()->toString() + "\n";
+ }
+}
+
+std::string FakeVehicleHardware::dumpListProperties() {
+ auto configs = mServerSidePropStore->getAllConfigs();
+ if (configs.size() == 0) {
+ return "no properties to list\n";
+ }
+ int rowNumber = 1;
+ std::string msg = StringPrintf("listing %zu properties\n", configs.size());
+ for (const auto& config : configs) {
+ msg += StringPrintf("%d: %d\n", rowNumber++, config.prop);
+ }
+ return msg;
+}
+
+Result<void> FakeVehicleHardware::checkArgumentsSize(const std::vector<std::string>& options,
+ size_t minSize) {
+ size_t size = options.size();
+ if (size >= minSize) {
+ return {};
+ }
+ return Error() << StringPrintf("Invalid number of arguments: required at least %zu, got %zu\n",
+ minSize, size);
+}
+
+std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
+ if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
+ return getErrorMsg(result);
+ }
+
+ // options[0] is the command itself...
+ int rowNumber = 1;
+ size_t size = options.size();
+ std::string msg = "";
+ for (size_t i = 1; i < size; ++i) {
+ auto propResult = safelyParseInt<int32_t>(i, options[i]);
+ if (!propResult.ok()) {
+ msg += getErrorMsg(propResult);
+ continue;
+ }
+ int32_t prop = propResult.value();
+ auto result = mServerSidePropStore->getConfig(prop);
+ if (!result.ok()) {
+ msg += StringPrintf("No property %d\n", prop);
+ continue;
+ }
+ msg += dumpOnePropertyByConfig(rowNumber++, *result.value());
+ }
+ return msg;
+}
+
+std::vector<std::string> FakeVehicleHardware::getOptionValues(
+ const std::vector<std::string>& options, size_t* index) {
+ std::vector<std::string> values;
+ while (*index < options.size()) {
+ std::string option = options[*index];
+ if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
+ return std::move(values);
+ }
+ values.push_back(option);
+ (*index)++;
+ }
+ return std::move(values);
+}
+
+Result<VehiclePropValue> FakeVehicleHardware::parseSetPropOptions(
+ const std::vector<std::string>& options) {
+ // Options format:
+ // --set PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...] [-b b1 b2...] [-a a]
+ size_t optionIndex = 1;
+ auto result = safelyParseInt<int32_t>(optionIndex, options[optionIndex]);
+ if (!result.ok()) {
+ return Error() << StringPrintf("Property value: \"%s\" is not a valid int: %s\n",
+ options[optionIndex].c_str(), getErrorMsg(result).c_str());
+ }
+ VehiclePropValue prop = {};
+ prop.prop = result.value();
+ prop.status = VehiclePropertyStatus::AVAILABLE;
+ optionIndex++;
+ std::unordered_set<std::string> parsedOptions;
+
+ while (optionIndex < options.size()) {
+ std::string type = options[optionIndex];
+ optionIndex++;
+ size_t currentIndex = optionIndex;
+ std::vector<std::string> values = getOptionValues(options, &optionIndex);
+ if (parsedOptions.find(type) != parsedOptions.end()) {
+ return Error() << StringPrintf("Duplicate \"%s\" options\n", type.c_str());
+ }
+ parsedOptions.insert(type);
+ if (EqualsIgnoreCase(type, "-i")) {
+ if (values.size() == 0) {
+ return Error() << "No values specified when using \"-i\"\n";
+ }
+ prop.value.int32Values.resize(values.size());
+ for (size_t i = 0; i < values.size(); i++) {
+ auto int32Result = safelyParseInt<int32_t>(currentIndex + i, values[i]);
+ if (!int32Result.ok()) {
+ return Error()
+ << StringPrintf("Value: \"%s\" is not a valid int: %s\n",
+ values[i].c_str(), getErrorMsg(int32Result).c_str());
+ }
+ prop.value.int32Values[i] = int32Result.value();
+ }
+ } else if (EqualsIgnoreCase(type, "-i64")) {
+ if (values.size() == 0) {
+ return Error() << "No values specified when using \"-i64\"\n";
+ }
+ prop.value.int64Values.resize(values.size());
+ for (size_t i = 0; i < values.size(); i++) {
+ auto int64Result = safelyParseInt<int64_t>(currentIndex + i, values[i]);
+ if (!int64Result.ok()) {
+ return Error()
+ << StringPrintf("Value: \"%s\" is not a valid int64: %s\n",
+ values[i].c_str(), getErrorMsg(int64Result).c_str());
+ }
+ prop.value.int64Values[i] = int64Result.value();
+ }
+ } else if (EqualsIgnoreCase(type, "-f")) {
+ if (values.size() == 0) {
+ return Error() << "No values specified when using \"-f\"\n";
+ }
+ prop.value.floatValues.resize(values.size());
+ for (size_t i = 0; i < values.size(); i++) {
+ auto floatResult = safelyParseFloat(currentIndex + i, values[i]);
+ if (!floatResult.ok()) {
+ return Error()
+ << StringPrintf("Value: \"%s\" is not a valid float: %s\n",
+ values[i].c_str(), getErrorMsg(floatResult).c_str());
+ }
+ prop.value.floatValues[i] = floatResult.value();
+ }
+ } else if (EqualsIgnoreCase(type, "-s")) {
+ if (values.size() != 1) {
+ return Error() << "Expect exact one value when using \"-s\"\n";
+ }
+ prop.value.stringValue = values[0];
+ } else if (EqualsIgnoreCase(type, "-b")) {
+ if (values.size() != 1) {
+ return Error() << "Expect exact one value when using \"-b\"\n";
+ }
+ auto bytesResult = parseHexString(values[0]);
+ if (!bytesResult.ok()) {
+ return Error() << StringPrintf("value: \"%s\" is not a valid hex string: %s\n",
+ values[0].c_str(), getErrorMsg(bytesResult).c_str());
+ }
+ prop.value.byteValues = std::move(bytesResult.value());
+ } else if (EqualsIgnoreCase(type, "-a")) {
+ if (values.size() != 1) {
+ return Error() << "Expect exact one value when using \"-a\"\n";
+ }
+ auto int32Result = safelyParseInt<int32_t>(currentIndex, values[0]);
+ if (!int32Result.ok()) {
+ return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n",
+ values[0].c_str(), getErrorMsg(int32Result).c_str());
+ }
+ prop.areaId = int32Result.value();
+ } else {
+ return Error() << StringPrintf("Unknown option: %s\n", type.c_str());
+ }
+ }
+
+ return prop;
+}
+
+std::string FakeVehicleHardware::dumpSetProperties(const std::vector<std::string>& options) {
+ if (auto result = checkArgumentsSize(options, 3); !result.ok()) {
+ return getErrorMsg(result);
+ }
+
+ auto parseResult = parseSetPropOptions(options);
+ if (!parseResult.ok()) {
+ return getErrorMsg(parseResult);
+ }
+ VehiclePropValue prop = std::move(parseResult.value());
+ ALOGD("Dump: Setting property: %s", prop.toString().c_str());
+
+ bool isSpecialValue = false;
+ auto setResult = maybeSetSpecialValue(prop, &isSpecialValue);
+
+ if (!isSpecialValue) {
+ auto updatedValue = mValuePool->obtain(prop);
+ updatedValue->timestamp = elapsedRealtimeNano();
+ setResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+ }
+
+ if (setResult.ok()) {
+ return StringPrintf("Set property: %s\n", prop.toString().c_str());
+ }
+ return StringPrintf("failed to set property: %s, error: %s\n", prop.toString().c_str(),
+ getErrorMsg(setResult).c_str());
+}
+
StatusCode FakeVehicleHardware::checkHealth() {
- // TODO(b/201830716): Implement this.
+ // Always return OK for checkHealth.
return StatusCode::OK;
}
@@ -544,6 +867,49 @@
}
}
+Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
+ float out;
+ if (!ParseFloat(s, &out)) {
+ return Error() << StringPrintf("non-float argument at index %d: %s\n", index, s.c_str());
+ }
+ return out;
+}
+
+Result<std::vector<uint8_t>> FakeVehicleHardware::parseHexString(const std::string& s) {
+ std::vector<uint8_t> bytes;
+ if (s.size() % 2 != 0) {
+ return Error() << StringPrintf("invalid hex string: %s, should have even size\n",
+ s.c_str());
+ }
+ if (!StartsWith(s, "0x")) {
+ return Error() << StringPrintf("hex string should start with \"0x\", got %s\n", s.c_str());
+ }
+ std::string subs = s.substr(2);
+ std::transform(subs.begin(), subs.end(), subs.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+
+ bool highDigit = true;
+ for (size_t i = 0; i < subs.size(); i++) {
+ char c = subs[i];
+ uint8_t v;
+ if (c >= '0' && c <= '9') {
+ v = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ v = c - 'a' + 10;
+ } else {
+ return Error() << StringPrintf("invalid character %c in hex string %s\n", c,
+ subs.c_str());
+ }
+ if (highDigit) {
+ bytes.push_back(v * 16);
+ } else {
+ bytes[bytes.size() - 1] += v;
+ }
+ highDigit = !highDigit;
+ }
+ return bytes;
+}
+
} // namespace fake
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 970d044..0812c2a 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -24,6 +24,7 @@
#include <android-base/expected.h>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utils/Log.h>
@@ -52,13 +53,16 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::base::expected;
+using ::android::base::StringPrintf;
using ::android::base::unexpected;
using ::testing::ContainerEq;
+using ::testing::ContainsRegex;
using ::testing::Eq;
using ::testing::IsSubsetOf;
using ::testing::WhenSortedBy;
constexpr int INVALID_PROP_ID = 0;
+constexpr char CAR_MAKE[] = "Default Car";
} // namespace
@@ -1203,6 +1207,261 @@
}));
}
+TEST_F(FakeVehicleHardwareTest, testDumpAllProperties) {
+ std::vector<std::string> options;
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_TRUE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex("dumping .+ properties"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpHelp) {
+ std::vector<std::string> options;
+ options.push_back("--help");
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex("Usage: "));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpListProperties) {
+ std::vector<std::string> options;
+ options.push_back("--list");
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex("listing .+ properties"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificProperties) {
+ std::vector<std::string> options;
+ options.push_back("--get");
+ std::string prop1 = std::to_string(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+ std::string prop2 = std::to_string(toInt(VehicleProperty::TIRE_PRESSURE));
+ options.push_back(prop1);
+ options.push_back(prop2);
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer,
+ ContainsRegex(StringPrintf("1:.*prop: %s.*\n2-0:.*prop: %s.*\n2-1:.*prop: %s.*\n",
+ prop1.c_str(), prop2.c_str(), prop2.c_str())));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesInvalidProp) {
+ std::vector<std::string> options;
+ options.push_back("--get");
+ std::string prop1 = std::to_string(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+ std::string prop2 = std::to_string(INVALID_PROP_ID);
+ options.push_back(prop1);
+ options.push_back(prop2);
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex(StringPrintf("1:.*prop: %s.*\nNo property %d\n",
+ prop1.c_str(), INVALID_PROP_ID)));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesNoArg) {
+ std::vector<std::string> options;
+ options.push_back("--get");
+
+ // No arguments.
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex("Invalid number of arguments"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpInvalidOptions) {
+ std::vector<std::string> options;
+ options.push_back("--invalid");
+
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
+}
+
+struct SetPropTestCase {
+ std::string test_name;
+ std::vector<std::string> options;
+ bool success;
+ std::string errorMsg = "";
+};
+
+class FakeVehicleHardwareSetPropTest : public FakeVehicleHardwareTest,
+ public testing::WithParamInterface<SetPropTestCase> {};
+
+TEST_P(FakeVehicleHardwareSetPropTest, cmdSetOneProperty) {
+ const SetPropTestCase& tc = GetParam();
+
+ DumpResult result = getHardware()->dump(tc.options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ if (tc.success) {
+ ASSERT_THAT(result.buffer, ContainsRegex("Set property:"));
+ } else {
+ ASSERT_THAT(result.buffer, ContainsRegex(tc.errorMsg));
+ }
+}
+
+std::vector<SetPropTestCase> GenSetPropParams() {
+ std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
+ return {
+ {"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, true},
+ {"success_set_bytes", {"--set", infoMakeProperty, "-b", "0xdeadbeef"}, true},
+ {"success_set_bytes_caps", {"--set", infoMakeProperty, "-b", "0xDEADBEEF"}, true},
+ {"success_set_int", {"--set", infoMakeProperty, "-i", "2147483647"}, true},
+ {"success_set_ints",
+ {"--set", infoMakeProperty, "-i", "2147483647", "0", "-2147483648"},
+ true},
+ {"success_set_int64",
+ {"--set", infoMakeProperty, "-i64", "-9223372036854775808"},
+ true},
+ {"success_set_int64s",
+ {"--set", infoMakeProperty, "-i64", "-9223372036854775808", "0",
+ "9223372036854775807"},
+ true},
+ {"success_set_float", {"--set", infoMakeProperty, "-f", "1.175494351E-38"}, true},
+ {"success_set_floats",
+ {"--set", infoMakeProperty, "-f", "-3.402823466E+38", "0", "3.402823466E+38"},
+ true},
+ {"success_set_area", {"--set", infoMakeProperty, "-a", "2147483647"}, true},
+ {"fail_no_options", {"--set", infoMakeProperty}, false, "Invalid number of arguments"},
+ {"fail_less_than_4_options",
+ {"--set", infoMakeProperty, "-i"},
+ false,
+ "No values specified"},
+ {"fail_unknown_options", {"--set", infoMakeProperty, "-abcd"}, false, "Unknown option"},
+ {"fail_invalid_property",
+ {"--set", "not valid", "-s", CAR_MAKE},
+ false,
+ "not a valid int"},
+ {"fail_duplicate_string",
+ {"--set", infoMakeProperty, "-s", CAR_MAKE, "-s", CAR_MAKE},
+ false,
+ "Duplicate \"-s\" options"},
+ {"fail_multiple_strings",
+ {"--set", infoMakeProperty, "-s", CAR_MAKE, CAR_MAKE},
+ false,
+ "Expect exact one value"},
+ {"fail_no_string_value",
+ {"--set", infoMakeProperty, "-s", "-a", "1234"},
+ false,
+ "Expect exact one value"},
+ {"fail_duplicate_bytes",
+ {"--set", infoMakeProperty, "-b", "0xdeadbeef", "-b", "0xdeadbeef"},
+ false,
+ "Duplicate \"-b\" options"},
+ {"fail_multiple_bytes",
+ {"--set", infoMakeProperty, "-b", "0xdeadbeef", "0xdeadbeef"},
+ false,
+ "Expect exact one value"},
+ {"fail_invalid_bytes",
+ {"--set", infoMakeProperty, "-b", "0xgood"},
+ false,
+ "not a valid hex string"},
+ {"fail_invalid_bytes_no_prefix",
+ {"--set", infoMakeProperty, "-b", "deadbeef"},
+ false,
+ "not a valid hex string"},
+ {"fail_invalid_int",
+ {"--set", infoMakeProperty, "-i", "abc"},
+ false,
+ "not a valid int"},
+ {"fail_int_out_of_range",
+ {"--set", infoMakeProperty, "-i", "2147483648"},
+ false,
+ "not a valid int"},
+ {"fail_no_int_value",
+ {"--set", infoMakeProperty, "-i", "-s", CAR_MAKE},
+ false,
+ "No values specified"},
+ {"fail_invalid_int64",
+ {"--set", infoMakeProperty, "-i64", "abc"},
+ false,
+ "not a valid int64"},
+ {"fail_int64_out_of_range",
+ {"--set", infoMakeProperty, "-i64", "-9223372036854775809"},
+ false,
+ "not a valid int64"},
+ {"fail_no_int64_value",
+ {"--set", infoMakeProperty, "-i64", "-s", CAR_MAKE},
+ false,
+ "No values specified"},
+ {"fail_invalid_float",
+ {"--set", infoMakeProperty, "-f", "abc"},
+ false,
+ "not a valid float"},
+ {"fail_float_out_of_range",
+ {"--set", infoMakeProperty, "-f", "-3.402823466E+39"},
+ false,
+ "not a valid float"},
+ {"fail_no_float_value",
+ {"--set", infoMakeProperty, "-f", "-s", CAR_MAKE},
+ false,
+ "No values specified"},
+ {"fail_multiple_areas",
+ {"--set", infoMakeProperty, "-a", "2147483648", "0"},
+ false,
+ "Expect exact one value"},
+ {"fail_invalid_area",
+ {"--set", infoMakeProperty, "-a", "abc"},
+ false,
+ "not a valid int"},
+ {"fail_area_out_of_range",
+ {"--set", infoMakeProperty, "-a", "2147483648"},
+ false,
+ "not a valid int"},
+ {"fail_no_area_value",
+ {"--set", infoMakeProperty, "-a", "-s", CAR_MAKE},
+ false,
+ "Expect exact one value"},
+ };
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ FakeVehicleHardwareSetPropTests, FakeVehicleHardwareSetPropTest,
+ testing::ValuesIn(GenSetPropParams()),
+ [](const testing::TestParamInfo<FakeVehicleHardwareSetPropTest::ParamType>& info) {
+ return info.param.test_name;
+ });
+
+TEST_F(FakeVehicleHardwareTest, SetComplexPropTest) {
+ std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
+ getHardware()->dump({"--set", infoMakeProperty, "-s", CAR_MAKE,
+ "-b", "0xdeadbeef", "-i", "2147483647",
+ "0", "-2147483648", "-i64", "-9223372036854775808",
+ "0", "9223372036854775807", "-f", "-3.402823466E+38",
+ "0", "3.402823466E+38", "-a", "123"});
+ VehiclePropValue requestProp;
+ requestProp.prop = toInt(VehicleProperty::INFO_MAKE);
+ requestProp.areaId = 123;
+ auto result = getValue(requestProp);
+ ASSERT_TRUE(result.ok());
+ VehiclePropValue value = result.value();
+ ASSERT_EQ(value.prop, toInt(VehicleProperty::INFO_MAKE));
+ ASSERT_EQ(value.areaId, 123);
+ ASSERT_STREQ(CAR_MAKE, value.value.stringValue.c_str());
+ uint8_t bytes[] = {0xde, 0xad, 0xbe, 0xef};
+ ASSERT_FALSE(memcmp(bytes, value.value.byteValues.data(), sizeof(bytes)));
+ ASSERT_EQ(3u, value.value.int32Values.size());
+ ASSERT_EQ(2147483647, value.value.int32Values[0]);
+ ASSERT_EQ(0, value.value.int32Values[1]);
+ ASSERT_EQ(-2147483648, value.value.int32Values[2]);
+ ASSERT_EQ(3u, value.value.int64Values.size());
+ // -9223372036854775808 is not a valid literal since '-' and '9223372036854775808' would be two
+ // tokens and the later does not fit in unsigned long long.
+ ASSERT_EQ(-9223372036854775807 - 1, value.value.int64Values[0]);
+ ASSERT_EQ(0, value.value.int64Values[1]);
+ ASSERT_EQ(9223372036854775807, value.value.int64Values[2]);
+ ASSERT_EQ(3u, value.value.floatValues.size());
+ ASSERT_EQ(-3.402823466E+38f, value.value.floatValues[0]);
+ ASSERT_EQ(0.0f, value.value.floatValues[1]);
+ ASSERT_EQ(3.402823466E+38f, value.value.floatValues[2]);
+}
+
} // namespace fake
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 013d177..a7fcdcf 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -37,6 +37,7 @@
#include <aidl/android/hardware/automotive/vehicle/SetValueResult.h>
#include <aidl/android/hardware/automotive/vehicle/SetValueResults.h>
#include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
+#include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReport.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleArea.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 49b33d5..0f0ccf1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -67,24 +67,30 @@
}
inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
- const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
+ int32_t propId, int32_t areaId,
const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
if (config.areaConfigs.size() == 0) {
return nullptr;
}
- if (isGlobalProp(propValue.prop)) {
+ if (isGlobalProp(propId)) {
return &(config.areaConfigs[0]);
}
for (const auto& c : config.areaConfigs) {
- if (c.areaId == propValue.areaId) {
+ if (c.areaId == areaId) {
return &c;
}
}
return nullptr;
}
+inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
+ return getAreaConfig(propValue.prop, propValue.areaId, config);
+}
+
inline std::unique_ptr<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
createVehiclePropValueVec(::aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,
size_t vecSize) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 1a79230..c1fa896 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -21,9 +21,11 @@
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
-#include <android-base/format.h>
+#include <android-base/stringprintf.h>
#include <math/HashCombine.h>
+#include <inttypes.h>
+
namespace android {
namespace hardware {
namespace automotive {
@@ -36,13 +38,14 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::base::Error;
using ::android::base::Result;
+using ::android::base::StringPrintf;
bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
return area == other.area && token == other.token;
}
std::string VehiclePropertyStore::RecordId::toString() const {
- return ::fmt::format("RecordID{{.areaId={:d}, .token={:d}}}", area, token);
+ return StringPrintf("RecordID{{.areaId=% " PRId32 ", .token=%" PRId64 "}", area, token);
}
size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId) const {
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index a54ab4b..0132e6f 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -57,6 +57,8 @@
"src/ConnectedClient.cpp",
"src/DefaultVehicleHal.cpp",
"src/PendingRequestPool.cpp",
+ "src/RecurrentTimer.cpp",
+ "src/SubscriptionManager.cpp",
],
static_libs: [
"VehicleHalUtils",
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 43a9603..15a6278 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -17,6 +17,9 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_
#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_
+#include "PendingRequestPool.h"
+
+#include <IVehicleHardware.h>
#include <VehicleHalTypes.h>
#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
@@ -39,15 +42,33 @@
// This class is thread-safe.
class ConnectedClient {
public:
- ConnectedClient(
- std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
- callback);
+ using CallbackType =
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+
+ ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
virtual ~ConnectedClient() = default;
+ // Gets the unique ID for this client.
+ const void* id();
+
+ // Adds client requests. The requests would be registered as pending requests until
+ // {@code tryFinishRequests} is called for them.
+ // Returns {@code INVALID_ARG} error if any of the requestIds are duplicate with one of the
+ // pending request IDs or {@code TRY_AGAIN} error if the pending request pool is full and could
+ // no longer add requests.
+ ::android::base::Result<void> addRequests(const std::unordered_set<int64_t>& requestIds);
+
+ // Marks the requests as finished. Returns a list of request IDs that was pending and has been
+ // finished. It must be a set of the requested request IDs.
+ std::unordered_set<int64_t> tryFinishRequests(const std::unordered_set<int64_t>& requestIds);
+
protected:
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
- mCallback;
+ // Gets the callback to be called when the request for this client has timeout.
+ virtual std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() = 0;
+
+ const std::shared_ptr<PendingRequestPool> mRequestPool;
+ const CallbackType mCallback;
};
// A class to represent a client that calls {@code IVehicle.setValues} or {@code
@@ -55,12 +76,10 @@
template <class ResultType, class ResultsType>
class GetSetValuesClient final : public ConnectedClient {
public:
- GetSetValuesClient(
- std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
- callback);
+ GetSetValuesClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
// Sends the results to this client.
- void sendResults(const std::vector<ResultType>& results);
+ void sendResults(std::vector<ResultType>&& results);
// Sends each result separately to this client. Each result would be sent through one callback
// invocation.
@@ -69,11 +88,47 @@
// Gets the callback to be called when the request for this client has finished.
std::shared_ptr<const std::function<void(std::vector<ResultType>)>> getResultCallback();
+ protected:
+ // Gets the callback to be called when the request for this client has timeout.
+ std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override;
+
private:
// The following members are only initialized during construction.
+ std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback;
std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback;
};
+// A class to represent a client that calls {@code IVehicle.subscribe}.
+class SubscriptionClient final : public ConnectedClient {
+ public:
+ SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
+
+ // Gets the callback to be called when the request for this client has finished.
+ std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
+
+ // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
+ // callback.
+ static void sendUpdatedValues(
+ CallbackType callback,
+ std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
+ updatedValues);
+
+ protected:
+ // Gets the callback to be called when the request for this client has timeout.
+ std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override;
+
+ private:
+ // The following members are only initialized during construction.
+ std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback;
+ std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback;
+ std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback;
+
+ static void onGetValueResults(
+ const void* clientId, CallbackType callback,
+ std::shared_ptr<PendingRequestPool> requestPool,
+ std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult> results);
+};
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index f6f7d80..5e7adfc 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -19,6 +19,8 @@
#include "ConnectedClient.h"
#include "ParcelableUtils.h"
+#include "PendingRequestPool.h"
+#include "SubscriptionManager.h"
#include <IVehicleHardware.h>
#include <VehicleUtils.h>
@@ -28,6 +30,7 @@
#include <android/binder_auto_utils.h>
#include <memory>
+#include <mutex>
#include <unordered_map>
#include <vector>
@@ -36,13 +39,6 @@
namespace automotive {
namespace vehicle {
-// private namespace
-namespace defaultvehiclehal_impl {
-
-constexpr int INVALID_MEMORY_FD = -1;
-
-} // namespace defaultvehiclehal_impl
-
class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::vehicle::BnVehicle {
public:
using CallbackType =
@@ -50,6 +46,8 @@
explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
+ ~DefaultVehicleHal();
+
::ndk::ScopedAStatus getAllPropConfigs(
::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
override;
@@ -74,6 +72,7 @@
const std::vector<int32_t>& propIds) override;
::ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
int64_t sharedMemoryId) override;
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
IVehicleHardware* getHardware();
@@ -88,11 +87,68 @@
GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::SetValueResult,
::aidl::android::hardware::automotive::vehicle::SetValueResults>;
+ // A thread safe class to maintain an increasing request ID for each subscribe client. This
+ // class is safe to pass to async callbacks.
+ class SubscribeIdByClient {
+ public:
+ int64_t getId(const CallbackType& callback);
+
+ private:
+ std::mutex mLock;
+ std::unordered_map<const AIBinder*, int64_t> mIds GUARDED_BY(mLock);
+ };
+
+ // A thread safe class to store all subscribe clients. This class is safe to pass to async
+ // callbacks.
+ class SubscriptionClients {
+ public:
+ SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {}
+
+ std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback);
+
+ void removeClient(const AIBinder* clientId);
+
+ size_t countClients();
+
+ private:
+ std::mutex mLock;
+ std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>> mClients
+ GUARDED_BY(mLock);
+ // PendingRequestPool is thread-safe.
+ std::shared_ptr<PendingRequestPool> mPendingRequestPool;
+ };
+
+ // A wrapper for linkToDeath to enable stubbing for test.
+ class ILinkToDeath {
+ public:
+ virtual ~ILinkToDeath() = default;
+
+ virtual binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+ void* cookie) = 0;
+ };
+
+ // A real implementation for ILinkToDeath.
+ class AIBinderLinkToDeathImpl final : public ILinkToDeath {
+ public:
+ binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+ void* cookie) override;
+ };
+
+ // OnBinderDiedContext is a type used as a cookie passed deathRecipient. The deathRecipient's
+ // onBinderDied function takes only a cookie as input and we have to store all the contexts
+ // as the cookie.
+ struct OnBinderDiedContext {
+ DefaultVehicleHal* vhal;
+ const AIBinder* clientId;
+ };
+
// The default timeout of get or set value requests is 30s.
// TODO(b/214605968): define TIMEOUT_IN_NANO in IVehicle and allow getValues/setValues/subscribe
// to specify custom timeouts.
static constexpr int64_t TIMEOUT_IN_NANO = 30'000'000'000;
- const std::unique_ptr<IVehicleHardware> mVehicleHardware;
+ // heart beat event interval: 3s
+ static constexpr int64_t HEART_BEAT_INTERVAL_IN_NANO = 3'000'000'000;
+ const std::shared_ptr<IVehicleHardware> mVehicleHardware;
// mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
// lock guard them.
@@ -100,20 +156,90 @@
mConfigsByPropId;
// Only modified in constructor, so thread-safe.
std::unique_ptr<::ndk::ScopedFileDescriptor> mConfigFile;
+ // PendingRequestPool is thread-safe.
+ std::shared_ptr<PendingRequestPool> mPendingRequestPool;
+ // SubscriptionManager is thread-safe.
+ std::shared_ptr<SubscriptionManager> mSubscriptionManager;
std::mutex mLock;
- std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>> mGetValuesClients
+ std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
GUARDED_BY(mLock);
- std::unordered_map<CallbackType, std::shared_ptr<SetValuesClient>> mSetValuesClients
+ std::unordered_map<const AIBinder*, std::shared_ptr<GetValuesClient>> mGetValuesClients
GUARDED_BY(mLock);
+ std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>> mSetValuesClients
+ GUARDED_BY(mLock);
+ // SubscriptionClients is thread-safe.
+ std::shared_ptr<SubscriptionClients> mSubscriptionClients;
+ // mLinkToDeathImpl is only going to be changed in test.
+ std::unique_ptr<ILinkToDeath> mLinkToDeathImpl;
- template <class T>
- std::shared_ptr<T> getOrCreateClient(
- std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
- const CallbackType& callback) REQUIRES(mLock);
+ // RecurrentTimer is thread-safe.
+ RecurrentTimer mRecurrentTimer;
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
::android::base::Result<void> checkProperty(
const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+
+ ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+ requests);
+
+ ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+ requests);
+
+ ::android::base::Result<void> checkSubscribeOptions(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
+ options);
+
+ ::android::base::Result<void> checkReadPermission(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+ ::android::base::Result<void> checkWritePermission(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+ ::android::base::Result<
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
+ getConfig(int32_t propId) const;
+
+ void onBinderDiedWithContext(const AIBinder* clientId);
+
+ void onBinderUnlinkedWithContext(const AIBinder* clientId);
+
+ void monitorBinderLifeCycle(const CallbackType& callback);
+
+ bool checkDumpPermission();
+
+ template <class T>
+ static std::shared_ptr<T> getOrCreateClient(
+ std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+
+ static void getValueFromHardwareCallCallback(
+ std::weak_ptr<IVehicleHardware> vehicleHardware,
+ std::shared_ptr<SubscribeIdByClient> subscribeIdByClient,
+ std::shared_ptr<SubscriptionClients> subscriptionClients, const CallbackType& callback,
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+
+ static void onPropertyChangeEvent(
+ std::weak_ptr<SubscriptionManager> subscriptionManager,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
+ updatedValues);
+
+ static void checkHealth(std::weak_ptr<IVehicleHardware> hardware,
+ std::weak_ptr<SubscriptionManager> subscriptionManager);
+
+ static void onBinderDied(void* cookie);
+
+ static void onBinderUnlinked(void* cookie);
+
+ // Test-only
+ // Set the default timeout for pending requests.
+ void setTimeout(int64_t timeoutInNano);
+
+ // Test-only
+ void setLinkToDeathImpl(std::unique_ptr<ILinkToDeath> impl);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h
index 4b7c2f3..7b2111b 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h
@@ -29,6 +29,9 @@
namespace automotive {
namespace vehicle {
+// Turns the values into a stable large parcelable that could be sent via binder.
+// If values is small enough, it would be put into output.payloads, otherwise a shared memory file
+// would be created and output.sharedMemoryFd would be filled in.
template <class T1, class T2>
::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector<T1>&& values, T2* output) {
output->payloads = std::move(values);
@@ -44,6 +47,9 @@
// 'sharedMemoryFd' field.
output->payloads.clear();
output->sharedMemoryFd = std::move(*fd);
+ } else {
+ output->sharedMemoryFd = ::ndk::ScopedFileDescriptor();
+ // Do not modify payloads.
}
return ::ndk::ScopedAStatus::ok();
}
diff --git a/automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h b/automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h
index 6dcfaff..efb3315 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h
@@ -51,7 +51,7 @@
// seconds.
android::base::Result<void> addRequests(const void* clientId,
const std::unordered_set<int64_t>& requestIds,
- std::shared_ptr<TimeoutCallbackFunc> callback);
+ std::shared_ptr<const TimeoutCallbackFunc> callback);
// Checks whether the request is currently pending.
bool isRequestPending(const void* clientId, int64_t requestId) const;
@@ -66,6 +66,8 @@
// Returns how many pending requests in the pool, for testing purpose.
size_t countPendingRequests(const void* clientId) const;
+ size_t countPendingRequests() const;
+
private:
// The maximum number of pending requests allowed per client. If exceeds this number, adding
// more requests would fail. This is to prevent spamming from client.
@@ -74,7 +76,7 @@
struct PendingRequest {
std::unordered_set<int64_t> requestIds;
int64_t timeoutTimestamp;
- std::shared_ptr<TimeoutCallbackFunc> callback;
+ std::shared_ptr<const TimeoutCallbackFunc> callback;
};
int64_t mTimeoutInNano;
diff --git a/automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h b/automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h
new file mode 100644
index 0000000..5f0f716
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_
+#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_
+
+#include <android-base/thread_annotations.h>
+
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+// A thread-safe recurrent timer.
+class RecurrentTimer final {
+ public:
+ // The class for the function that would be called recurrently.
+ using Callback = std::function<void()>;
+
+ RecurrentTimer();
+
+ ~RecurrentTimer();
+
+ // Registers a recurrent callback for a given interval.
+ // Registering the same callback twice will override the interval provided before.
+ void registerTimerCallback(int64_t intervalInNano, std::shared_ptr<Callback> callback);
+
+ // Unregisters a previously registered recurrent callback.
+ void unregisterTimerCallback(std::shared_ptr<Callback> callback);
+
+ private:
+ // friend class for unit testing.
+ friend class RecurrentTimerTest;
+
+ struct CallbackInfo {
+ std::shared_ptr<Callback> callback;
+ int64_t interval;
+ int64_t nextTime;
+ // A flag to indicate whether this CallbackInfo is already outdated and should be ignored.
+ // The reason we need this flag is because we cannot easily remove an element from a heap.
+ bool outdated = false;
+
+ static bool cmp(const std::unique_ptr<CallbackInfo>& lhs,
+ const std::unique_ptr<CallbackInfo>& rhs);
+ };
+
+ std::mutex mLock;
+ std::thread mThread;
+ std::condition_variable mCond;
+ bool mStopRequested GUARDED_BY(mLock) = false;
+ // A map to map each callback to its current active CallbackInfo in the mCallbackQueue.
+ std::unordered_map<std::shared_ptr<Callback>, CallbackInfo*> mCallbacks GUARDED_BY(mLock);
+ // A min-heap sorted by nextTime. Note that because we cannot remove arbitrary element from the
+ // heap, a single Callback can have multiple entries in this queue, all but one should be valid.
+ // The rest should be mark as outdated. The valid one is one stored in mCallbacks.
+ std::vector<std::unique_ptr<CallbackInfo>> mCallbackQueue GUARDED_BY(mLock);
+
+ void loop();
+
+ // Mark the callbackInfo as outdated and should be ignored when popped from the heap.
+ void markOutdatedLocked(CallbackInfo* callback) REQUIRES(mLock);
+ // Remove all outdated callbackInfos from the top of the heap. This function must be called
+ // each time we might introduce outdated elements to the top. We must make sure the heap is
+ // always valid from the top.
+ void removeInvalidCallbackLocked() REQUIRES(mLock);
+ // Pops the next closest callback (must be valid) from the heap.
+ std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock);
+};
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_vhal_include_RecurrentTimer_H_
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
new file mode 100644
index 0000000..e739c8c
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
+#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
+
+#include "RecurrentTimer.h"
+
+#include <VehicleHalTypes.h>
+
+#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
+#include <android-base/result.h>
+#include <android-base/thread_annotations.h>
+
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+// A thread-safe subscription manager that manages all VHAL subscriptions.
+class SubscriptionManager final {
+ public:
+ using ClientIdType = const AIBinder*;
+ using CallbackType =
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+ using GetValueFunc = std::function<void(
+ const CallbackType& callback,
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)>;
+
+ explicit SubscriptionManager(GetValueFunc&& action);
+ ~SubscriptionManager();
+
+ // Subscribes to properties according to {@code SubscribeOptions}. Note that all option must
+ // contain non-empty areaIds field, which contains all area IDs to subscribe. As a result,
+ // the options here is different from the options passed from VHAL client.
+ // Returns error if any of the subscribe options is not valid. If error is returned, no
+ // properties would be subscribed.
+ // Returns ok if all the options are parsed correctly and all the properties are subscribed.
+ ::android::base::Result<void> subscribe(
+ const CallbackType& callback,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
+ options,
+ bool isContinuousProperty);
+
+ // Unsubscribes from the properties for the client.
+ // Returns error if the client was not subscribed before or one of the given property was not
+ // subscribed. If error is returned, no property would be unsubscribed.
+ // Returns ok if all the requested properties for the client are unsubscribed.
+ ::android::base::Result<void> unsubscribe(ClientIdType client,
+ const std::vector<int32_t>& propIds);
+
+ // Unsubscribes from all the properties for the client.
+ // Returns error if the client was not subscribed before. If error is returned, no property
+ // would be unsubscribed.
+ // Returns ok if all the properties for the client are unsubscribed.
+ ::android::base::Result<void> unsubscribe(ClientIdType client);
+
+ // For a list of updated properties, returns a map that maps clients subscribing to
+ // the updated properties to a list of updated values. This would only return on-change property
+ // clients that should be informed for the given updated values.
+ std::unordered_map<
+ CallbackType,
+ std::vector<const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue*>>
+ getSubscribedClients(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
+ updatedValues);
+
+ // Checks whether the sample rate is valid.
+ static bool checkSampleRate(float sampleRate);
+
+ private:
+ // Friend class for testing.
+ friend class DefaultVehicleHalTest;
+
+ struct PropIdAreaId {
+ int32_t propId;
+ int32_t areaId;
+
+ bool operator==(const PropIdAreaId& other) const;
+ };
+
+ struct PropIdAreaIdHash {
+ size_t operator()(const PropIdAreaId& propIdAreaId) const;
+ };
+
+ // A class to represent a registered subscription.
+ class Subscription {
+ public:
+ Subscription() = default;
+
+ Subscription(const Subscription&) = delete;
+
+ virtual ~Subscription() = default;
+
+ virtual bool isOnChange();
+ };
+
+ // A subscription for OnContinuous property. The registered action would be called recurrently
+ // until this class is destructed.
+ class RecurrentSubscription final : public Subscription {
+ public:
+ explicit RecurrentSubscription(std::shared_ptr<RecurrentTimer> timer,
+ std::function<void()>&& action, int64_t interval);
+ ~RecurrentSubscription();
+
+ bool isOnChange() override;
+
+ private:
+ std::shared_ptr<std::function<void()>> mAction;
+ std::shared_ptr<RecurrentTimer> mTimer;
+ };
+
+ // A subscription for OnChange property.
+ class OnChangeSubscription final : public Subscription {
+ public:
+ bool isOnChange() override;
+ };
+
+ mutable std::mutex mLock;
+ std::unordered_map<PropIdAreaId, std::unordered_map<ClientIdType, CallbackType>,
+ PropIdAreaIdHash>
+ mClientsByPropIdArea GUARDED_BY(mLock);
+ std::unordered_map<ClientIdType, std::unordered_map<PropIdAreaId, std::unique_ptr<Subscription>,
+ PropIdAreaIdHash>>
+ mSubscriptionsByClient GUARDED_BY(mLock);
+ // RecurrentTimer is thread-safe.
+ std::shared_ptr<RecurrentTimer> mTimer;
+ const GetValueFunc mGetValue;
+
+ static ::android::base::Result<int64_t> getInterval(float sampleRate);
+
+ // Checks whether the manager is empty. For testing purpose.
+ bool isEmpty();
+};
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 656dfaf..098bfee 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -84,9 +84,9 @@
// Send all the GetValue/SetValue results through callback in a single callback invocation.
template <class ResultType, class ResultsType>
void sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback,
- const std::vector<ResultType>& results) {
+ std::vector<ResultType>&& results) {
ResultsType parcelableResults;
- ScopedAStatus status = vectorToStableLargeParcelable(results, &parcelableResults);
+ ScopedAStatus status = vectorToStableLargeParcelable(std::move(results), &parcelableResults);
if (status.isOk()) {
if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
!callbackStatus.isOk()) {
@@ -99,7 +99,55 @@
ALOGE("failed to marshal result into large parcelable, error: "
"%s, code: %d",
status.getMessage(), statusCode);
- sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback, results);
+ sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback,
+ parcelableResults.payloads);
+}
+
+// The timeout callback for GetValues/SetValues.
+template <class ResultType, class ResultsType>
+void onTimeout(
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+ const std::unordered_set<int64_t>& timeoutIds) {
+ std::vector<ResultType> timeoutResults;
+ for (int64_t requestId : timeoutIds) {
+ ALOGD("hardware request timeout, request ID: %" PRId64, requestId);
+ timeoutResults.push_back({
+ .requestId = requestId,
+ .status = StatusCode::TRY_AGAIN,
+ });
+ }
+ sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(timeoutResults));
+}
+
+// The on-results callback for GetValues/SetValues.
+template <class ResultType, class ResultsType>
+void getOrSetValuesCallback(
+ const void* clientId,
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+ std::vector<ResultType>&& results, std::shared_ptr<PendingRequestPool> requestPool) {
+ std::unordered_set<int64_t> requestIds;
+ for (const auto& result : results) {
+ requestIds.insert(result.requestId);
+ }
+
+ auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds);
+
+ auto it = results.begin();
+ while (it != results.end()) {
+ int64_t requestId = it->requestId;
+ if (finishedRequests.find(requestId) == finishedRequests.end()) {
+ ALOGD("no pending request for the result from hardware, "
+ "possibly already time-out, ID: %" PRId64,
+ requestId);
+ it = results.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ if (!results.empty()) {
+ sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(results));
+ }
}
// Specify the functions for GetValues and SetValues types.
@@ -109,27 +157,64 @@
std::shared_ptr<IVehicleCallback> callback, const SetValueResult& result);
template void sendGetOrSetValueResults<GetValueResult, GetValueResults>(
- std::shared_ptr<IVehicleCallback> callback, const std::vector<GetValueResult>& results);
+ std::shared_ptr<IVehicleCallback> callback, std::vector<GetValueResult>&& results);
template void sendGetOrSetValueResults<SetValueResult, SetValueResults>(
- std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results);
+ std::shared_ptr<IVehicleCallback> callback, std::vector<SetValueResult>&& results);
template void sendGetOrSetValueResultsSeparately<GetValueResult, GetValueResults>(
std::shared_ptr<IVehicleCallback> callback, const std::vector<GetValueResult>& results);
template void sendGetOrSetValueResultsSeparately<SetValueResult, SetValueResults>(
std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results);
+template void onTimeout<GetValueResult, GetValueResults>(
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+ const std::unordered_set<int64_t>& timeoutIds);
+template void onTimeout<SetValueResult, SetValueResults>(
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+ const std::unordered_set<int64_t>& timeoutIds);
+
+template void getOrSetValuesCallback<GetValueResult, GetValueResults>(
+ const void* clientId,
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+ std::vector<GetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
+template void getOrSetValuesCallback<SetValueResult, SetValueResults>(
+ const void* clientId,
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
+ std::vector<SetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
+
} // namespace
-ConnectedClient::ConnectedClient(std::shared_ptr<IVehicleCallback> callback)
- : mCallback(callback) {}
+ConnectedClient::ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool,
+ std::shared_ptr<IVehicleCallback> callback)
+ : mRequestPool(requestPool), mCallback(callback) {}
+
+const void* ConnectedClient::id() {
+ return reinterpret_cast<const void*>(this);
+}
+
+Result<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) {
+ return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback());
+}
+
+std::unordered_set<int64_t> ConnectedClient::tryFinishRequests(
+ const std::unordered_set<int64_t>& requestIds) {
+ return mRequestPool->tryFinishRequests(id(), requestIds);
+}
template <class ResultType, class ResultsType>
GetSetValuesClient<ResultType, ResultsType>::GetSetValuesClient(
- std::shared_ptr<IVehicleCallback> callback)
- : ConnectedClient(callback) {
+ std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback)
+ : ConnectedClient(requestPool, callback) {
+ mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>(
+ [callback](const std::unordered_set<int64_t>& timeoutIds) {
+ return onTimeout<ResultType, ResultsType>(callback, timeoutIds);
+ });
+ auto requestPoolCopy = mRequestPool;
+ const void* clientId = id();
mResultCallback = std::make_shared<const std::function<void(std::vector<ResultType>)>>(
- [callback](std::vector<ResultType> results) {
- return sendGetOrSetValueResults<ResultType, ResultsType>(callback, results);
+ [clientId, callback, requestPoolCopy](std::vector<ResultType> results) {
+ return getOrSetValuesCallback<ResultType, ResultsType>(
+ clientId, callback, std::move(results), requestPoolCopy);
});
}
@@ -140,9 +225,14 @@
}
template <class ResultType, class ResultsType>
-void GetSetValuesClient<ResultType, ResultsType>::sendResults(
- const std::vector<ResultType>& results) {
- return sendGetOrSetValueResults<ResultType, ResultsType>(mCallback, results);
+std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc>
+GetSetValuesClient<ResultType, ResultsType>::getTimeoutCallback() {
+ return mTimeoutCallback;
+}
+
+template <class ResultType, class ResultsType>
+void GetSetValuesClient<ResultType, ResultsType>::sendResults(std::vector<ResultType>&& results) {
+ return sendGetOrSetValueResults<ResultType, ResultsType>(mCallback, std::move(results));
}
template <class ResultType, class ResultsType>
@@ -154,6 +244,100 @@
template class GetSetValuesClient<GetValueResult, GetValueResults>;
template class GetSetValuesClient<SetValueResult, SetValueResults>;
+SubscriptionClient::SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool,
+ std::shared_ptr<IVehicleCallback> callback)
+ : ConnectedClient(requestPool, callback) {
+ mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>(
+ [](std::unordered_set<int64_t> timeoutIds) {
+ for (int64_t id : timeoutIds) {
+ ALOGW("subscribe: requests with IDs: %" PRId64
+ " has timed-out, not client informed, "
+ "possibly one of recurrent requests for this subscription failed",
+ id);
+ }
+ });
+ auto requestPoolCopy = mRequestPool;
+ const void* clientId = reinterpret_cast<const void*>(this);
+ mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>(
+ [clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) {
+ onGetValueResults(clientId, callback, requestPoolCopy, results);
+ });
+}
+
+std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>>
+SubscriptionClient::getResultCallback() {
+ return mResultCallback;
+}
+
+std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc>
+SubscriptionClient::getTimeoutCallback() {
+ return mTimeoutCallback;
+}
+
+void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,
+ std::vector<VehiclePropValue>&& updatedValues) {
+ if (updatedValues.empty()) {
+ return;
+ }
+
+ // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
+ VehiclePropValues vehiclePropValues;
+ int32_t sharedMemoryFileCount = 0;
+ ScopedAStatus status =
+ vectorToStableLargeParcelable(std::move(updatedValues), &vehiclePropValues);
+ if (!status.isOk()) {
+ int statusCode = status.getServiceSpecificError();
+ ALOGE("subscribe: failed to marshal result into large parcelable, error: "
+ "%s, code: %d",
+ status.getMessage(), statusCode);
+ return;
+ }
+
+ if (ScopedAStatus callbackStatus =
+ callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
+ !callbackStatus.isOk()) {
+ ALOGE("subscribe: failed to call callback, error: %s, code: %d", status.getMessage(),
+ status.getServiceSpecificError());
+ }
+}
+
+void SubscriptionClient::onGetValueResults(const void* clientId,
+ std::shared_ptr<IVehicleCallback> callback,
+ std::shared_ptr<PendingRequestPool> requestPool,
+ std::vector<GetValueResult> results) {
+ std::unordered_set<int64_t> requestIds;
+ for (const auto& result : results) {
+ requestIds.insert(result.requestId);
+ }
+
+ auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds);
+ std::vector<VehiclePropValue> propValues;
+ for (auto& result : results) {
+ int64_t requestId = result.requestId;
+ if (finishedRequests.find(requestId) == finishedRequests.end()) {
+ ALOGE("subscribe[%" PRId64
+ "]: no pending request for the result from hardware, "
+ "possibly already time-out",
+ requestId);
+ continue;
+ }
+ if (result.status != StatusCode::OK) {
+ ALOGE("subscribe[%" PRId64
+ "]: hardware returns non-ok status for getValues, status: "
+ "%d",
+ requestId, toInt(result.status));
+ continue;
+ }
+ if (!result.prop.has_value()) {
+ ALOGE("subscribe[%" PRId64 "]: no prop value in getValues result", requestId);
+ continue;
+ }
+ propValues.push_back(std::move(result.prop.value()));
+ }
+
+ sendUpdatedValues(callback, std::move(propValues));
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 7f09a59..c0a66da 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -23,18 +23,27 @@
#include <VehicleUtils.h>
#include <android-base/result.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_ibinder.h>
+#include <private/android_filesystem_config.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <inttypes.h>
+#include <set>
+#include <unordered_set>
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
+namespace {
+
using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
-using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
@@ -44,15 +53,59 @@
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::automotive::car_binder_lib::LargeParcelableBase;
using ::android::base::Error;
using ::android::base::expected;
using ::android::base::Result;
+using ::android::base::StringPrintf;
+
+using ::ndk::ScopedAIBinder_DeathRecipient;
using ::ndk::ScopedAStatus;
+std::string toString(const std::unordered_set<int64_t>& values) {
+ std::string str = "";
+ for (auto it = values.begin(); it != values.end(); it++) {
+ str += std::to_string(*it);
+ if (std::next(it, 1) != values.end()) {
+ str += ", ";
+ }
+ }
+ return str;
+}
+
+} // namespace
+
+std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient(
+ const CallbackType& callback) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return getOrCreateClient(&mClients, callback, mPendingRequestPool);
+}
+
+int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ // This would be initialized to 0 if callback does not exist in the map.
+ int64_t subscribeId = (mIds[callback->asBinder().get()])++;
+ return subscribeId;
+}
+
+void DefaultVehicleHal::SubscriptionClients::removeClient(const AIBinder* clientId) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mClients.erase(clientId);
+}
+
+size_t DefaultVehicleHal::SubscriptionClients::countClients() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mClients.size();
+}
+
DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware)
- : mVehicleHardware(std::move(hardware)) {
+ : mVehicleHardware(std::move(hardware)),
+ mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) {
auto configs = mVehicleHardware->getAllPropertyConfigs();
for (auto& config : configs) {
mConfigsByPropId[config.prop] = config;
@@ -69,6 +122,168 @@
if (result.value() != nullptr) {
mConfigFile = std::move(result.value());
}
+
+ mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);
+
+ auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>();
+ // Make a weak copy of IVehicleHardware because subscriptionManager uses IVehicleHardware and
+ // IVehicleHardware uses subscriptionManager. We want to avoid cyclic reference.
+ std::weak_ptr<IVehicleHardware> hardwareCopy = mVehicleHardware;
+ SubscriptionManager::GetValueFunc getValueFunc = std::bind(
+ &DefaultVehicleHal::getValueFromHardwareCallCallback, hardwareCopy, subscribeIdByClient,
+ mSubscriptionClients, std::placeholders::_1, std::placeholders::_2);
+ mSubscriptionManager = std::make_shared<SubscriptionManager>(std::move(getValueFunc));
+
+ std::weak_ptr<SubscriptionManager> subscriptionManagerCopy = mSubscriptionManager;
+ mVehicleHardware->registerOnPropertyChangeEvent(
+ std::make_unique<IVehicleHardware::PropertyChangeCallback>(
+ [subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
+ onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
+ }));
+
+ // Register heartbeat event.
+ mRecurrentTimer.registerTimerCallback(
+ HEART_BEAT_INTERVAL_IN_NANO,
+ std::make_shared<std::function<void()>>([hardwareCopy, subscriptionManagerCopy]() {
+ checkHealth(hardwareCopy, subscriptionManagerCopy);
+ }));
+
+ mLinkToDeathImpl = std::make_unique<AIBinderLinkToDeathImpl>();
+ mDeathRecipient = ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(&DefaultVehicleHal::onBinderDied));
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(),
+ &DefaultVehicleHal::onBinderUnlinked);
+}
+
+DefaultVehicleHal::~DefaultVehicleHal() {
+ // Delete the deathRecipient so that onBinderDied would not be called to reference 'this'.
+ mDeathRecipient = ScopedAIBinder_DeathRecipient();
+}
+
+void DefaultVehicleHal::onPropertyChangeEvent(
+ std::weak_ptr<SubscriptionManager> subscriptionManager,
+ const std::vector<VehiclePropValue>& updatedValues) {
+ auto manager = subscriptionManager.lock();
+ if (manager == nullptr) {
+ ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+ return;
+ }
+ auto updatedValuesByClients = manager->getSubscribedClients(updatedValues);
+ for (const auto& [callback, valuePtrs] : updatedValuesByClients) {
+ std::vector<VehiclePropValue> values;
+ for (const VehiclePropValue* valuePtr : valuePtrs) {
+ values.push_back(*valuePtr);
+ }
+ SubscriptionClient::sendUpdatedValues(callback, std::move(values));
+ }
+}
+
+template <class T>
+std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
+ std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool) {
+ const AIBinder* clientId = callback->asBinder().get();
+ if (clients->find(clientId) == clients->end()) {
+ (*clients)[clientId] = std::make_shared<T>(pendingRequestPool, callback);
+ }
+ return (*clients)[clientId];
+}
+
+void DefaultVehicleHal::monitorBinderLifeCycle(const CallbackType& callback) {
+ AIBinder* clientId = callback->asBinder().get();
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mOnBinderDiedContexts.find(clientId) != mOnBinderDiedContexts.end()) {
+ // Already registered.
+ return;
+ }
+ }
+
+ std::unique_ptr<OnBinderDiedContext> context = std::make_unique<OnBinderDiedContext>(
+ OnBinderDiedContext{.vhal = this, .clientId = clientId});
+ binder_status_t status = mLinkToDeathImpl->linkToDeath(clientId, mDeathRecipient.get(),
+ static_cast<void*>(context.get()));
+ if (status == STATUS_OK) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ // Insert into a map to keep the context object alive.
+ mOnBinderDiedContexts[clientId] = std::move(context);
+ } else {
+ ALOGE("failed to call linkToDeath on client binder, status: %d", static_cast<int>(status));
+ }
+}
+
+void DefaultVehicleHal::onBinderDied(void* cookie) {
+ OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
+ context->vhal->onBinderDiedWithContext(context->clientId);
+}
+
+void DefaultVehicleHal::onBinderDiedWithContext(const AIBinder* clientId) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mSetValuesClients.erase(clientId);
+ mGetValuesClients.erase(clientId);
+ mSubscriptionClients->removeClient(clientId);
+ mSubscriptionManager->unsubscribe(clientId);
+}
+
+void DefaultVehicleHal::onBinderUnlinked(void* cookie) {
+ // Delete the context associated with this cookie.
+ OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
+ context->vhal->onBinderUnlinkedWithContext(context->clientId);
+}
+
+void DefaultVehicleHal::onBinderUnlinkedWithContext(const AIBinder* clientId) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mOnBinderDiedContexts.erase(clientId);
+}
+
+template std::shared_ptr<DefaultVehicleHal::GetValuesClient>
+DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::GetValuesClient>(
+ std::unordered_map<const AIBinder*, std::shared_ptr<GetValuesClient>>* clients,
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+template std::shared_ptr<DefaultVehicleHal::SetValuesClient>
+DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>(
+ std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>>* clients,
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+template std::shared_ptr<SubscriptionClient>
+DefaultVehicleHal::getOrCreateClient<SubscriptionClient>(
+ std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>>* clients,
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+
+void DefaultVehicleHal::getValueFromHardwareCallCallback(
+ std::weak_ptr<IVehicleHardware> vehicleHardware,
+ std::shared_ptr<SubscribeIdByClient> subscribeIdByClient,
+ std::shared_ptr<SubscriptionClients> subscriptionClients, const CallbackType& callback,
+ const VehiclePropValue& value) {
+ int64_t subscribeId = subscribeIdByClient->getId(callback);
+ auto client = subscriptionClients->getClient(callback);
+ if (auto addRequestResult = client->addRequests({subscribeId}); !addRequestResult.ok()) {
+ ALOGE("subscribe[%" PRId64 "]: too many pending requests, ignore the getValue request",
+ subscribeId);
+ return;
+ }
+
+ std::vector<GetValueRequest> hardwareRequests = {{
+ .requestId = subscribeId,
+ .prop = value,
+ }};
+
+ std::shared_ptr<IVehicleHardware> hardware = vehicleHardware.lock();
+ if (hardware == nullptr) {
+ ALOGW("the IVehicleHardware is destroyed, DefaultVehicleHal is ending");
+ return;
+ }
+ if (StatusCode status = hardware->getValues(client->getResultCallback(), hardwareRequests);
+ status != StatusCode::OK) {
+ // If the hardware returns error, finish all the pending requests for this request because
+ // we never expect hardware to call callback for these requests.
+ client->tryFinishRequests({subscribeId});
+ ALOGE("subscribe[%" PRId64 "]: failed to get value from VehicleHardware, code: %d",
+ subscribeId, toInt(status));
+ }
+}
+
+void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) {
+ mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
}
ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
@@ -84,55 +299,42 @@
return ScopedAStatus::ok();
}
-template <class T>
-std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
- std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
- const CallbackType& callback) {
- if (clients->find(callback) == clients->end()) {
- // TODO(b/204943359): Remove client from clients when linkToDeath is implemented.
- (*clients)[callback] = std::make_shared<T>(callback);
- }
- return (*clients)[callback];
-}
-
-template std::shared_ptr<DefaultVehicleHal::GetValuesClient>
-DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::GetValuesClient>(
- std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>>* clients,
- const CallbackType& callback);
-
-template std::shared_ptr<DefaultVehicleHal::SetValuesClient>
-DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>(
- std::unordered_map<CallbackType, std::shared_ptr<SetValuesClient>>* clients,
- const CallbackType& callback);
-
-Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
- int32_t propId = propValue.prop;
+Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
auto it = mConfigsByPropId.find(propId);
if (it == mConfigsByPropId.end()) {
return Error() << "no config for property, ID: " << propId;
}
- const VehiclePropConfig& config = it->second;
- const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, config);
+ return &(it->second);
+}
+
+Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
+ int32_t propId = propValue.prop;
+ auto result = getConfig(propId);
+ if (!result.ok()) {
+ return result.error();
+ }
+ const VehiclePropConfig* config = result.value();
+ const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, *config);
if (!isGlobalProp(propId) && areaConfig == nullptr) {
// Ignore areaId for global property. For non global property, check whether areaId is
// allowed. areaId must appear in areaConfig.
return Error() << "invalid area ID: " << propValue.areaId << " for prop ID: " << propId
<< ", not listed in config";
}
- if (auto result = checkPropValue(propValue, &config); !result.ok()) {
+ if (auto result = checkPropValue(propValue, config); !result.ok()) {
return Error() << "invalid property value: " << propValue.toString()
- << ", error: " << result.error().message();
+ << ", error: " << getErrorMsg(result);
}
if (auto result = checkValueRange(propValue, areaConfig); !result.ok()) {
return Error() << "property value out of range: " << propValue.toString()
- << ", error: " << result.error().message();
+ << ", error: " << getErrorMsg(result);
}
return {};
}
ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,
const GetValueRequests& requests) {
- // TODO(b/203713317): check for duplicate properties and duplicate request IDs.
+ monitorBinderLifeCycle(callback);
expected<LargeParcelableBase::BorrowedOwnedObject<GetValueRequests>, ScopedAStatus>
deserializedResults = fromStableLargeParcelable(requests);
@@ -143,25 +345,74 @@
const std::vector<GetValueRequest>& getValueRequests =
deserializedResults.value().getObject()->payloads;
+ auto maybeRequestIds = checkDuplicateRequests(getValueRequests);
+ if (!maybeRequestIds.ok()) {
+ ALOGE("getValues: duplicate request ID");
+ return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG);
+ }
+
+ // A list of failed result we already know before sending to hardware.
+ std::vector<GetValueResult> failedResults;
+ // The list of requests that we would send to hardware.
+ std::vector<GetValueRequest> hardwareRequests;
+
+ for (const auto& request : getValueRequests) {
+ if (auto result = checkReadPermission(request.prop); !result.ok()) {
+ ALOGW("property does not support reading: %s", getErrorMsg(result).c_str());
+ failedResults.push_back(GetValueResult{
+ .requestId = request.requestId,
+ .status = getErrorCode(result),
+ .prop = {},
+ });
+ } else {
+ hardwareRequests.push_back(request);
+ }
+ }
+
+ // The set of request Ids that we would send to hardware.
+ std::unordered_set<int64_t> hardwareRequestIds;
+ for (const auto& request : hardwareRequests) {
+ hardwareRequestIds.insert(request.requestId);
+ }
+
std::shared_ptr<GetValuesClient> client;
{
std::scoped_lock<std::mutex> lockGuard(mLock);
- client = getOrCreateClient(&mGetValuesClients, callback);
+ client = getOrCreateClient(&mGetValuesClients, callback, mPendingRequestPool);
+ }
+ // Register the pending hardware requests and also check for duplicate request Ids.
+ if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
+ ALOGE("getValues[%s]: failed to add pending requests, error: %s",
+ toString(hardwareRequestIds).c_str(), getErrorMsg(addRequestResult).c_str());
+ return toScopedAStatus(addRequestResult);
+ }
+
+ if (!failedResults.empty()) {
+ // First send the failed results we already know back to the client.
+ client->sendResults(std::move(failedResults));
+ }
+
+ if (hardwareRequests.empty()) {
+ return ScopedAStatus::ok();
}
if (StatusCode status =
- mVehicleHardware->getValues(client->getResultCallback(), getValueRequests);
+ mVehicleHardware->getValues(client->getResultCallback(), hardwareRequests);
status != StatusCode::OK) {
+ // If the hardware returns error, finish all the pending requests for this request because
+ // we never expect hardware to call callback for these requests.
+ client->tryFinishRequests(hardwareRequestIds);
+ ALOGE("getValues[%s]: failed to get value from VehicleHardware, status: %d",
+ toString(hardwareRequestIds).c_str(), toInt(status));
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
toInt(status), "failed to get value from VehicleHardware");
}
-
return ScopedAStatus::ok();
}
ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback,
const SetValueRequests& requests) {
- // TODO(b/203713317): check for duplicate properties and duplicate request IDs.
+ monitorBinderLifeCycle(callback);
expected<LargeParcelableBase::BorrowedOwnedObject<SetValueRequests>, ScopedAStatus>
deserializedResults = fromStableLargeParcelable(requests);
@@ -177,32 +428,71 @@
// The list of requests that we would send to hardware.
std::vector<SetValueRequest> hardwareRequests;
+ auto maybeRequestIds = checkDuplicateRequests(setValueRequests);
+ if (!maybeRequestIds.ok()) {
+ ALOGE("setValues: duplicate request ID");
+ return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG);
+ }
+
for (auto& request : setValueRequests) {
int64_t requestId = request.requestId;
+ if (auto result = checkWritePermission(request.value); !result.ok()) {
+ ALOGW("property does not support writing: %s", getErrorMsg(result).c_str());
+ failedResults.push_back(SetValueResult{
+ .requestId = requestId,
+ .status = getErrorCode(result),
+ });
+ continue;
+ }
if (auto result = checkProperty(request.value); !result.ok()) {
- ALOGW("property not valid: %s", result.error().message().c_str());
+ ALOGW("setValues[%" PRId64 "]: property is not valid: %s", requestId,
+ getErrorMsg(result).c_str());
failedResults.push_back(SetValueResult{
.requestId = requestId,
.status = StatusCode::INVALID_ARG,
});
continue;
}
+
hardwareRequests.push_back(request);
}
+ // The set of request Ids that we would send to hardware.
+ std::unordered_set<int64_t> hardwareRequestIds;
+ for (const auto& request : hardwareRequests) {
+ hardwareRequestIds.insert(request.requestId);
+ }
+
std::shared_ptr<SetValuesClient> client;
{
std::scoped_lock<std::mutex> lockGuard(mLock);
- client = getOrCreateClient(&mSetValuesClients, callback);
+ client = getOrCreateClient(&mSetValuesClients, callback, mPendingRequestPool);
+ }
+
+ // Register the pending hardware requests and also check for duplicate request Ids.
+ if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
+ ALOGE("setValues[%s], failed to add pending requests, error: %s",
+ toString(hardwareRequestIds).c_str(), getErrorMsg(addRequestResult).c_str());
+ return toScopedAStatus(addRequestResult, StatusCode::INVALID_ARG);
}
if (!failedResults.empty()) {
- client->sendResults(failedResults);
+ // First send the failed results we already know back to the client.
+ client->sendResults(std::move(failedResults));
+ }
+
+ if (hardwareRequests.empty()) {
+ return ScopedAStatus::ok();
}
if (StatusCode status =
mVehicleHardware->setValues(client->getResultCallback(), hardwareRequests);
status != StatusCode::OK) {
+ // If the hardware returns error, finish all the pending requests for this request because
+ // we never expect hardware to call callback for these requests.
+ client->tryFinishRequests(hardwareRequestIds);
+ ALOGE("setValues[%s], failed to set value to VehicleHardware, status: %d",
+ toString(hardwareRequestIds).c_str(), toInt(status));
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
toInt(status), "failed to set value to VehicleHardware");
}
@@ -210,6 +500,34 @@
return ScopedAStatus::ok();
}
+#define CHECK_DUPLICATE_REQUESTS(PROP_NAME) \
+ do { \
+ std::vector<int64_t> requestIds; \
+ std::set<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> requestProps; \
+ for (const auto& request : requests) { \
+ const auto& prop = request.PROP_NAME; \
+ if (requestProps.count(prop) != 0) { \
+ return ::android::base::Error() \
+ << "duplicate request for property: " << prop.toString(); \
+ } \
+ requestProps.insert(prop); \
+ requestIds.push_back(request.requestId); \
+ } \
+ return requestIds; \
+ } while (0);
+
+::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests(
+ const std::vector<GetValueRequest>& requests) {
+ CHECK_DUPLICATE_REQUESTS(prop);
+}
+
+::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests(
+ const std::vector<SetValueRequest>& requests) {
+ CHECK_DUPLICATE_REQUESTS(value);
+}
+
+#undef CHECK_DUPLICATE_REQUESTS
+
ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
VehiclePropConfigs* output) {
std::vector<VehiclePropConfig> configs;
@@ -221,15 +539,112 @@
return vectorToStableLargeParcelable(std::move(configs), output);
}
-ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType&,
- const std::vector<SubscribeOptions>&, int32_t) {
- // TODO(b/200737967): implement this.
+Result<void> DefaultVehicleHal::checkSubscribeOptions(
+ const std::vector<SubscribeOptions>& options) {
+ for (const auto& option : options) {
+ int32_t propId = option.propId;
+ if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << StringPrintf("no config for property, ID: %" PRId32, propId);
+ }
+ const VehiclePropConfig& config = mConfigsByPropId[propId];
+
+ if (config.changeMode != VehiclePropertyChangeMode::ON_CHANGE &&
+ config.changeMode != VehiclePropertyChangeMode::CONTINUOUS) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << "only support subscribing to ON_CHANGE or CONTINUOUS property";
+ }
+
+ if (config.access != VehiclePropertyAccess::READ &&
+ config.access != VehiclePropertyAccess::READ_WRITE) {
+ return Error(toInt(StatusCode::ACCESS_DENIED))
+ << StringPrintf("Property %" PRId32 " has no read access", propId);
+ }
+
+ if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+ float sampleRate = option.sampleRate;
+ float minSampleRate = config.minSampleRate;
+ float maxSampleRate = config.maxSampleRate;
+ if (sampleRate < minSampleRate || sampleRate > maxSampleRate) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << StringPrintf("sample rate: %f out of range, must be within %f and %f",
+ sampleRate, minSampleRate, maxSampleRate);
+ }
+ if (!SubscriptionManager::checkSampleRate(sampleRate)) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << "invalid sample rate: " << sampleRate;
+ }
+ }
+
+ if (isGlobalProp(propId)) {
+ continue;
+ }
+
+ // Non-global property.
+ for (int32_t areaId : option.areaIds) {
+ if (auto areaConfig = getAreaConfig(propId, areaId, config); areaConfig == nullptr) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << StringPrintf("invalid area ID: %" PRId32 " for prop ID: %" PRId32
+ ", not listed in config",
+ areaId, propId);
+ }
+ }
+ }
+ return {};
+}
+
+ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
+ const std::vector<SubscribeOptions>& options,
+ [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
+ monitorBinderLifeCycle(callback);
+
+ // TODO(b/205189110): Use shared memory file count.
+ if (auto result = checkSubscribeOptions(options); !result.ok()) {
+ ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
+ return toScopedAStatus(result);
+ }
+
+ std::vector<SubscribeOptions> onChangeSubscriptions;
+ std::vector<SubscribeOptions> continuousSubscriptions;
+ for (const auto& option : options) {
+ int32_t propId = option.propId;
+ // We have already validate config exists.
+ const VehiclePropConfig& config = mConfigsByPropId[propId];
+
+ SubscribeOptions optionCopy = option;
+ // If areaIds is empty, subscribe to all areas.
+ if (optionCopy.areaIds.empty() && !isGlobalProp(propId)) {
+ for (const auto& areaConfig : config.areaConfigs) {
+ optionCopy.areaIds.push_back(areaConfig.areaId);
+ }
+ }
+
+ if (isGlobalProp(propId)) {
+ optionCopy.areaIds = {0};
+ }
+
+ if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+ continuousSubscriptions.push_back(std::move(optionCopy));
+ } else {
+ onChangeSubscriptions.push_back(std::move(optionCopy));
+ }
+ }
+ // Since we have already check the sample rates, the following functions must succeed.
+ if (!onChangeSubscriptions.empty()) {
+ mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+ /*isContinuousProperty=*/false);
+ }
+ if (!continuousSubscriptions.empty()) {
+ mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+ /*isContinuousProperty=*/true);
+ }
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType&, const std::vector<int32_t>&) {
- // TODO(b/200737967): implement this.
- return ScopedAStatus::ok();
+ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType& callback,
+ const std::vector<int32_t>& propIds) {
+ return toScopedAStatus(mSubscriptionManager->unsubscribe(callback->asBinder().get(), propIds),
+ StatusCode::INVALID_ARG);
}
ScopedAStatus DefaultVehicleHal::returnSharedMemory(const CallbackType&, int64_t) {
@@ -241,6 +656,103 @@
return mVehicleHardware.get();
}
+Result<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
+ int32_t propId = value.prop;
+ auto result = getConfig(propId);
+ if (!result.ok()) {
+ return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+ }
+ const VehiclePropConfig* config = result.value();
+
+ if (config->access != VehiclePropertyAccess::WRITE &&
+ config->access != VehiclePropertyAccess::READ_WRITE) {
+ return Error(toInt(StatusCode::ACCESS_DENIED))
+ << StringPrintf("Property %" PRId32 " has no write access", propId);
+ }
+ return {};
+}
+
+Result<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
+ int32_t propId = value.prop;
+ auto result = getConfig(propId);
+ if (!result.ok()) {
+ return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+ }
+ const VehiclePropConfig* config = result.value();
+
+ if (config->access != VehiclePropertyAccess::READ &&
+ config->access != VehiclePropertyAccess::READ_WRITE) {
+ return Error(toInt(StatusCode::ACCESS_DENIED))
+ << StringPrintf("Property %" PRId32 " has no read access", propId);
+ }
+ return {};
+}
+
+void DefaultVehicleHal::checkHealth(std::weak_ptr<IVehicleHardware> hardware,
+ std::weak_ptr<SubscriptionManager> subscriptionManager) {
+ auto hardwarePtr = hardware.lock();
+ if (hardwarePtr == nullptr) {
+ ALOGW("the VehicleHardware is destroyed, DefaultVehicleHal is ending");
+ return;
+ }
+
+ StatusCode status = hardwarePtr->checkHealth();
+ if (status != StatusCode::OK) {
+ ALOGE("VHAL check health returns non-okay status");
+ return;
+ }
+ std::vector<VehiclePropValue> values = {{
+ .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+ .areaId = 0,
+ .status = VehiclePropertyStatus::AVAILABLE,
+ .value.int64Values = {uptimeMillis()},
+ }};
+ onPropertyChangeEvent(subscriptionManager, values);
+ return;
+}
+
+binder_status_t DefaultVehicleHal::AIBinderLinkToDeathImpl::linkToDeath(
+ AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) {
+ return AIBinder_linkToDeath(binder, recipient, cookie);
+}
+
+void DefaultVehicleHal::setLinkToDeathImpl(std::unique_ptr<ILinkToDeath> impl) {
+ mLinkToDeathImpl = std::move(impl);
+}
+
+bool DefaultVehicleHal::checkDumpPermission() {
+ uid_t uid = AIBinder_getCallingUid();
+ return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
+}
+
+binder_status_t DefaultVehicleHal::dump(int fd, const char** args, uint32_t numArgs) {
+ if (!checkDumpPermission()) {
+ dprintf(fd, "Caller must be root, system or shell");
+ return STATUS_PERMISSION_DENIED;
+ }
+
+ std::vector<std::string> options;
+ for (uint32_t i = 0; i < numArgs; i++) {
+ options.push_back(args[i]);
+ }
+ DumpResult result = mVehicleHardware->dump(options);
+ dprintf(fd, "%s", (result.buffer + "\n").c_str());
+ if (!result.callerShouldDumpState) {
+ dprintf(fd, "Skip dumping Vehicle HAL State.\n");
+ return STATUS_OK;
+ }
+ dprintf(fd, "Vehicle HAL State: \n");
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
+ dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
+ dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
+ dprintf(fd, "Currently have %zu subscription clients\n",
+ mSubscriptionClients->countClients());
+ }
+ return STATUS_OK;
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp b/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp
index c2d6f89..23a5403 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp
@@ -74,7 +74,7 @@
Result<void> PendingRequestPool::addRequests(const void* clientId,
const std::unordered_set<int64_t>& requestIds,
- std::shared_ptr<TimeoutCallbackFunc> callback) {
+ std::shared_ptr<const TimeoutCallbackFunc> callback) {
std::scoped_lock<std::mutex> lockGuard(mLock);
std::list<PendingRequest>* pendingRequests;
size_t pendingRequestCount = 0;
@@ -117,6 +117,18 @@
return isRequestPendingLocked(clientId, requestId);
}
+size_t PendingRequestPool::countPendingRequests() const {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ size_t count = 0;
+ for (const auto& [clientId, requests] : mPendingRequestsByClient) {
+ for (const auto& request : requests) {
+ count += request.requestIds.size();
+ }
+ }
+ return count;
+}
+
size_t PendingRequestPool::countPendingRequests(const void* clientId) const {
std::scoped_lock<std::mutex> lockGuard(mLock);
diff --git a/automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp
new file mode 100644
index 0000000..8521c4d
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 "RecurrentTimer.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <inttypes.h>
+#include <math.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::android::base::ScopedLockAssertion;
+
+RecurrentTimer::RecurrentTimer() : mThread(&RecurrentTimer::loop, this) {}
+
+RecurrentTimer::~RecurrentTimer() {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mStopRequested = true;
+ }
+ mCond.notify_one();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void RecurrentTimer::registerTimerCallback(int64_t intervalInNano,
+ std::shared_ptr<RecurrentTimer::Callback> callback) {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ // Aligns the nextTime to multiply of interval.
+ int64_t nextTime = ceil(elapsedRealtimeNano() / intervalInNano) * intervalInNano;
+
+ std::unique_ptr<CallbackInfo> info = std::make_unique<CallbackInfo>();
+ info->callback = callback;
+ info->interval = intervalInNano;
+ info->nextTime = nextTime;
+
+ auto it = mCallbacks.find(callback);
+ if (it != mCallbacks.end()) {
+ ALOGI("Replacing an existing timer callback with a new interval, current: %" PRId64
+ " ns, new: %" PRId64 " ns",
+ it->second->interval, intervalInNano);
+ markOutdatedLocked(it->second);
+ }
+ mCallbacks[callback] = info.get();
+ mCallbackQueue.push_back(std::move(info));
+ // Insert the last element into the heap.
+ std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+ }
+ mCond.notify_one();
+}
+
+void RecurrentTimer::unregisterTimerCallback(std::shared_ptr<RecurrentTimer::Callback> callback) {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ auto it = mCallbacks.find(callback);
+ if (it == mCallbacks.end()) {
+ ALOGE("No event found to unregister");
+ return;
+ }
+
+ markOutdatedLocked(it->second);
+ mCallbacks.erase(it);
+ }
+
+ mCond.notify_one();
+}
+
+void RecurrentTimer::markOutdatedLocked(RecurrentTimer::CallbackInfo* info) {
+ info->outdated = true;
+ info->callback = nullptr;
+ // Make sure the first element is always valid.
+ removeInvalidCallbackLocked();
+}
+
+void RecurrentTimer::removeInvalidCallbackLocked() {
+ while (mCallbackQueue.size() != 0 && mCallbackQueue[0]->outdated) {
+ std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+ mCallbackQueue.pop_back();
+ }
+}
+
+std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() {
+ std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+ std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]);
+ mCallbackQueue.pop_back();
+ // Make sure the first element is always valid.
+ removeInvalidCallbackLocked();
+ return info;
+}
+
+void RecurrentTimer::loop() {
+ std::unique_lock<std::mutex> uniqueLock(mLock);
+
+ while (true) {
+ // Wait until the timer exits or we have at least one recurrent callback.
+ mCond.wait(uniqueLock, [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mStopRequested || mCallbackQueue.size() != 0;
+ });
+
+ int64_t interval;
+ {
+ ScopedLockAssertion lockAssertion(mLock);
+ if (mStopRequested) {
+ return;
+ }
+ // The first element is the nearest next event.
+ int64_t nextTime = mCallbackQueue[0]->nextTime;
+ int64_t now = elapsedRealtimeNano();
+ if (nextTime > now) {
+ interval = nextTime - now;
+ } else {
+ interval = 0;
+ }
+ }
+
+ // Wait for the next event or the timer exits.
+ if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mStopRequested;
+ })) {
+ return;
+ }
+
+ {
+ ScopedLockAssertion lockAssertion(mLock);
+ int64_t now = elapsedRealtimeNano();
+ while (mCallbackQueue.size() > 0) {
+ int64_t nextTime = mCallbackQueue[0]->nextTime;
+ if (nextTime > now) {
+ break;
+ }
+
+ std::unique_ptr<CallbackInfo> info = popNextCallbackLocked();
+ info->nextTime += info->interval;
+
+ auto callback = info->callback;
+ mCallbackQueue.push_back(std::move(info));
+ std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+
+ (*callback)();
+ }
+ }
+ }
+}
+
+bool RecurrentTimer::CallbackInfo::cmp(const std::unique_ptr<RecurrentTimer::CallbackInfo>& lhs,
+ const std::unique_ptr<RecurrentTimer::CallbackInfo>& rhs) {
+ return lhs->nextTime > rhs->nextTime;
+}
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
new file mode 100644
index 0000000..21bfba6
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -0,0 +1,247 @@
+/*
+ * 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 "SubscriptionManager.h"
+
+#include <math/HashCombine.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+namespace {
+
+constexpr float ONE_SECOND_IN_NANO = 1'000'000'000.;
+
+} // namespace
+
+using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
+using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+
+bool SubscriptionManager::PropIdAreaId::operator==(const PropIdAreaId& other) const {
+ return areaId == other.areaId && propId == other.propId;
+}
+
+size_t SubscriptionManager::PropIdAreaIdHash::operator()(PropIdAreaId const& propIdAreaId) const {
+ size_t res = 0;
+ hashCombine(res, propIdAreaId.propId);
+ hashCombine(res, propIdAreaId.areaId);
+ return res;
+}
+
+SubscriptionManager::SubscriptionManager(GetValueFunc&& action)
+ : mTimer(std::make_shared<RecurrentTimer>()), mGetValue(std::move(action)) {}
+
+SubscriptionManager::~SubscriptionManager() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ mClientsByPropIdArea.clear();
+ // RecurrentSubscription has reference to mGetValue, so it must be destroyed before mGetValue is
+ // destroyed.
+ mSubscriptionsByClient.clear();
+}
+
+bool SubscriptionManager::checkSampleRate(float sampleRate) {
+ return getInterval(sampleRate).ok();
+}
+
+Result<int64_t> SubscriptionManager::getInterval(float sampleRate) {
+ int64_t interval = 0;
+ if (sampleRate <= 0) {
+ return Error() << "invalid sample rate, must be a positive number";
+ }
+ if (sampleRate <= (ONE_SECOND_IN_NANO / static_cast<float>(INT64_MAX))) {
+ return Error() << "invalid sample rate: " << sampleRate << ", too small";
+ }
+ interval = static_cast<int64_t>(ONE_SECOND_IN_NANO / sampleRate);
+ return interval;
+}
+
+Result<void> SubscriptionManager::subscribe(const std::shared_ptr<IVehicleCallback>& callback,
+ const std::vector<SubscribeOptions>& options,
+ bool isContinuousProperty) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ std::vector<int64_t> intervals;
+ for (const auto& option : options) {
+ float sampleRate = option.sampleRate;
+
+ if (isContinuousProperty) {
+ auto intervalResult = getInterval(sampleRate);
+ if (!intervalResult.ok()) {
+ return intervalResult.error();
+ }
+ intervals.push_back(intervalResult.value());
+ }
+
+ if (option.areaIds.empty()) {
+ ALOGE("area IDs to subscribe must not be empty");
+ return Error() << "area IDs to subscribe must not be empty";
+ }
+ }
+
+ size_t intervalIndex = 0;
+ ClientIdType clientId = callback->asBinder().get();
+ for (const auto& option : options) {
+ int32_t propId = option.propId;
+ const std::vector<int32_t>& areaIds = option.areaIds;
+ int64_t interval = 0;
+ if (isContinuousProperty) {
+ interval = intervals[intervalIndex];
+ intervalIndex++;
+ }
+ for (int32_t areaId : areaIds) {
+ PropIdAreaId propIdAreaId = {
+ .propId = propId,
+ .areaId = areaId,
+ };
+ if (isContinuousProperty) {
+ VehiclePropValue propValueRequest{
+ .prop = propId,
+ .areaId = areaId,
+ };
+ mSubscriptionsByClient[clientId][propIdAreaId] =
+ std::make_unique<RecurrentSubscription>(
+ mTimer,
+ [this, callback, propValueRequest] {
+ mGetValue(callback, propValueRequest);
+ },
+ interval);
+ } else {
+ mSubscriptionsByClient[clientId][propIdAreaId] =
+ std::make_unique<OnChangeSubscription>();
+ }
+ mClientsByPropIdArea[propIdAreaId][clientId] = callback;
+ }
+ }
+ return {};
+}
+
+Result<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId,
+ const std::vector<int32_t>& propIds) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ if (mSubscriptionsByClient.find(clientId) == mSubscriptionsByClient.end()) {
+ return Error() << "No property was subscribed for the callback";
+ }
+ std::unordered_set<int32_t> subscribedPropIds;
+ for (auto const& [propIdAreaId, _] : mSubscriptionsByClient[clientId]) {
+ subscribedPropIds.insert(propIdAreaId.propId);
+ }
+
+ for (int32_t propId : propIds) {
+ if (subscribedPropIds.find(propId) == subscribedPropIds.end()) {
+ return Error() << "property ID: " << propId << " is not subscribed";
+ }
+ }
+
+ auto& subscriptions = mSubscriptionsByClient[clientId];
+ auto it = subscriptions.begin();
+ while (it != subscriptions.end()) {
+ int32_t propId = it->first.propId;
+ if (std::find(propIds.begin(), propIds.end(), propId) != propIds.end()) {
+ auto& clients = mClientsByPropIdArea[it->first];
+ clients.erase(clientId);
+ if (clients.empty()) {
+ mClientsByPropIdArea.erase(it->first);
+ }
+ it = subscriptions.erase(it);
+ } else {
+ it++;
+ }
+ }
+ if (subscriptions.empty()) {
+ mSubscriptionsByClient.erase(clientId);
+ }
+ return {};
+}
+
+Result<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ if (mSubscriptionsByClient.find(clientId) == mSubscriptionsByClient.end()) {
+ return Error() << "No property was subscribed for this client";
+ }
+
+ auto& subscriptions = mSubscriptionsByClient[clientId];
+ for (auto const& [propIdAreaId, _] : subscriptions) {
+ auto& clients = mClientsByPropIdArea[propIdAreaId];
+ clients.erase(clientId);
+ if (clients.empty()) {
+ mClientsByPropIdArea.erase(propIdAreaId);
+ }
+ }
+ mSubscriptionsByClient.erase(clientId);
+ return {};
+}
+
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
+SubscriptionManager::getSubscribedClients(const std::vector<VehiclePropValue>& updatedValues) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
+ clients;
+
+ for (const auto& value : updatedValues) {
+ PropIdAreaId propIdAreaId{
+ .propId = value.prop,
+ .areaId = value.areaId,
+ };
+ if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+ continue;
+ }
+ for (const auto& [clientId, client] : mClientsByPropIdArea[propIdAreaId]) {
+ if (!mSubscriptionsByClient[clientId][propIdAreaId]->isOnChange()) {
+ continue;
+ }
+ clients[client].push_back(&value);
+ }
+ }
+ return clients;
+}
+
+bool SubscriptionManager::isEmpty() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mSubscriptionsByClient.empty() && mClientsByPropIdArea.empty();
+}
+
+SubscriptionManager::RecurrentSubscription::RecurrentSubscription(
+ std::shared_ptr<RecurrentTimer> timer, std::function<void()>&& action, int64_t interval)
+ : mAction(std::make_shared<std::function<void()>>(action)), mTimer(timer) {
+ mTimer->registerTimerCallback(interval, mAction);
+}
+
+SubscriptionManager::RecurrentSubscription::~RecurrentSubscription() {
+ mTimer->unregisterTimerCallback(mAction);
+}
+
+bool SubscriptionManager::RecurrentSubscription::isOnChange() {
+ return false;
+}
+
+bool SubscriptionManager::OnChangeSubscription::isOnChange() {
+ return true;
+}
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp
index ddd0c65..bdb0d31 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp
@@ -39,12 +39,17 @@
void SetUp() override {
mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
mCallbackClient = IVehicleCallback::fromBinder(mCallback->asBinder());
+ // timeout: 1s.
+ int64_t timeout = 1000000000;
+ mPool = std::make_shared<PendingRequestPool>(timeout);
}
std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
MockVehicleCallback* getCallback() { return mCallback.get(); }
+ std::shared_ptr<PendingRequestPool> getPool() { return mPool; }
+
protected:
using GetValuesClient = GetSetValuesClient<GetValueResult, GetValueResults>;
using SetValuesClient = GetSetValuesClient<SetValueResult, SetValueResults>;
@@ -52,6 +57,7 @@
private:
std::shared_ptr<MockVehicleCallback> mCallback;
std::shared_ptr<IVehicleCallback> mCallbackClient;
+ std::shared_ptr<PendingRequestPool> mPool;
};
TEST_F(ConnectedClientTest, testSendGetValueResults) {
@@ -72,9 +78,10 @@
},
}};
- GetValuesClient client(getCallbackClient());
+ GetValuesClient client(getPool(), getCallbackClient());
- client.sendResults(results);
+ auto resultsCopy = results;
+ client.sendResults(std::move(resultsCopy));
auto maybeGetValueResults = getCallback()->nextGetValueResults();
ASSERT_TRUE(maybeGetValueResults.has_value());
@@ -99,7 +106,7 @@
},
}};
- GetValuesClient client(getCallbackClient());
+ GetValuesClient client(getPool(), getCallbackClient());
client.sendResultsSeparately(results);
@@ -131,7 +138,9 @@
},
}};
- GetValuesClient client(getCallbackClient());
+ GetValuesClient client(getPool(), getCallbackClient());
+
+ client.addRequests({0, 1});
(*(client.getResultCallback()))(results);
@@ -150,9 +159,10 @@
.status = StatusCode::OK,
}};
- SetValuesClient client(getCallbackClient());
+ SetValuesClient client(getPool(), getCallbackClient());
- client.sendResults(results);
+ auto resultsCopy = results;
+ client.sendResults(std::move(resultsCopy));
auto maybeSetValueResults = getCallback()->nextSetValueResults();
ASSERT_TRUE(maybeSetValueResults.has_value());
@@ -169,7 +179,7 @@
.status = StatusCode::OK,
}};
- SetValuesClient client(getCallbackClient());
+ SetValuesClient client(getPool(), getCallbackClient());
client.sendResultsSeparately(results);
@@ -193,7 +203,9 @@
.status = StatusCode::OK,
}};
- SetValuesClient client(getCallbackClient());
+ SetValuesClient client(getPool(), getCallbackClient());
+
+ client.addRequests({0, 1});
(*(client.getResultCallback()))(results);
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index ffc08a7..7443d5b 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#include "ConnectedClient.h"
#include "DefaultVehicleHal.h"
#include "MockVehicleCallback.h"
+#include "MockVehicleHardware.h"
#include <IVehicleHardware.h>
#include <LargeParcelableBase.h>
@@ -25,8 +27,11 @@
#include <android-base/thread_annotations.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <sys/mman.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
+#include <chrono>
#include <list>
#include <memory>
#include <mutex>
@@ -53,10 +58,14 @@
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
@@ -65,207 +74,35 @@
using ::ndk::ScopedAStatus;
using ::ndk::ScopedFileDescriptor;
+using ::ndk::SpAIBinder;
+using ::testing::ContainsRegex;
using ::testing::Eq;
+using ::testing::UnorderedElementsAre;
+using ::testing::UnorderedElementsAreArray;
using ::testing::WhenSortedBy;
constexpr int32_t INVALID_PROP_ID = 0;
// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x10000000 + 0x03000000 + 0x00400000;
-
-template <class T>
-std::optional<T> pop(std::list<T>& items) {
- if (items.size() > 0) {
- auto item = std::move(items.front());
- items.pop_front();
- return item;
- }
- return std::nullopt;
-}
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t READ_ONLY_PROP = 10006 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x10000000 + 0x01000000 + 0x00400000;
int32_t testInt32VecProp(size_t i) {
// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
return static_cast<int32_t>(i) + 0x10000000 + 0x01000000 + 0x00410000;
}
-class MockVehicleHardware final : public IVehicleHardware {
- public:
- ~MockVehicleHardware() {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- for (auto& thread : mThreads) {
- thread.join();
- }
- }
-
- std::vector<VehiclePropConfig> getAllPropertyConfigs() const override {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- return mPropertyConfigs;
- }
-
- StatusCode setValues(std::shared_ptr<const SetValuesCallback> callback,
- const std::vector<SetValueRequest>& requests) override {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- return handleRequests(__func__, callback, requests, &mSetValueRequests,
- &mSetValueResponses);
- }
-
- StatusCode getValues(std::shared_ptr<const GetValuesCallback> callback,
- const std::vector<GetValueRequest>& requests) const override {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- return handleRequests(__func__, callback, requests, &mGetValueRequests,
- &mGetValueResponses);
- }
-
- DumpResult dump(const std::vector<std::string>&) override {
- // TODO(b/200737967): mock this.
- return DumpResult{};
- }
-
- StatusCode checkHealth() override {
- // TODO(b/200737967): mock this.
- return StatusCode::OK;
- }
-
- void registerOnPropertyChangeEvent(std::unique_ptr<const PropertyChangeCallback>) override {
- // TODO(b/200737967): mock this.
- }
-
- void registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback>) override {
- // TODO(b/200737967): mock this.
- }
-
- // Test functions.
- void setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- mPropertyConfigs = configs;
- }
-
- void addGetValueResponses(const std::vector<GetValueResult>& responses) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- mGetValueResponses.push_back(responses);
- }
-
- void addSetValueResponses(const std::vector<SetValueResult>& responses) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- mSetValueResponses.push_back(responses);
- }
-
- std::vector<GetValueRequest> nextGetValueRequests() {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
- if (!request.has_value()) {
- return std::vector<GetValueRequest>();
- }
- return std::move(request.value());
- }
-
- std::vector<SetValueRequest> nextSetValueRequests() {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
- if (!request.has_value()) {
- return std::vector<SetValueRequest>();
- }
- return std::move(request.value());
- }
-
- void setStatus(const char* functionName, StatusCode status) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- mStatusByFunctions[functionName] = status;
- }
-
- void setSleepTime(int64_t timeInNano) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- mSleepTime = timeInNano;
- }
-
- private:
- mutable std::mutex mLock;
- std::vector<VehiclePropConfig> mPropertyConfigs GUARDED_BY(mLock);
- mutable std::list<std::vector<GetValueRequest>> mGetValueRequests GUARDED_BY(mLock);
- mutable std::list<std::vector<GetValueResult>> mGetValueResponses GUARDED_BY(mLock);
- mutable std::list<std::vector<SetValueRequest>> mSetValueRequests GUARDED_BY(mLock);
- mutable std::list<std::vector<SetValueResult>> mSetValueResponses GUARDED_BY(mLock);
- std::unordered_map<const char*, StatusCode> mStatusByFunctions GUARDED_BY(mLock);
- int64_t mSleepTime GUARDED_BY(mLock) = 0;
- mutable std::vector<std::thread> mThreads GUARDED_BY(mLock);
-
- template <class ResultType>
- StatusCode returnResponse(
- std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
- std::list<std::vector<ResultType>>* storedResponses) const;
-
- template <class RequestType, class ResultType>
- StatusCode handleRequests(
- const char* functionName,
- std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
- const std::vector<RequestType>& requests,
- std::list<std::vector<RequestType>>* storedRequests,
- std::list<std::vector<ResultType>>* storedResponses) const REQUIRES(mLock);
-};
-
-template <class ResultType>
-StatusCode MockVehicleHardware::returnResponse(
- std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
- std::list<std::vector<ResultType>>* storedResponses) const {
- if (storedResponses->size() > 0) {
- (*callback)(std::move(storedResponses->front()));
- storedResponses->pop_front();
- return StatusCode::OK;
- } else {
- ALOGE("no more response");
- return StatusCode::INTERNAL_ERROR;
- }
-}
-
-template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
- std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
- std::list<std::vector<GetValueResult>>* storedResponses) const;
-
-template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
- std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
- std::list<std::vector<SetValueResult>>* storedResponses) const;
-
-template <class RequestType, class ResultType>
-StatusCode MockVehicleHardware::handleRequests(
- const char* functionName,
- std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
- const std::vector<RequestType>& requests,
- std::list<std::vector<RequestType>>* storedRequests,
- std::list<std::vector<ResultType>>* storedResponses) const {
- storedRequests->push_back(requests);
- if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
- if (StatusCode status = it->second; status != StatusCode::OK) {
- return status;
- }
- }
-
- if (mSleepTime != 0) {
- int64_t sleepTime = mSleepTime;
- mThreads.emplace_back([this, callback, sleepTime, storedResponses]() {
- std::this_thread::sleep_for(std::chrono::nanoseconds(sleepTime));
- returnResponse(callback, storedResponses);
- });
- return StatusCode::OK;
-
- } else {
- return returnResponse(callback, storedResponses);
- }
-}
-
-template StatusCode MockVehicleHardware::handleRequests<GetValueRequest, GetValueResult>(
- const char* functionName,
- std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
- const std::vector<GetValueRequest>& requests,
- std::list<std::vector<GetValueRequest>>* storedRequests,
- std::list<std::vector<GetValueResult>>* storedResponses) const;
-
-template StatusCode MockVehicleHardware::handleRequests<SetValueRequest, SetValueResult>(
- const char* functionName,
- std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
- const std::vector<SetValueRequest>& requests,
- std::list<std::vector<SetValueRequest>>* storedRequests,
- std::list<std::vector<SetValueResult>>* storedResponses) const;
-
struct PropConfigCmp {
bool operator()(const VehiclePropConfig& a, const VehiclePropConfig& b) const {
return (a.prop < b.prop);
@@ -318,6 +155,62 @@
.areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
},
.expectedStatus = StatusCode::INVALID_ARG,
+ },
+ {
+ .name = "no_write_permission",
+ .request =
+ {
+ .prop = READ_ONLY_PROP,
+ .value.int32Values = {0},
+ },
+ .expectedStatus = StatusCode::ACCESS_DENIED,
+ }};
+}
+
+struct SubscribeInvalidOptionsTestCase {
+ std::string name;
+ SubscribeOptions option;
+};
+
+std::vector<SubscribeInvalidOptionsTestCase> getSubscribeInvalidOptionsTestCases() {
+ return {{
+ .name = "invalid_prop",
+ .option =
+ {
+ .propId = INVALID_PROP_ID,
+ },
+ },
+ {
+ .name = "invalid_area_ID",
+ .option =
+ {
+ .propId = AREA_ON_CHANGE_PROP,
+ .areaIds = {0},
+ },
+ },
+ {
+ .name = "invalid_sample_rate",
+ .option =
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 0.0,
+ },
+ },
+ {
+ .name = "sample_rate_out_of_range",
+ .option =
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 1000.0,
+ },
+ },
+ {
+ .name = "static_property",
+ .option =
+ {
+ // Default change mode is static.
+ .propId = testInt32VecProp(0),
+ },
}};
}
@@ -331,6 +224,7 @@
for (size_t i = 0; i < 10000; i++) {
testConfigs.push_back(VehiclePropConfig{
.prop = testInt32VecProp(i),
+ .access = VehiclePropertyAccess::READ_WRITE,
.areaConfigs =
{
{
@@ -341,19 +235,109 @@
},
});
}
+ // A property with area config.
testConfigs.push_back(
VehiclePropConfig{.prop = INT32_WINDOW_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
.areaConfigs = {{
.areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
.minInt32Value = 0,
.maxInt32Value = 100,
}}});
+ // A global on-change property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = GLOBAL_ON_CHANGE_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ });
+ // A global continuous property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 100.0,
+ });
+ // A per-area on-change property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = AREA_ON_CHANGE_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {
+ {
+
+ .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ {
+ .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ },
+ });
+ // A per-area continuous property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = AREA_CONTINUOUS_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 1000.0,
+ .areaConfigs =
+ {
+ {
+
+ .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ {
+ .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ },
+ });
+ // A read-only property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = READ_ONLY_PROP,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 1000.0,
+ });
+ // A write-only property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = WRITE_ONLY_PROP,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 1000.0,
+ });
+ // Register the heartbeat event property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ });
hardware->setPropertyConfigs(testConfigs);
mHardwarePtr = hardware.get();
mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
- mCallbackClient = IVehicleCallback::fromBinder(mCallback->asBinder());
+ // Keep the local binder alive.
+ mBinder = mCallback->asBinder();
+ mCallbackClient = IVehicleCallback::fromBinder(mBinder);
+
+ // Set the linkToDeath to a fake implementation that always returns OK.
+ setTestLinkToDeathImpl();
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(countPendingRequests(), static_cast<size_t>(0))
+ << "must have no pending requests when test finishes";
}
MockVehicleHardware* getHardware() { return mHardwarePtr; }
@@ -364,6 +348,38 @@
MockVehicleCallback* getCallback() { return mCallback.get(); }
+ void setTimeout(int64_t timeoutInNano) { mVhal->setTimeout(timeoutInNano); }
+
+ void setTestLinkToDeathImpl() {
+ mVhal->setLinkToDeathImpl(std::make_unique<TestLinkToDeathImpl>());
+ }
+
+ size_t countPendingRequests() { return mVhal->mPendingRequestPool->countPendingRequests(); }
+
+ size_t countClients() {
+ std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+ return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size() +
+ mVhal->mSubscriptionClients->countClients();
+ }
+
+ std::shared_ptr<PendingRequestPool> getPool() { return mVhal->mPendingRequestPool; }
+
+ void onBinderDied(void* cookie) { return mVhal->onBinderDied(cookie); }
+
+ void onBinderUnlinked(void* cookie) { return mVhal->onBinderUnlinked(cookie); }
+
+ void* getOnBinderDiedContexts(AIBinder* clientId) {
+ std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+ return mVhal->mOnBinderDiedContexts[clientId].get();
+ }
+
+ size_t countOnBinderDiedContexts() {
+ std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+ return mVhal->mOnBinderDiedContexts.size();
+ }
+
+ bool hasNoSubscriptions() { return mVhal->mSubscriptionManager->isEmpty(); }
+
static Result<void> getValuesTestCases(size_t size, GetValueRequests& requests,
std::vector<GetValueResult>& expectedResults,
std::vector<GetValueRequest>& expectedHardwareRequests) {
@@ -430,21 +446,25 @@
if (result.value() != nullptr) {
requests.payloads.clear();
requests.sharedMemoryFd = std::move(*result.value());
+ requests.payloads.clear();
}
return {};
}
- size_t countClients() {
- std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
- return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size();
- }
-
private:
std::shared_ptr<DefaultVehicleHal> mVhal;
std::shared_ptr<IVehicle> mVhalClient;
MockVehicleHardware* mHardwarePtr;
std::shared_ptr<MockVehicleCallback> mCallback;
std::shared_ptr<IVehicleCallback> mCallbackClient;
+ SpAIBinder mBinder;
+
+ class TestLinkToDeathImpl final : public DefaultVehicleHal::ILinkToDeath {
+ public:
+ binder_status_t linkToDeath(AIBinder*, AIBinder_DeathRecipient*, void*) override {
+ return STATUS_OK;
+ }
+ };
};
TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
@@ -570,6 +590,178 @@
ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
}
+TEST_F(DefaultVehicleHalTest, testGetValuesNoReadPermission) {
+ GetValueRequests requests = {
+ .sharedMemoryFd = {},
+ .payloads =
+ {
+ {
+ .requestId = 0,
+ .prop =
+ {
+ .prop = WRITE_ONLY_PROP,
+ },
+ },
+ },
+ };
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValue with no read permission should return okay with error "
+ "returned from callback"
+ << ", error: " << status.getMessage();
+ EXPECT_TRUE(getHardware()->nextGetValueRequests().empty()) << "expect no request to hardware";
+
+ auto maybeResult = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeResult.has_value()) << "no results in callback";
+ EXPECT_EQ(maybeResult.value().payloads, std::vector<GetValueResult>({
+ {
+ .requestId = 0,
+ .status = StatusCode::ACCESS_DENIED,
+ },
+ }))
+ << "expect to get ACCESS_DENIED status if no read permission";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesFinishBeforeTimeout) {
+ // timeout: 0.1s
+ int64_t timeout = 100000000;
+ setTimeout(timeout);
+
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ // The response would be returned after 0.05s.
+ getHardware()->setSleepTime(timeout / 2);
+ getHardware()->addGetValueResponses(expectedResults);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ // Wait for the response.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
+
+ auto maybeGetValueResults = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+ EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
+ ASSERT_FALSE(getCallback()->nextGetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesFinishAfterTimeout) {
+ // timeout: 0.1s
+ int64_t timeout = 100000000;
+ setTimeout(timeout);
+
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ // The response would be returned after 0.2s.
+ getHardware()->setSleepTime(timeout * 2);
+ getHardware()->addGetValueResponses(expectedResults);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ // Wait for the response.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+
+ for (size_t i = 0; i < expectedResults.size(); i++) {
+ expectedResults[i] = {
+ .requestId = expectedResults[i].requestId,
+ .status = StatusCode::TRY_AGAIN,
+ .prop = std::nullopt,
+ };
+ }
+
+ auto maybeGetValueResults = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeGetValueResults.value().payloads, UnorderedElementsAreArray(expectedResults))
+ << "results mismatch, expect TRY_AGAIN error.";
+ ASSERT_FALSE(getCallback()->nextGetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestIdsInTwoRequests) {
+ // timeout: 0.1s
+ int64_t timeout = 100000000;
+ setTimeout(timeout);
+
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->setSleepTime(timeout * 2);
+ getHardware()->addGetValueResponses(expectedResults);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ // Use the same request ID again.
+ status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk())
+ << "Use the same request ID before the previous request finishes must fail";
+
+ // Wait for the request to finish.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestIdsInOneRequest) {
+ GetValueRequests requests = {.payloads = {
+ {
+ .requestId = 0,
+ .prop =
+ VehiclePropValue{
+ .prop = testInt32VecProp(0),
+ },
+ },
+ {
+ .requestId = 0,
+ .prop =
+ VehiclePropValue{
+ .prop = testInt32VecProp(1),
+ },
+ },
+ }};
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "duplicate Ids in one request must fail";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestProps) {
+ GetValueRequests requests = {.payloads = {
+ {
+ .requestId = 0,
+ .prop =
+ VehiclePropValue{
+ .prop = testInt32VecProp(0),
+ },
+ },
+ {
+ .requestId = 1,
+ .prop =
+ VehiclePropValue{
+ .prop = testInt32VecProp(0),
+ },
+ },
+ }};
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
+}
+
TEST_F(DefaultVehicleHalTest, testSetValuesSmall) {
SetValueRequests requests;
std::vector<SetValueResult> expectedResults;
@@ -675,6 +867,725 @@
<< "results from hardware mismatch";
}
+TEST_F(DefaultVehicleHalTest, testSetValuesFinishBeforeTimeout) {
+ // timeout: 0.1s
+ int64_t timeout = 100000000;
+ setTimeout(timeout);
+
+ SetValueRequests requests;
+ std::vector<SetValueResult> expectedResults;
+ std::vector<SetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ // The response would be returned after 0.05s.
+ getHardware()->setSleepTime(timeout / 2);
+ getHardware()->addSetValueResponses(expectedResults);
+
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ // Wait for the response.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
+
+ auto maybeSetValueResults = getCallback()->nextSetValueResults();
+ ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+ EXPECT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
+ ASSERT_FALSE(getCallback()->nextSetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesFinishAfterTimeout) {
+ // timeout: 0.1s
+ int64_t timeout = 100000000;
+ setTimeout(timeout);
+
+ SetValueRequests requests;
+ std::vector<SetValueResult> expectedResults;
+ std::vector<SetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ // The response would be returned after 0.2s.
+ getHardware()->setSleepTime(timeout * 2);
+ getHardware()->addSetValueResponses(expectedResults);
+
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ // Wait for the response.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+
+ for (size_t i = 0; i < expectedResults.size(); i++) {
+ expectedResults[i] = {
+ .requestId = expectedResults[i].requestId,
+ .status = StatusCode::TRY_AGAIN,
+ };
+ }
+
+ auto maybeSetValueResults = getCallback()->nextSetValueResults();
+ ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeSetValueResults.value().payloads, UnorderedElementsAreArray(expectedResults))
+ << "results mismatch, expect TRY_AGAIN error.";
+ ASSERT_FALSE(getCallback()->nextSetValueResults().has_value()) << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestIdsInTwoRequests) {
+ // timeout: 0.1s
+ int64_t timeout = 100000000;
+ setTimeout(timeout);
+
+ SetValueRequests requests;
+ std::vector<SetValueResult> expectedResults;
+ std::vector<SetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(setValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->setSleepTime(timeout * 2);
+ getHardware()->addSetValueResponses(expectedResults);
+
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ // Use the same request ID again.
+ status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk())
+ << "Use the same request ID before the previous request finishes must fail";
+
+ // Wait for the request to finish.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestIdsInOneRequest) {
+ SetValueRequests requests = {.payloads = {
+ {
+ .requestId = 0,
+ .value =
+ VehiclePropValue{
+ .prop = testInt32VecProp(0),
+ .value.int32Values = {0},
+ },
+ },
+ {
+ .requestId = 0,
+ .value =
+ VehiclePropValue{
+ .prop = testInt32VecProp(1),
+ .value.int32Values = {0},
+ },
+ },
+ }};
+
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "duplicate Ids in one request must fail";
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestProps) {
+ SetValueRequests requests = {.payloads = {
+ {
+ .requestId = 0,
+ .value =
+ VehiclePropValue{
+ .prop = testInt32VecProp(0),
+ .value.int32Values = {0},
+ },
+ },
+ {
+ .requestId = 1,
+ .value =
+ VehiclePropValue{
+ .prop = testInt32VecProp(0),
+ .value.int32Values = {0},
+ },
+ },
+ }};
+
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeUnsubscribe) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+ ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnChangeNormal) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = GLOBAL_ON_CHANGE_PROP,
+ .value.int32Values = {0},
+ };
+ SetValueRequests setValueRequests = {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ };
+ std::vector<SetValueResult> setValueResults = {{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }};
+
+ // Set the value to trigger a property change event.
+ getHardware()->addSetValueResponses(setValueResults);
+ status = getClient()->setValues(getCallbackClient(), setValueRequests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+ << "results mismatch, expect on change event for the updated value";
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "more results than expected";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnchangeUnrelatedEventIgnored) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .value.int32Values = {0},
+ };
+
+ // Set the value to trigger a property change event. This event should be ignored because we
+ // have not subscribed to it.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "must receive no property update event if the property is not subscribed";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChange) {
+ int testAreaId = toInt(VehicleAreaWindow::ROW_1_LEFT);
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = AREA_ON_CHANGE_PROP,
+ .areaIds = {testAreaId},
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = AREA_ON_CHANGE_PROP,
+ .areaId = testAreaId,
+ .value.int32Values = {0},
+ };
+
+ // Set the value to trigger a property change event.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+ << "results mismatch, expect on change event for the updated value";
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChangeAllAreas) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = AREA_ON_CHANGE_PROP,
+ // No areaIds means subscribing to all area IDs.
+ .areaIds = {},
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue1{
+ .prop = AREA_ON_CHANGE_PROP,
+ .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+ .value.int32Values = {0},
+ };
+ VehiclePropValue testValue2{
+ .prop = AREA_ON_CHANGE_PROP,
+ .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+ .value.int32Values = {0},
+ };
+
+ // Set the values to trigger property change events for two areas.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ },
+ {
+ .requestId = 1,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue1,
+ },
+ SetValueRequest{
+ .requestId = 1,
+ .value = testValue2,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue1, testValue2))
+ << "results mismatch, expect two on-change events for all updated areas";
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuous) {
+ VehiclePropValue testValue{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .value.int32Values = {0},
+ };
+ // Set responses for all the hardware getValues requests.
+ getHardware()->setGetValueResponder(
+ [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ VehiclePropValue prop = request.prop;
+ prop.value.int32Values = {0};
+ results.push_back({
+ .requestId = request.requestId,
+ .status = StatusCode::OK,
+ .prop = prop,
+ });
+ }
+ (*callback)(results);
+ return StatusCode::OK;
+ });
+
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 20.0,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ // Sleep for 1s, which should generate ~20 events.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // Should trigger about 20 times, check for at least 15 events to be safe.
+ for (size_t i = 0; i < 15; i++) {
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+ << "results mismatch, expect to get the updated value";
+ }
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaContinuous) {
+ // Set responses for all the hardware getValues requests.
+ getHardware()->setGetValueResponder(
+ [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ VehiclePropValue prop = request.prop;
+ prop.value.int32Values = {0};
+ results.push_back({
+ .requestId = request.requestId,
+ .status = StatusCode::OK,
+ .prop = prop,
+ });
+ }
+ (*callback)(results);
+ return StatusCode::OK;
+ });
+
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = AREA_CONTINUOUS_PROP,
+ .sampleRate = 20.0,
+ .areaIds = {toInt(VehicleAreaWindow::ROW_1_LEFT)},
+ },
+ {
+ .propId = AREA_CONTINUOUS_PROP,
+ .sampleRate = 10.0,
+ .areaIds = {toInt(VehicleAreaWindow::ROW_1_RIGHT)},
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ // Sleep for 1s, which should generate ~20 events.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ std::vector<VehiclePropValue> events;
+ while (true) {
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ if (!maybeResults.has_value()) {
+ break;
+ }
+ for (const auto& value : maybeResults.value().payloads) {
+ events.push_back(value);
+ }
+ }
+
+ size_t leftCount = 0;
+ size_t rightCount = 0;
+
+ for (const auto& event : events) {
+ ASSERT_EQ(event.prop, AREA_CONTINUOUS_PROP);
+ if (event.areaId == toInt(VehicleAreaWindow::ROW_1_LEFT)) {
+ leftCount++;
+ continue;
+ }
+ rightCount++;
+ }
+
+ // Should trigger about 20 times, check for at least 15 events to be safe.
+ ASSERT_GE(leftCount, static_cast<size_t>(15));
+ // Should trigger about 10 times, check for at least 5 events to be safe.
+ ASSERT_GE(rightCount, static_cast<size_t>(5));
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeOnChange) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+ ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = GLOBAL_ON_CHANGE_PROP,
+ .value.int32Values = {0},
+ };
+
+ // Set the value to trigger a property change event.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "No property event should be generated after unsubscription";
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeContinuous) {
+ VehiclePropValue testValue{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .value.int32Values = {0},
+ };
+ // Set responses for all the hardware getValues requests.
+ getHardware()->setGetValueResponder(
+ [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ VehiclePropValue prop = request.prop;
+ prop.value.int32Values = {0};
+ results.push_back({
+ .requestId = request.requestId,
+ .status = StatusCode::OK,
+ .prop = prop,
+ });
+ }
+ (*callback)(results);
+ return StatusCode::OK;
+ });
+
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 20.0,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_CONTINUOUS_PROP}));
+
+ ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+
+ // Clear existing events.
+ while (getCallback()->nextOnPropertyEventResults().has_value()) {
+ // Do nothing.
+ }
+
+ // Wait for a while, make sure no new events are generated.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "No property event should be generated after unsubscription";
+}
+
+class SubscribeInvalidOptionsTest
+ : public DefaultVehicleHalTest,
+ public testing::WithParamInterface<SubscribeInvalidOptionsTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+ SubscribeInvalidOptionsTests, SubscribeInvalidOptionsTest,
+ ::testing::ValuesIn(getSubscribeInvalidOptionsTestCases()),
+ [](const testing::TestParamInfo<SubscribeInvalidOptionsTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(SubscribeInvalidOptionsTest, testSubscribeInvalidOptions) {
+ std::vector<SubscribeOptions> options = {GetParam().option};
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_FALSE(status.isOk()) << "invalid subscribe options must fail";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeNoReadPermission) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = WRITE_ONLY_PROP,
+ }};
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_FALSE(status.isOk()) << "subscribe to a write-only property must fail";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeFailure) {
+ auto status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+ ASSERT_FALSE(status.isOk()) << "unsubscribe to a not-subscribed property must fail";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testHeartbeatEvent) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = toInt(VehicleProperty::VHAL_HEARTBEAT),
+ }};
+ int64_t currentTime = uptimeMillis();
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "unable to subscribe to heartbeat event: " << status.getMessage();
+
+ // We send out a heartbeat event every 3s, so sleep for 3s.
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_EQ(maybeResults.value().payloads.size(), static_cast<size_t>(1));
+ VehiclePropValue gotValue = maybeResults.value().payloads[0];
+ ASSERT_EQ(gotValue.prop, toInt(VehicleProperty::VHAL_HEARTBEAT));
+ ASSERT_EQ(gotValue.value.int64Values.size(), static_cast<size_t>(1));
+ ASSERT_GE(gotValue.value.int64Values[0], currentTime)
+ << "expect to get the latest timestamp with the heartbeat event";
+}
+
+TEST_F(DefaultVehicleHalTest, testOnBinderDiedUnlinked) {
+ // First subscribe to a continuous property so that we register a death recipient for our
+ // client.
+ VehiclePropValue testValue{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .value.int32Values = {0},
+ };
+ // Set responses for all the hardware getValues requests.
+ getHardware()->setGetValueResponder(
+ [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ VehiclePropValue prop = request.prop;
+ prop.value.int32Values = {0};
+ results.push_back({
+ .requestId = request.requestId,
+ .status = StatusCode::OK,
+ .prop = prop,
+ });
+ }
+ (*callback)(results);
+ return StatusCode::OK;
+ });
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 20.0,
+ },
+ };
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+ // Sleep for 100ms so that the subscriptionClient gets created because we would at least try to
+ // get value once.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ // Issue another getValue request on the same client.
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+ ASSERT_TRUE(getValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
+ getHardware()->addGetValueResponses(expectedResults);
+ status = getClient()->getValues(getCallbackClient(), requests);
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(1))
+ << "expect one OnBinderDied context when one client is registered";
+
+ // Get the death recipient cookie for our callback that would be used in onBinderDied and
+ // onBinderUnlinked.
+ AIBinder* clientId = getCallbackClient()->asBinder().get();
+ void* context = getOnBinderDiedContexts(clientId);
+
+ onBinderDied(context);
+
+ ASSERT_EQ(countClients(), static_cast<size_t>(0))
+ << "expect all clients to be removed when binder died";
+ ASSERT_TRUE(hasNoSubscriptions()) << "expect no subscriptions when binder died";
+
+ onBinderUnlinked(context);
+
+ ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(0))
+ << "expect OnBinderDied context to be deleted when binder is unlinked";
+}
+
+TEST_F(DefaultVehicleHalTest, testDumpCallerShouldDump) {
+ std::string buffer = "Dump from hardware";
+ getHardware()->setDumpResult({
+ .callerShouldDumpState = true,
+ .buffer = buffer,
+ });
+ int fd = memfd_create("memfile", 0);
+ getClient()->dump(fd, nullptr, 0);
+
+ lseek(fd, 0, SEEK_SET);
+ char buf[10240] = {};
+ read(fd, buf, sizeof(buf));
+ close(fd);
+
+ std::string msg(buf);
+
+ ASSERT_THAT(msg, ContainsRegex(buffer + "\nVehicle HAL State: \n"));
+}
+
+TEST_F(DefaultVehicleHalTest, testDumpCallerShouldNotDump) {
+ std::string buffer = "Dump from hardware";
+ getHardware()->setDumpResult({
+ .callerShouldDumpState = false,
+ .buffer = buffer,
+ });
+ int fd = memfd_create("memfile", 0);
+ getClient()->dump(fd, nullptr, 0);
+
+ lseek(fd, 0, SEEK_SET);
+ char buf[10240] = {};
+ read(fd, buf, sizeof(buf));
+ close(fd);
+
+ std::string msg(buf);
+
+ ASSERT_THAT(msg, ContainsRegex(buffer));
+ ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index ca366cd..5e3e03c 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -31,16 +31,6 @@
using ::ndk::ScopedFileDescriptor;
template <class T>
-std::optional<T> pop(std::list<T>& items) {
- if (items.size() > 0) {
- auto item = std::move(items.front());
- items.pop_front();
- return item;
- }
- return std::nullopt;
-}
-
-template <class T>
static ScopedAStatus storeResults(const T& results, std::list<T>* storedResults) {
T resultsCopy{
.payloads = results.payloads,
@@ -65,8 +55,12 @@
return storeResults(results, &mSetValueResults);
}
-ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues&, int32_t) {
- return ScopedAStatus::ok();
+ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues& results,
+ int32_t sharedMemoryFileCount) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ mSharedMemoryFileCount = sharedMemoryFileCount;
+ return storeResults(results, &mOnPropertyEventResults);
}
ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
@@ -83,6 +77,11 @@
return pop(mSetValueResults);
}
+std::optional<VehiclePropValues> MockVehicleCallback::nextOnPropertyEventResults() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return pop(mOnPropertyEventResults);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index 916575a..c83164f 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -31,6 +31,16 @@
namespace automotive {
namespace vehicle {
+template <class T>
+std::optional<T> pop(std::list<T>& items) {
+ if (items.size() > 0) {
+ auto item = std::move(items.front());
+ items.pop_front();
+ return item;
+ }
+ return std::nullopt;
+}
+
// MockVehicleCallback is a mock VehicleCallback implementation that simply stores the results.
class MockVehicleCallback final
: public ::aidl::android::hardware::automotive::vehicle::BnVehicleCallback {
@@ -52,6 +62,8 @@
nextGetValueResults();
std::optional<::aidl::android::hardware::automotive::vehicle::SetValueResults>
nextSetValueResults();
+ std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValues>
+ nextOnPropertyEventResults();
private:
std::mutex mLock;
@@ -59,6 +71,9 @@
GUARDED_BY(mLock);
std::list<::aidl::android::hardware::automotive::vehicle::SetValueResults> mSetValueResults
GUARDED_BY(mLock);
+ std::list<::aidl::android::hardware::automotive::vehicle::VehiclePropValues>
+ mOnPropertyEventResults GUARDED_BY(mLock);
+ int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
new file mode 100644
index 0000000..66aef7c
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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 "MockVehicleHardware.h"
+#include "MockVehicleCallback.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+MockVehicleHardware::~MockVehicleHardware() {
+ std::unique_lock<std::mutex> lk(mLock);
+ mCv.wait(lk, [this] { return mThreadCount == 0; });
+}
+
+std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mPropertyConfigs;
+}
+
+StatusCode MockVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
+ const std::vector<SetValueRequest>& requests) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (StatusCode status = handleRequestsLocked(__func__, callback, requests, &mSetValueRequests,
+ &mSetValueResponses);
+ status != StatusCode::OK) {
+ return status;
+ }
+ if (mPropertyChangeCallback == nullptr) {
+ return StatusCode::OK;
+ }
+ std::vector<VehiclePropValue> values;
+ for (auto& request : requests) {
+ values.push_back(request.value);
+ }
+ (*mPropertyChangeCallback)(values);
+ return StatusCode::OK;
+}
+
+StatusCode MockVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) const {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mGetValueResponder != nullptr) {
+ return mGetValueResponder(callback, requests);
+ }
+ return handleRequestsLocked(__func__, callback, requests, &mGetValueRequests,
+ &mGetValueResponses);
+}
+
+void MockVehicleHardware::setDumpResult(DumpResult result) {
+ mDumpResult = result;
+}
+
+DumpResult MockVehicleHardware::dump(const std::vector<std::string>&) {
+ return mDumpResult;
+}
+
+StatusCode MockVehicleHardware::checkHealth() {
+ return StatusCode::OK;
+}
+
+void MockVehicleHardware::registerOnPropertyChangeEvent(
+ std::unique_ptr<const PropertyChangeCallback> callback) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mPropertyChangeCallback = std::move(callback);
+}
+
+void MockVehicleHardware::registerOnPropertySetErrorEvent(
+ std::unique_ptr<const PropertySetErrorCallback>) {
+ // TODO(b/200737967): mock this.
+}
+
+void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mPropertyConfigs = configs;
+}
+
+void MockVehicleHardware::addGetValueResponses(const std::vector<GetValueResult>& responses) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mGetValueResponses.push_back(responses);
+}
+
+void MockVehicleHardware::addSetValueResponses(const std::vector<SetValueResult>& responses) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mSetValueResponses.push_back(responses);
+}
+
+void MockVehicleHardware::setGetValueResponder(
+ std::function<StatusCode(std::shared_ptr<const GetValuesCallback>,
+ const std::vector<GetValueRequest>&)>&& responder) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mGetValueResponder = responder;
+}
+
+std::vector<GetValueRequest> MockVehicleHardware::nextGetValueRequests() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
+ if (!request.has_value()) {
+ return std::vector<GetValueRequest>();
+ }
+ return std::move(request.value());
+}
+
+std::vector<SetValueRequest> MockVehicleHardware::nextSetValueRequests() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
+ if (!request.has_value()) {
+ return std::vector<SetValueRequest>();
+ }
+ return std::move(request.value());
+}
+
+void MockVehicleHardware::setStatus(const char* functionName, StatusCode status) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mStatusByFunctions[functionName] = status;
+}
+
+void MockVehicleHardware::setSleepTime(int64_t timeInNano) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mSleepTime = timeInNano;
+}
+
+template <class ResultType>
+StatusCode MockVehicleHardware::returnResponse(
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ std::list<std::vector<ResultType>>* storedResponses) const {
+ if (storedResponses->size() > 0) {
+ (*callback)(std::move(storedResponses->front()));
+ storedResponses->pop_front();
+ return StatusCode::OK;
+ } else {
+ ALOGE("no more response");
+ return StatusCode::INTERNAL_ERROR;
+ }
+}
+
+template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
+ std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+ std::list<std::vector<GetValueResult>>* storedResponses) const;
+
+template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
+ std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+ std::list<std::vector<SetValueResult>>* storedResponses) const;
+
+template <class RequestType, class ResultType>
+StatusCode MockVehicleHardware::handleRequestsLocked(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ const std::vector<RequestType>& requests,
+ std::list<std::vector<RequestType>>* storedRequests,
+ std::list<std::vector<ResultType>>* storedResponses) const {
+ storedRequests->push_back(requests);
+ if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
+ if (StatusCode status = it->second; status != StatusCode::OK) {
+ return status;
+ }
+ }
+
+ if (mSleepTime != 0) {
+ int64_t sleepTime = mSleepTime;
+ mThreadCount++;
+ std::thread t([this, callback, sleepTime, storedResponses]() {
+ std::this_thread::sleep_for(std::chrono::nanoseconds(sleepTime));
+ returnResponse(callback, storedResponses);
+ mThreadCount--;
+ mCv.notify_one();
+ });
+ // Detach the thread here so we do not have to maintain the thread object. mThreadCount
+ // and mCv make sure we wait for all threads to end before we exit.
+ t.detach();
+ return StatusCode::OK;
+
+ } else {
+ return returnResponse(callback, storedResponses);
+ }
+}
+
+template StatusCode MockVehicleHardware::handleRequestsLocked<GetValueRequest, GetValueResult>(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+ const std::vector<GetValueRequest>& requests,
+ std::list<std::vector<GetValueRequest>>* storedRequests,
+ std::list<std::vector<GetValueResult>>* storedResponses) const;
+
+template StatusCode MockVehicleHardware::handleRequestsLocked<SetValueRequest, SetValueResult>(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+ const std::vector<SetValueRequest>& requests,
+ std::list<std::vector<SetValueRequest>>* storedRequests,
+ std::list<std::vector<SetValueResult>>* storedResponses) const;
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
new file mode 100644
index 0000000..74d4fae
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleHardware_H_
+#define android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleHardware_H_
+
+#include <IVehicleHardware.h>
+#include <VehicleHalTypes.h>
+
+#include <android-base/thread_annotations.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+class MockVehicleHardware final : public IVehicleHardware {
+ public:
+ ~MockVehicleHardware();
+
+ std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+ getAllPropertyConfigs() const override;
+ ::aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+ std::shared_ptr<const SetValuesCallback> callback,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+ requests) override;
+ ::aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+ std::shared_ptr<const GetValuesCallback> callback,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+ requests) const override;
+ DumpResult dump(const std::vector<std::string>&) override;
+ ::aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override;
+ void registerOnPropertyChangeEvent(
+ std::unique_ptr<const PropertyChangeCallback> callback) override;
+ void registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback>) override;
+
+ // Test functions.
+ void setPropertyConfigs(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>&
+ configs);
+ void addGetValueResponses(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>&
+ responses);
+ void addSetValueResponses(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>&
+ responses);
+ void setGetValueResponder(
+ std::function<::aidl::android::hardware::automotive::vehicle::StatusCode(
+ std::shared_ptr<const GetValuesCallback>,
+ const std::vector<
+ ::aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>&&
+ responder);
+ std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>
+ nextGetValueRequests();
+ std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>
+ nextSetValueRequests();
+ void setStatus(const char* functionName,
+ ::aidl::android::hardware::automotive::vehicle::StatusCode status);
+ void setSleepTime(int64_t timeInNano);
+ void setDumpResult(DumpResult result);
+
+ private:
+ mutable std::mutex mLock;
+ mutable std::condition_variable mCv;
+ mutable std::atomic<int> mThreadCount;
+ std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig> mPropertyConfigs
+ GUARDED_BY(mLock);
+ mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>>
+ mGetValueRequests GUARDED_BY(mLock);
+ mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>>
+ mGetValueResponses GUARDED_BY(mLock);
+ mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>>
+ mSetValueRequests GUARDED_BY(mLock);
+ mutable std::list<std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>>
+ mSetValueResponses GUARDED_BY(mLock);
+ std::unordered_map<const char*, ::aidl::android::hardware::automotive::vehicle::StatusCode>
+ mStatusByFunctions GUARDED_BY(mLock);
+ int64_t mSleepTime GUARDED_BY(mLock) = 0;
+ std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
+ std::function<::aidl::android::hardware::automotive::vehicle::StatusCode(
+ std::shared_ptr<const GetValuesCallback>,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
+ mGetValueResponder GUARDED_BY(mLock);
+
+ template <class ResultType>
+ ::aidl::android::hardware::automotive::vehicle::StatusCode returnResponse(
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ std::list<std::vector<ResultType>>* storedResponses) const;
+ template <class RequestType, class ResultType>
+ ::aidl::android::hardware::automotive::vehicle::StatusCode handleRequestsLocked(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ const std::vector<RequestType>& requests,
+ std::list<std::vector<RequestType>>* storedRequests,
+ std::list<std::vector<ResultType>>* storedResponses) const REQUIRES(mLock);
+
+ DumpResult mDumpResult;
+};
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleHardware_H_
diff --git a/automotive/vehicle/aidl/impl/vhal/test/PendingRequestPoolTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/PendingRequestPoolTest.cpp
index 03d795b..9c9e4b9 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/PendingRequestPoolTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/PendingRequestPoolTest.cpp
@@ -53,7 +53,7 @@
int64_t getTimeout() { return TEST_TIMEOUT; }
- void* getTestClientId() { return reinterpret_cast<void*>(0); }
+ const void* getTestClientId() { return reinterpret_cast<const void*>(0); }
private:
// Test timeout is 0.1s.
@@ -239,12 +239,12 @@
auto callback = std::make_shared<PendingRequestPool::TimeoutCallbackFunc>(
[](std::unordered_set<int64_t>) {});
- ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<void*>(0), {0}, callback));
- ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<void*>(1), {1, 2, 0}, callback));
+ ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<const void*>(0), {0}, callback));
+ ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<const void*>(1), {1, 2, 0}, callback));
- ASSERT_THAT(getPool()->tryFinishRequests(reinterpret_cast<void*>(0), {0}),
+ ASSERT_THAT(getPool()->tryFinishRequests(reinterpret_cast<const void*>(0), {0}),
UnorderedElementsAre(0));
- ASSERT_THAT(getPool()->tryFinishRequests(reinterpret_cast<void*>(1), {1, 2, 0}),
+ ASSERT_THAT(getPool()->tryFinishRequests(reinterpret_cast<const void*>(1), {1, 2, 0}),
UnorderedElementsAre(0, 1, 2));
}
@@ -258,14 +258,14 @@
for (size_t i = 0; i < 10000; i++) {
requests.insert(static_cast<int64_t>(i));
}
- ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<void*>(0), requests, callback));
+ ASSERT_RESULT_OK(getPool()->addRequests(reinterpret_cast<const void*>(0), requests, callback));
- auto result = getPool()->addRequests(reinterpret_cast<void*>(0), {static_cast<int64_t>(10000)},
- callback);
+ auto result = getPool()->addRequests(reinterpret_cast<const void*>(0),
+ {static_cast<int64_t>(10000)}, callback);
ASSERT_FALSE(result.ok()) << "adding more pending requests than limit must fail";
ASSERT_EQ(result.error().code(), toInt(StatusCode::TRY_AGAIN));
- getPool()->tryFinishRequests(reinterpret_cast<void*>(0), requests);
+ getPool()->tryFinishRequests(reinterpret_cast<const void*>(0), requests);
}
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp
new file mode 100644
index 0000000..d343cea
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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 "RecurrentTimer.h"
+
+#include <android-base/thread_annotations.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+class RecurrentTimerTest : public ::testing::Test {
+ public:
+ std::shared_ptr<RecurrentTimer::Callback> getCallback(size_t token) {
+ return std::make_shared<RecurrentTimer::Callback>([this, token] {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ mCallbacks.push_back(token);
+ });
+ }
+
+ std::vector<size_t> getCalledCallbacks() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mCallbacks;
+ }
+
+ void clearCalledCallbacks() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mCallbacks.clear();
+ }
+
+ size_t countTimerCallbackQueue(RecurrentTimer* timer) {
+ std::scoped_lock<std::mutex> lockGuard(timer->mLock);
+ return timer->mCallbackQueue.size();
+ }
+
+ private:
+ std::mutex mLock;
+ std::vector<size_t> mCallbacks GUARDED_BY(mLock);
+};
+
+TEST_F(RecurrentTimerTest, testRegisterCallback) {
+ RecurrentTimer timer;
+ // 0.1s
+ int64_t interval = 100000000;
+
+ auto action = getCallback(0);
+ timer.registerTimerCallback(interval, action);
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ timer.unregisterTimerCallback(action);
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+}
+
+TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
+ RecurrentTimer timer;
+ // 0.1s
+ int64_t interval = 100000000;
+
+ auto action = getCallback(0);
+ timer.registerTimerCallback(interval, action);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+ timer.unregisterTimerCallback(action);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+ clearCalledCallbacks();
+
+ timer.registerTimerCallback(interval, action);
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+}
+
+TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
+ std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
+ // 0.1s
+ int64_t interval = 100000000;
+
+ auto action = getCallback(0);
+ timer->registerTimerCallback(interval, action);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+ timer.reset();
+
+ clearCalledCallbacks();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+ ASSERT_TRUE(getCalledCallbacks().empty());
+}
+
+TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
+ RecurrentTimer timer;
+ // 0.1s
+ int64_t interval1 = 100000000;
+ auto action1 = getCallback(1);
+ timer.registerTimerCallback(interval1, action1);
+ // 0.05s
+ int64_t interval2 = 50000000;
+ auto action2 = getCallback(2);
+ timer.registerTimerCallback(interval2, action2);
+ // 0.03s
+ int64_t interval3 = 30000000;
+ auto action3 = getCallback(3);
+ timer.registerTimerCallback(interval3, action3);
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ timer.unregisterTimerCallback(action1);
+ timer.unregisterTimerCallback(action2);
+ timer.unregisterTimerCallback(action3);
+
+ size_t action1Count = 0;
+ size_t action2Count = 0;
+ size_t action3Count = 0;
+ for (size_t token : getCalledCallbacks()) {
+ if (token == 1) {
+ action1Count++;
+ }
+ if (token == 2) {
+ action2Count++;
+ }
+ if (token == 3) {
+ action3Count++;
+ }
+ }
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ ASSERT_GE(action1Count, static_cast<size_t>(9));
+ // Theoretically trigger 20 times, but check for at least 15 times to be stable.
+ ASSERT_GE(action2Count, static_cast<size_t>(15));
+ // Theoretically trigger 33 times, but check for at least 25 times to be stable.
+ ASSERT_GE(action3Count, static_cast<size_t>(25));
+}
+
+TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
+ RecurrentTimer timer;
+ // 0.02s
+ int64_t interval1 = 20000000;
+ // 0.01s
+ int64_t interval2 = 10000000;
+
+ auto action = getCallback(0);
+ for (int i = 0; i < 10; i++) {
+ timer.registerTimerCallback(interval1, action);
+ timer.registerTimerCallback(interval2, action);
+ }
+
+ clearCalledCallbacks();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+
+ timer.unregisterTimerCallback(action);
+
+ // Make sure there is no item in the callback queue.
+ ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
+}
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
new file mode 100644
index 0000000..f81b1a2
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
@@ -0,0 +1,491 @@
+/*
+ * 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 "SubscriptionManager.h"
+
+#include <VehicleHalTypes.h>
+
+#include <aidl/android/hardware/automotive/vehicle/BnVehicleCallback.h>
+#include <android-base/thread_annotations.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <float.h>
+#include <chrono>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::BnVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
+using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
+using ::ndk::ScopedAStatus;
+using ::ndk::SpAIBinder;
+using ::testing::ElementsAre;
+using ::testing::WhenSorted;
+
+class PropertyCallback final : public BnVehicleCallback {
+ public:
+ ScopedAStatus onGetValues(const GetValueResults&) override { return ScopedAStatus::ok(); }
+
+ ScopedAStatus onSetValues(const SetValueResults&) override { return ScopedAStatus::ok(); }
+
+ ScopedAStatus onPropertyEvent(const VehiclePropValues& values, int32_t) override {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ for (const auto& value : values.payloads) {
+ mEvents.push_back(value);
+ }
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus onPropertySetError(const VehiclePropErrors&) override {
+ return ScopedAStatus::ok();
+ }
+
+ // Test functions.
+ std::list<VehiclePropValue> getEvents() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mEvents;
+ }
+
+ void clearEvents() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mEvents.clear();
+ }
+
+ private:
+ std::mutex mLock;
+ std::list<VehiclePropValue> mEvents GUARDED_BY(mLock);
+};
+
+class SubscriptionManagerTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ mManager = std::make_unique<SubscriptionManager>(
+ [](const std::shared_ptr<IVehicleCallback>& callback,
+ const VehiclePropValue& value) {
+ callback->onPropertyEvent(
+ VehiclePropValues{
+ .payloads = {value},
+ },
+ 0);
+ });
+ mCallback = ::ndk::SharedRefBase::make<PropertyCallback>();
+ // Keep the local binder alive.
+ mBinder = mCallback->asBinder();
+ mCallbackClient = IVehicleCallback::fromBinder(mBinder);
+ }
+
+ SubscriptionManager* getManager() { return mManager.get(); }
+
+ std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
+
+ PropertyCallback* getCallback() { return mCallback.get(); }
+
+ std::list<VehiclePropValue> getEvents() { return getCallback()->getEvents(); }
+
+ void clearEvents() { return getCallback()->clearEvents(); }
+
+ private:
+ std::unique_ptr<SubscriptionManager> mManager;
+ std::shared_ptr<PropertyCallback> mCallback;
+ std::shared_ptr<IVehicleCallback> mCallbackClient;
+ SpAIBinder mBinder;
+};
+
+TEST_F(SubscriptionManagerTest, testSubscribeGlobalContinuous) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = 0,
+ .areaIds = {0},
+ .sampleRate = 10.0,
+ }};
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ ASSERT_GE(getEvents().size(), static_cast<size_t>(9));
+ EXPECT_EQ(getEvents().back().prop, 0);
+ EXPECT_EQ(getEvents().back().areaId, 0);
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeMultiplePropsGlobalContinuous) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = 0,
+ .areaIds = {0},
+ .sampleRate = 10.0,
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ .sampleRate = 20.0,
+ }};
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ size_t event0Count = 0;
+ size_t event1Count = 0;
+
+ for (const auto& event : getEvents()) {
+ if (event.prop == 0) {
+ event0Count++;
+ } else {
+ event1Count++;
+ }
+ }
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ EXPECT_GE(event0Count, static_cast<size_t>(9));
+ // Theoretically trigger 20 times, but check for at least 15 times to be stable.
+ EXPECT_GE(event1Count, static_cast<size_t>(15));
+}
+
+TEST_F(SubscriptionManagerTest, testOverrideSubscriptionContinuous) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = 0,
+ .areaIds = {0},
+ .sampleRate = 20.0,
+ }};
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ // Override sample rate to be 10.0.
+ options[0].sampleRate = 10.0;
+ result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ EXPECT_GE(getEvents().size(), static_cast<size_t>(9));
+ EXPECT_LE(getEvents().size(), static_cast<size_t>(15));
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeMultipleAreasContinuous) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = 0,
+ .areaIds = {0, 1},
+ .sampleRate = 10.0,
+ },
+ };
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ size_t area0Count = 0;
+ size_t area1Count = 0;
+
+ for (const auto& event : getEvents()) {
+ if (event.areaId == 0) {
+ area0Count++;
+ } else {
+ area1Count++;
+ }
+ }
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ EXPECT_GE(area0Count, static_cast<size_t>(9));
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ EXPECT_GE(area1Count, static_cast<size_t>(9));
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeGlobalContinuous) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = 0,
+ .areaIds = {0},
+ .sampleRate = 10.0,
+ }};
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ result = getManager()->unsubscribe(getCallbackClient()->asBinder().get());
+ ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+ clearEvents();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ ASSERT_TRUE(getEvents().empty());
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeMultipleAreas) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = 0,
+ .areaIds = {0, 1, 2, 3, 4},
+ .sampleRate = 10.0,
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ .sampleRate = 10.0,
+ },
+ };
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+ std::vector<int32_t>({0}));
+ ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+ clearEvents();
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // Theoretically trigger 10 times, but check for at least 9 times to be stable.
+ EXPECT_GE(getEvents().size(), static_cast<size_t>(9));
+
+ for (const auto& event : getEvents()) {
+ EXPECT_EQ(event.prop, 1);
+ }
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeByCallback) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = 0,
+ .areaIds = {0, 1, 2, 3, 4},
+ .sampleRate = 10.0,
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ .sampleRate = 10.0,
+ },
+ };
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ result = getManager()->unsubscribe(getCallbackClient()->asBinder().get());
+ ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+ clearEvents();
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ EXPECT_TRUE(getEvents().empty());
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeFailure) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = 0,
+ .areaIds = {0, 1, 2, 3, 4},
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ },
+ };
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, false);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ // Property ID: 2 was not subscribed.
+ result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+ std::vector<int32_t>({0, 1, 2}));
+ ASSERT_FALSE(result.ok()) << "unsubscribe an unsubscribed property must fail";
+
+ // Since property 0 and property 1 was not unsubscribed successfully, we should be able to
+ // unsubscribe them again.
+ result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+ std::vector<int32_t>({0, 1}));
+ ASSERT_TRUE(result.ok()) << "a failed unsubscription must not unsubscribe any properties"
+ << result.error().message();
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeOnchange) {
+ std::vector<SubscribeOptions> options1 = {
+ {
+ .propId = 0,
+ .areaIds = {0, 1},
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ },
+ };
+ std::vector<SubscribeOptions> options2 = {
+ {
+ .propId = 0,
+ .areaIds = {0},
+ },
+ };
+
+ SpAIBinder binder1 = ::ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+ std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+ SpAIBinder binder2 = ::ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+ std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+ auto result = getManager()->subscribe(client1, options1, false);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+ result = getManager()->subscribe(client2, options2, false);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ std::vector<VehiclePropValue> updatedValues = {
+ {
+ .prop = 0,
+ .areaId = 0,
+ },
+ {
+ .prop = 0,
+ .areaId = 1,
+ },
+ {
+ .prop = 1,
+ .areaId = 0,
+ },
+ {
+ .prop = 1,
+ .areaId = 1,
+ },
+ };
+ auto clients = getManager()->getSubscribedClients(updatedValues);
+
+ ASSERT_THAT(clients[client1],
+ WhenSorted(ElementsAre(&updatedValues[0], &updatedValues[1], &updatedValues[2])));
+ ASSERT_THAT(clients[client2], ElementsAre(&updatedValues[0]));
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeInvalidOption) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = 0,
+ .areaIds = {0, 1, 2, 3, 4},
+ // invalid sample rate.
+ .sampleRate = 0.0,
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ .sampleRate = 10.0,
+ },
+ };
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_FALSE(result.ok()) << "subscribe with invalid sample rate must fail";
+ ASSERT_TRUE(getManager()
+ ->getSubscribedClients({{
+ .prop = 0,
+ .areaId = 0,
+ },
+ {
+ .prop = 1,
+ .areaId = 0,
+ }})
+ .empty())
+ << "no property should be subscribed if error is returned";
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribeNoAreaIds) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = 0,
+ .areaIds = {},
+ .sampleRate = 1.0,
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ .sampleRate = 10.0,
+ },
+ };
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, true);
+ ASSERT_FALSE(result.ok()) << "subscribe with invalid sample rate must fail";
+ ASSERT_TRUE(getManager()
+ ->getSubscribedClients({{
+ .prop = 1,
+ .areaId = 0,
+ }})
+ .empty())
+ << "no property should be subscribed if error is returned";
+}
+
+TEST_F(SubscriptionManagerTest, testUnsubscribeOnchange) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = 0,
+ .areaIds = {0, 1},
+ },
+ {
+ .propId = 1,
+ .areaIds = {0},
+ },
+ };
+
+ auto result = getManager()->subscribe(getCallbackClient(), options, false);
+ ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+ result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
+ std::vector<int32_t>({0}));
+ ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
+
+ std::vector<VehiclePropValue> updatedValues = {
+ {
+ .prop = 0,
+ .areaId = 0,
+ },
+ {
+ .prop = 1,
+ .areaId = 0,
+ },
+ };
+ auto clients = getManager()->getSubscribedClients(updatedValues);
+
+ ASSERT_THAT(clients[getCallbackClient()], ElementsAre(&updatedValues[1]));
+}
+
+TEST_F(SubscriptionManagerTest, testCheckSampleRateValid) {
+ ASSERT_TRUE(SubscriptionManager::checkSampleRate(1.0));
+}
+
+TEST_F(SubscriptionManagerTest, testCheckSampleRateInvalidTooSmall) {
+ ASSERT_FALSE(SubscriptionManager::checkSampleRate(FLT_MIN));
+}
+
+TEST_F(SubscriptionManagerTest, testCheckSampleRateInvalidZero) {
+ ASSERT_FALSE(SubscriptionManager::checkSampleRate(0));
+}
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/proto/Android.bp
similarity index 94%
rename from automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
rename to automotive/vehicle/proto/Android.bp
index 3307bd6..683f128 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
+++ b/automotive/vehicle/proto/Android.bp
@@ -25,8 +25,8 @@
cc_library_static {
name: "android.hardware.automotive.vehicle@2.0-libproto-native",
visibility: [
- "//hardware/interfaces/automotive/vehicle/2.0/default:__subpackages__",
- "//device/generic/car/emulator/vhal_v2_0:__subpackages__",
+ "//hardware/interfaces/automotive/vehicle:__subpackages__",
+ "//device/generic/car/emulator:__subpackages__",
],
vendor: true,
host_supported: true,
diff --git a/automotive/vehicle/proto/VehicleHalProto.proto b/automotive/vehicle/proto/VehicleHalProto.proto
new file mode 100644
index 0000000..0dafe8c
--- /dev/null
+++ b/automotive/vehicle/proto/VehicleHalProto.proto
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+syntax = "proto2";
+
+package vhal_proto;
+
+// CMD messages are from workstation --> VHAL
+// RESP messages are from VHAL --> workstation
+enum MsgType {
+ GET_CONFIG_CMD = 0;
+ GET_CONFIG_RESP = 1;
+ GET_CONFIG_ALL_CMD = 2;
+ GET_CONFIG_ALL_RESP = 3;
+ GET_PROPERTY_CMD = 4;
+ GET_PROPERTY_RESP = 5;
+ GET_PROPERTY_ALL_CMD = 6;
+ GET_PROPERTY_ALL_RESP = 7;
+ SET_PROPERTY_CMD = 8;
+ SET_PROPERTY_RESP = 9;
+ SET_PROPERTY_ASYNC = 10;
+ DEBUG_CMD = 11;
+ DEBUG_RESP = 12;
+}
+enum Status {
+ RESULT_OK = 0;
+ ERROR_UNKNOWN = 1;
+ ERROR_UNIMPLEMENTED_CMD = 2;
+ ERROR_INVALID_PROPERTY = 3;
+ ERROR_INVALID_AREA_ID = 4;
+ ERROR_PROPERTY_UNINITIALIZED = 5;
+ ERROR_WRITE_ONLY_PROPERTY = 6;
+ ERROR_MEMORY_ALLOC_FAILED = 7;
+ ERROR_INVALID_OPERATION = 8;
+}
+
+enum VehiclePropStatus {
+ AVAILABLE = 0;
+ UNAVAILABLE = 1;
+ ERROR = 2;
+}
+
+message VehicleAreaConfig {
+ required int32 area_id = 1;
+ optional sint32 min_int32_value = 2;
+ optional sint32 max_int32_value = 3;
+ optional sint64 min_int64_value = 4;
+ optional sint64 max_int64_value = 5;
+ optional float min_float_value = 6;
+ optional float max_float_value = 7;
+}
+
+message VehiclePropConfig {
+ required int32 prop = 1;
+ optional int32 access = 2;
+ optional int32 change_mode = 3;
+ optional int32 value_type = 4;
+ optional int32 supported_areas = 5; // Deprecated - DO NOT USE
+ repeated VehicleAreaConfig area_configs = 6;
+ optional int32 config_flags = 7;
+ repeated int32 config_array = 8;
+ optional string config_string = 9;
+ optional float min_sample_rate = 10;
+ optional float max_sample_rate = 11;
+};
+
+message VehiclePropValue {
+ // common data
+ required int32 prop = 1;
+ optional int32 value_type = 2;
+ optional int64 timestamp = 3; // required for valid data from HAL, skipped for set
+ optional VehiclePropStatus status = 10; // required for valid data from HAL, skipped for set
+
+ // values
+ optional int32 area_id = 4;
+ repeated sint32 int32_values = 5; // this also covers boolean value.
+ repeated sint64 int64_values = 6;
+ repeated float float_values = 7;
+ optional string string_value = 8;
+ optional bytes bytes_value = 9;
+};
+
+// This structure is used to notify what values to get from the Vehicle HAL
+message VehiclePropGet {
+ required int32 prop = 1;
+ optional int32 area_id = 2;
+};
+
+message EmulatorMessage {
+ required MsgType msg_type = 1;
+ optional Status status = 2; // Only for RESP messages
+ repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands
+ repeated VehiclePropConfig config = 4;
+ repeated VehiclePropValue value = 5;
+ repeated string debug_commands = 6; // Required for debug command
+ optional string debug_result = 7; // Required for debug RESP messages
+};
diff --git a/bluetooth/audio/2.2/default/OWNERS b/bluetooth/audio/2.2/default/OWNERS
new file mode 100644
index 0000000..17ea464
--- /dev/null
+++ b/bluetooth/audio/2.2/default/OWNERS
@@ -0,0 +1,4 @@
+include platform/packages/modules/Bluetooth:/OWNERS
+
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 12eed55..5107240 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -43,6 +43,10 @@
vndk: {
enabled: true,
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.bluetooth",
+ ],
},
},
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacCapabilities.aidl
index ad44c26..899b8ca 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacCapabilities.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacCapabilities.aidl
@@ -34,9 +34,9 @@
package android.hardware.bluetooth.audio;
@VintfStability
parcelable AacCapabilities {
- android.hardware.bluetooth.audio.AacObjectType objectType;
+ android.hardware.bluetooth.audio.AacObjectType[] objectType;
int[] sampleRateHz;
- android.hardware.bluetooth.audio.ChannelMode channelMode;
+ android.hardware.bluetooth.audio.ChannelMode[] channelMode;
boolean variableBitRateSupported;
byte[] bitsPerSample;
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
index c129c66..2148244 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -34,8 +34,8 @@
package android.hardware.bluetooth.audio;
@Backing(type="byte") @VintfStability
enum AacObjectType {
- MPEG2_LC = 1,
- MPEG4_LC = 2,
- MPEG4_LTP = 4,
- MPEG4_SCALABLE = 8,
+ MPEG2_LC = 0,
+ MPEG4_LC = 1,
+ MPEG4_LTP = 2,
+ MPEG4_SCALABLE = 3,
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxCapabilities.aidl
index 4767b69..08a38e2 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxCapabilities.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxCapabilities.aidl
@@ -35,6 +35,6 @@
@VintfStability
parcelable AptxCapabilities {
int[] sampleRateHz;
- android.hardware.bluetooth.audio.ChannelMode channelMode;
+ android.hardware.bluetooth.audio.ChannelMode[] channelMode;
byte[] bitsPerSample;
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
index 3ca93c3..c3bc741 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -34,7 +34,7 @@
package android.hardware.bluetooth.audio;
@Backing(type="byte") @VintfStability
enum ChannelMode {
- UNKNOWN = 1,
- MONO = 2,
- STEREO = 4,
+ UNKNOWN = 0,
+ MONO = 1,
+ STEREO = 2,
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
index e2a08a0..948c04a 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -37,11 +37,16 @@
android.hardware.bluetooth.audio.CodecType codecType;
android.hardware.bluetooth.audio.CodecCapabilities.Capabilities capabilities;
@VintfStability
+ parcelable VendorCapabilities {
+ ParcelableHolder extension;
+ }
+ @VintfStability
union Capabilities {
android.hardware.bluetooth.audio.SbcCapabilities sbcCapabilities;
android.hardware.bluetooth.audio.AacCapabilities aacCapabilities;
android.hardware.bluetooth.audio.LdacCapabilities ldacCapabilities;
android.hardware.bluetooth.audio.AptxCapabilities aptxCapabilities;
android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
+ android.hardware.bluetooth.audio.CodecCapabilities.VendorCapabilities vendorCapabilities;
}
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
index 34ebd60..32bccd8 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -40,11 +40,18 @@
boolean isScmstEnabled;
android.hardware.bluetooth.audio.CodecConfiguration.CodecSpecific config;
@VintfStability
+ parcelable VendorConfiguration {
+ int vendorId;
+ char codecId;
+ ParcelableHolder codecConfig;
+ }
+ @VintfStability
union CodecSpecific {
android.hardware.bluetooth.audio.SbcConfiguration sbcConfig;
android.hardware.bluetooth.audio.AacConfiguration aacConfig;
android.hardware.bluetooth.audio.LdacConfiguration ldacConfig;
android.hardware.bluetooth.audio.AptxConfiguration aptxConfig;
android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
+ android.hardware.bluetooth.audio.CodecConfiguration.VendorConfiguration vendorConfig;
}
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
index 44b434b..3a5f951 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
@@ -41,4 +41,5 @@
APTX_HD = 4,
LDAC = 5,
LC3 = 6,
+ VENDOR = 7,
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacCapabilities.aidl
index 19e041a..aa4e4c8 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacCapabilities.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacCapabilities.aidl
@@ -35,7 +35,7 @@
@VintfStability
parcelable LdacCapabilities {
int[] sampleRateHz;
- android.hardware.bluetooth.audio.LdacChannelMode channelMode;
- android.hardware.bluetooth.audio.LdacQualityIndex qualityIndex;
+ android.hardware.bluetooth.audio.LdacChannelMode[] channelMode;
+ android.hardware.bluetooth.audio.LdacQualityIndex[] qualityIndex;
byte[] bitsPerSample;
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
index a9d6c5e..88d6faf 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -34,8 +34,8 @@
package android.hardware.bluetooth.audio;
@Backing(type="byte") @VintfStability
enum LdacChannelMode {
- UNKNOWN = 1,
- STEREO = 2,
- DUAL = 4,
- MONO = 8,
+ UNKNOWN = 0,
+ STEREO = 1,
+ DUAL = 2,
+ MONO = 3,
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
index 693392f..35e4358 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -34,8 +34,8 @@
package android.hardware.bluetooth.audio;
@Backing(type="byte") @VintfStability
enum LdacQualityIndex {
- HIGH = 1,
- MID = 2,
- LOW = 4,
- ABR = 8,
+ HIGH = 0,
+ MID = 1,
+ LOW = 2,
+ ABR = 3,
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmCapabilities.aidl
index 6cfe5cd..0c2f87d 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmCapabilities.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/PcmCapabilities.aidl
@@ -35,7 +35,7 @@
@VintfStability
parcelable PcmCapabilities {
int[] sampleRateHz;
- android.hardware.bluetooth.audio.ChannelMode channelMode;
+ android.hardware.bluetooth.audio.ChannelMode[] channelMode;
byte[] bitsPerSample;
int[] dataIntervalUs;
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
index 5170f16..091f6d7 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -34,6 +34,6 @@
package android.hardware.bluetooth.audio;
@Backing(type="byte") @VintfStability
enum SbcAllocMethod {
- ALLOC_MD_S = 1,
- ALLOC_MD_L = 2,
+ ALLOC_MD_S = 0,
+ ALLOC_MD_L = 1,
}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcCapabilities.aidl
index ec3aa0f..c8d7e7e 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcCapabilities.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcCapabilities.aidl
@@ -35,10 +35,10 @@
@VintfStability
parcelable SbcCapabilities {
int[] sampleRateHz;
- android.hardware.bluetooth.audio.SbcChannelMode channelMode;
+ android.hardware.bluetooth.audio.SbcChannelMode[] channelMode;
byte[] blockLength;
byte[] numSubbands;
- android.hardware.bluetooth.audio.SbcAllocMethod allocMethod;
+ android.hardware.bluetooth.audio.SbcAllocMethod[] allocMethod;
byte[] bitsPerSample;
int minBitpool;
int maxBitpool;
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
index 88fca4a..6441a99 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -34,9 +34,9 @@
package android.hardware.bluetooth.audio;
@Backing(type="byte") @VintfStability
enum SbcChannelMode {
- UNKNOWN = 1,
- JOINT_STEREO = 2,
- STEREO = 4,
- DUAL = 8,
- MONO = 16,
+ UNKNOWN = 0,
+ JOINT_STEREO = 1,
+ STEREO = 2,
+ DUAL = 3,
+ MONO = 4,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacCapabilities.aidl
index 4303883..c4153e9 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacCapabilities.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacCapabilities.aidl
@@ -24,11 +24,9 @@
*/
@VintfStability
parcelable AacCapabilities {
- /* bitfield */
- AacObjectType objectType;
+ AacObjectType[] objectType;
int[] sampleRateHz;
- /* bitfield */
- ChannelMode channelMode;
+ ChannelMode[] channelMode;
boolean variableBitRateSupported;
byte[] bitsPerSample;
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacObjectType.aidl
index 480e422..4e9958c 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacObjectType.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -22,17 +22,17 @@
/**
* MPEG-2 Low Complexity. Support is Mandatory.
*/
- MPEG2_LC = 1,
+ MPEG2_LC,
/**
* MPEG-4 Low Complexity. Support is Optional.
*/
- MPEG4_LC = 1 << 1,
+ MPEG4_LC,
/**
* MPEG-4 Long Term Prediction. Support is Optional.
*/
- MPEG4_LTP = 1 << 2,
+ MPEG4_LTP,
/**
* MPEG-4 Scalable. Support is Optional.
*/
- MPEG4_SCALABLE = 1 << 3,
+ MPEG4_SCALABLE,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxCapabilities.aidl
index 6a37fc6..f5605d3 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxCapabilities.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AptxCapabilities.aidl
@@ -24,7 +24,6 @@
@VintfStability
parcelable AptxCapabilities {
int[] sampleRateHz;
- /* bitfield */
- ChannelMode channelMode;
+ ChannelMode[] channelMode;
byte[] bitsPerSample;
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
index 2df879d..6613872 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -19,7 +19,7 @@
@VintfStability
@Backing(type="byte")
enum ChannelMode {
- UNKNOWN = 1,
- MONO = 1 << 1,
- STEREO = 1 << 2,
+ UNKNOWN,
+ MONO,
+ STEREO,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
index 5bf0252..41e2431 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -30,12 +30,17 @@
@VintfStability
parcelable CodecCapabilities {
@VintfStability
+ parcelable VendorCapabilities {
+ ParcelableHolder extension;
+ }
+ @VintfStability
union Capabilities {
SbcCapabilities sbcCapabilities;
AacCapabilities aacCapabilities;
LdacCapabilities ldacCapabilities;
AptxCapabilities aptxCapabilities;
Lc3Capabilities lc3Capabilities;
+ VendorCapabilities vendorCapabilities;
}
CodecType codecType;
Capabilities capabilities;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
index 9e43f22..3679537 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -30,12 +30,19 @@
@VintfStability
parcelable CodecConfiguration {
@VintfStability
+ parcelable VendorConfiguration {
+ int vendorId;
+ char codecId;
+ ParcelableHolder codecConfig;
+ }
+ @VintfStability
union CodecSpecific {
SbcConfiguration sbcConfig;
AacConfiguration aacConfig;
LdacConfiguration ldacConfig;
AptxConfiguration aptxConfig;
Lc3Configuration lc3Config;
+ VendorConfiguration vendorConfig;
}
CodecType codecType;
/**
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
index 68c60f5..9c33081 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
@@ -26,4 +26,5 @@
APTX_HD,
LDAC,
LC3,
+ VENDOR,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacCapabilities.aidl
index 44cca7e..1dbec08 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacCapabilities.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacCapabilities.aidl
@@ -26,9 +26,7 @@
@VintfStability
parcelable LdacCapabilities {
int[] sampleRateHz;
- /* bitfiled */
- LdacChannelMode channelMode;
- /* bitfiled */
- LdacQualityIndex qualityIndex;
+ LdacChannelMode[] channelMode;
+ LdacQualityIndex[] qualityIndex;
byte[] bitsPerSample;
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacChannelMode.aidl
index 3acca32..3cc910f 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacChannelMode.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -22,8 +22,8 @@
@VintfStability
@Backing(type="byte")
enum LdacChannelMode {
- UNKNOWN = 1,
- STEREO = 1 << 1,
- DUAL = 1 << 2,
- MONO = 1 << 3,
+ UNKNOWN,
+ STEREO,
+ DUAL,
+ MONO,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
index cb12583..9993b8b 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -22,17 +22,17 @@
/**
* 990kbps
*/
- HIGH = 1,
+ HIGH,
/**
* 660kbps
*/
- MID = 1 << 1,
+ MID,
/**
* 330kbps
*/
- LOW = 1 << 2,
+ LOW,
/**
* Adaptive Bit Rate mode
*/
- ABR = 1 << 3,
+ ABR,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmCapabilities.aidl
index f5d699e..776b777 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmCapabilities.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/PcmCapabilities.aidl
@@ -24,7 +24,7 @@
@VintfStability
parcelable PcmCapabilities {
int[] sampleRateHz;
- ChannelMode channelMode;
+ ChannelMode[] channelMode;
byte[] bitsPerSample;
/**
* Data interval for data transfer
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
index 7047e34..1159f30 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -22,9 +22,9 @@
/**
* SNR
*/
- ALLOC_MD_S = 1,
+ ALLOC_MD_S,
/**
* Loudness
*/
- ALLOC_MD_L = 1 << 1,
+ ALLOC_MD_L,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcCapabilities.aidl
index cf62ed4..743a1f7 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcCapabilities.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcCapabilities.aidl
@@ -25,12 +25,10 @@
@VintfStability
parcelable SbcCapabilities {
int[] sampleRateHz;
- /* bitfield */
- SbcChannelMode channelMode;
+ SbcChannelMode[] channelMode;
byte[] blockLength;
byte[] numSubbands;
- /* bitfield */
- SbcAllocMethod allocMethod;
+ SbcAllocMethod[] allocMethod;
byte[] bitsPerSample;
/*
* range from 2 to 250.
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcChannelMode.aidl
index 7eb38cd..68e3267 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcChannelMode.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -19,9 +19,9 @@
@VintfStability
@Backing(type="byte")
enum SbcChannelMode {
- UNKNOWN = 1,
- JOINT_STEREO = 1 << 1,
- STEREO = 1 << 2,
- DUAL = 1 << 3,
- MONO = 1 << 4,
+ UNKNOWN,
+ JOINT_STEREO,
+ STEREO,
+ DUAL,
+ MONO,
}
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..fc8a911
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpHW"
+
+#include "A2dpOffloadAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+A2dpOffloadAudioProvider::A2dpOffloadAudioProvider() {
+ session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+bool A2dpOffloadAudioProvider::isValid(const SessionType& session_type) {
+ return (session_type == session_type_);
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+ session_type_, audio_config.get<AudioConfiguration::a2dpConfig>())) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ return BluetoothAudioProvider::startSession(host_if, audio_config,
+ _aidl_return);
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ *_aidl_return = DataMQDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+ nullptr, *audio_config_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
new file mode 100644
index 0000000..5934f5b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+ A2dpOffloadAudioProvider();
+
+ bool isValid(const SessionType& session_type) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..5a413e0
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpSW"
+
+#include "A2dpSoftwareAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+// Here the buffer size is based on SBC
+static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
+// SBC is 128, and here we choose the LCM of 16, 24, and 32
+static constexpr uint32_t kPcmFrameCount = 96;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+// The max counts by 1 tick (20ms) for SBC is about 7. Since using 96 for the
+// PCM counts, here we just choose a greater number
+static constexpr uint32_t kRtpFrameCount = 10;
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 2; // double buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
+ : BluetoothAudioProvider(), data_mq_(nullptr) {
+ LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+ << " byte(s)";
+ std::unique_ptr<DataMQ> data_mq(
+ new DataMQ(kDataMqSize, /* EventFlag */ true));
+ if (data_mq && data_mq->isValid()) {
+ data_mq_ = std::move(data_mq);
+ session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+ } else {
+ ALOGE_IF(!data_mq, "failed to allocate data MQ");
+ ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
+ }
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
+}
+
+ndk::ScopedAStatus A2dpSoftwareAudioProvider::startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const PcmConfiguration& pcm_config =
+ audio_config.get<AudioConfiguration::pcmConfig>();
+ if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << pcm_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return BluetoothAudioProvider::startSession(host_if, audio_config,
+ _aidl_return);
+}
+
+ndk::ScopedAStatus A2dpSoftwareAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ if (data_mq_ == nullptr || !data_mq_->isValid()) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = data_mq_->dupeDesc();
+ auto desc = data_mq_->dupeDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+ &desc, *audio_config_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
new file mode 100644
index 0000000..3bc0a13
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+ A2dpSoftwareAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+ // audio data queue for software encoding
+ std::unique_ptr<DataMQ> data_mq_;
+
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp
new file mode 100644
index 0000000..846702f
--- /dev/null
+++ b/bluetooth/audio/aidl/default/Android.bp
@@ -0,0 +1,34 @@
+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_library_shared {
+ name: "android.hardware.bluetooth.audio-V1-impl",
+ vendor: true,
+ vintf_fragments: ["bluetooth_audio.xml"],
+ srcs: [
+ "BluetoothAudioProvider.cpp",
+ "BluetoothAudioProviderFactory.cpp",
+ "A2dpOffloadAudioProvider.cpp",
+ "A2dpSoftwareAudioProvider.cpp",
+ "HearingAidAudioProvider.cpp",
+ "LeAudioOffloadAudioProvider.cpp",
+ "LeAudioSoftwareAudioProvider.cpp",
+ ],
+ export_include_dirs: ["."],
+ header_libs: ["libhardware_headers"],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "android.hardware.bluetooth.audio-V1-ndk",
+ "libbluetooth_audio_session_aidl",
+ ],
+}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
new file mode 100644
index 0000000..c2ffa2e
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderStub"
+
+#include "BluetoothAudioProvider.h"
+
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+BluetoothAudioProvider::BluetoothAudioProvider() {
+ death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(binderDiedCallbackAidl));
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+ if (host_if == nullptr) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+ stack_iface_ = host_if;
+
+ AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(),
+ this);
+
+ onSessionReady(_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::endSession() {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+ if (stack_iface_ != nullptr) {
+ BluetoothAudioSessionReport::OnSessionEnded(session_type_);
+
+ AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
+ death_recipient_.get(), this);
+ } else {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ }
+
+ stack_iface_ = nullptr;
+ audio_config_ = nullptr;
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::streamStarted(
+ BluetoothAudioStatus status) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status);
+
+ if (stack_iface_ != nullptr) {
+ BluetoothAudioSessionReport::ReportControlStatus(session_type_, true,
+ status);
+ } else {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status) << " has NO session";
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::streamSuspended(
+ BluetoothAudioStatus status) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status);
+
+ if (stack_iface_ != nullptr) {
+ BluetoothAudioSessionReport::ReportControlStatus(session_type_, false,
+ status);
+ } else {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", status=" << toString(status) << " has NO session";
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration(
+ const AudioConfiguration& audio_config) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+ if (stack_iface_ == nullptr || audio_config_ == nullptr) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (audio_config.getTag() != audio_config_->getTag()) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " audio config type is not match";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+ BluetoothAudioSessionReport::ReportAudioConfigChanged(session_type_,
+ *audio_config_);
+ return ndk::ScopedAStatus::ok();
+}
+
+void BluetoothAudioProvider::binderDiedCallbackAidl(void* ptr) {
+ LOG(ERROR) << __func__ << " - BluetoothAudio Service died";
+ auto provider = static_cast<BluetoothAudioProvider*>(ptr);
+ if (provider == nullptr) {
+ LOG(ERROR) << __func__ << ": Null AudioProvider HAL died";
+ return;
+ }
+ provider->endSession();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
new file mode 100644
index 0000000..f7acbdf
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioProvider.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <fmq/AidlMessageQueue.h>
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using MqDataType = int8_t;
+using MqDataMode = SynchronizedReadWrite;
+using DataMQ = AidlMessageQueue<MqDataType, MqDataMode>;
+using DataMQDesc = MQDescriptor<MqDataType, MqDataMode>;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioProvider : public BnBluetoothAudioProvider {
+ public:
+ BluetoothAudioProvider();
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+ ndk::ScopedAStatus endSession();
+ ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status);
+ ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status);
+ ndk::ScopedAStatus updateAudioConfiguration(
+ const AudioConfiguration& audio_config);
+
+ virtual bool isValid(const SessionType& sessionType) = 0;
+
+ protected:
+ virtual ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) = 0;
+ static void binderDiedCallbackAidl(void* cookie_ptr);
+
+ ::ndk::ScopedAIBinder_DeathRecipient death_recipient_;
+
+ std::shared_ptr<IBluetoothAudioPort> stack_iface_;
+ std::unique_ptr<AudioConfiguration> audio_config_ = nullptr;
+ SessionType session_type_;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
new file mode 100644
index 0000000..1e55a0b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderFactoryAIDL"
+
+#include "BluetoothAudioProviderFactory.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <android-base/logging.h>
+
+#include "A2dpOffloadAudioProvider.h"
+#include "A2dpSoftwareAudioProvider.h"
+#include "BluetoothAudioProvider.h"
+#include "HearingAidAudioProvider.h"
+#include "LeAudioOffloadAudioProvider.h"
+#include "LeAudioSoftwareAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
+
+ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
+ const SessionType session_type,
+ std::shared_ptr<IBluetoothAudioProvider>* _aidl_return) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type);
+ std::shared_ptr<BluetoothAudioProvider> provider = nullptr;
+
+ switch (session_type) {
+ case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make<A2dpSoftwareAudioProvider>();
+ break;
+ case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make<A2dpOffloadAudioProvider>();
+ break;
+ case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make<HearingAidAudioProvider>();
+ break;
+ case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make<LeAudioSoftwareOutputAudioProvider>();
+ break;
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ provider = ndk::SharedRefBase::make<LeAudioOffloadOutputAudioProvider>();
+ break;
+ case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
+ provider = ndk::SharedRefBase::make<LeAudioSoftwareInputAudioProvider>();
+ break;
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ provider = ndk::SharedRefBase::make<LeAudioOffloadInputAudioProvider>();
+ break;
+ default:
+ provider = nullptr;
+ break;
+ }
+
+ if (provider == nullptr || !provider->isValid(session_type)) {
+ provider = nullptr;
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = provider;
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderCapabilities(
+ const SessionType session_type,
+ std::vector<AudioCapabilities>* _aidl_return) {
+ if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ auto codec_capabilities =
+ BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(session_type);
+ _aidl_return->resize(codec_capabilities.size());
+ for (int i = 0; i < codec_capabilities.size(); i++) {
+ _aidl_return->at(i).set<AudioCapabilities::a2dpCapabilities>(
+ codec_capabilities[i]);
+ }
+ } else if (session_type ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ std::vector<LeAudioCodecCapabilitiesSetting> db_codec_capabilities =
+ BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(session_type);
+ if (db_codec_capabilities.size()) {
+ _aidl_return->resize(db_codec_capabilities.size());
+ for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+ _aidl_return->at(i).set<AudioCapabilities::leAudioCapabilities>(
+ db_codec_capabilities[i]);
+ }
+ }
+ } else if (session_type != SessionType::UNKNOWN) {
+ auto pcm_capabilities = BluetoothAudioCodecs::GetSoftwarePcmCapabilities();
+ _aidl_return->resize(pcm_capabilities.size());
+ for (int i = 0; i < pcm_capabilities.size(); i++) {
+ _aidl_return->at(i).set<AudioCapabilities::pcmCapabilities>(
+ pcm_capabilities[i]);
+ }
+ }
+
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type)
+ << " supports " << _aidl_return->size() << " codecs";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
new file mode 100644
index 0000000..b38cfd2
--- /dev/null
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioProviderFactory.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioProviderFactory : public BnBluetoothAudioProviderFactory {
+ public:
+ BluetoothAudioProviderFactory();
+
+ ndk::ScopedAStatus openProvider(
+ const SessionType session_type,
+ std::shared_ptr<IBluetoothAudioProvider>* _aidl_return) override;
+
+ ndk::ScopedAStatus getProviderCapabilities(
+ const SessionType session_type,
+ std::vector<AudioCapabilities>* _aidl_return) override;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
new file mode 100644
index 0000000..66ce93b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderHearingAid"
+
+#include "HearingAidAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
+static constexpr uint32_t kPcmFrameCount = 128;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+static constexpr uint32_t kRtpFrameCount = 7; // max counts by 1 tick (20ms)
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 1; // single buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+HearingAidAudioProvider::HearingAidAudioProvider()
+ : BluetoothAudioProvider(), data_mq_(nullptr) {
+ LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+ << " byte(s)";
+ std::unique_ptr<DataMQ> data_mq(
+ new DataMQ(kDataMqSize, /* EventFlag */ true));
+ if (data_mq && data_mq->isValid()) {
+ data_mq_ = std::move(data_mq);
+ session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+ } else {
+ ALOGE_IF(!data_mq, "failed to allocate data MQ");
+ ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
+ }
+}
+bool HearingAidAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
+}
+
+ndk::ScopedAStatus HearingAidAudioProvider::startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const auto& pcm_config = audio_config.get<AudioConfiguration::pcmConfig>();
+ if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << pcm_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return BluetoothAudioProvider::startSession(host_if, audio_config,
+ _aidl_return);
+}
+
+ndk::ScopedAStatus HearingAidAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ if (data_mq_ == nullptr || !data_mq_->isValid()) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = data_mq_->dupeDesc();
+ auto desc = data_mq_->dupeDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+ &desc, *audio_config_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/HearingAidAudioProvider.h b/bluetooth/audio/aidl/default/HearingAidAudioProvider.h
new file mode 100644
index 0000000..a7e19e9
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HearingAidAudioProvider.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class HearingAidAudioProvider : public BluetoothAudioProvider {
+ public:
+ HearingAidAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+ // audio data queue for software encoding
+ std::unique_ptr<DataMQ> data_mq_;
+
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
new file mode 100644
index 0000000..72ac9bd
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderLeAudioHW"
+
+#include "LeAudioOffloadAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+}
+
+LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
+ : BluetoothAudioProvider() {}
+
+bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const auto& le_audio_config =
+ audio_config.get<AudioConfiguration::leAudioConfig>();
+ if (!BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
+ session_type_, le_audio_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
+ << le_audio_config.toString();
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return BluetoothAudioProvider::startSession(host_if, audio_config,
+ _aidl_return);
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+ nullptr, *audio_config_);
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
new file mode 100644
index 0000000..a27a2e7
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+ LeAudioOffloadAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadOutputAudioProvider();
+};
+
+class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadInputAudioProvider();
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..67b7d60
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderLeAudioSW"
+
+#include "LeAudioSoftwareAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+#include <cstdint>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr uint32_t kBufferOutCount = 2; // two frame buffer
+static constexpr uint32_t kBufferInCount = 2; // two frame buffer
+
+inline uint32_t channel_mode_to_channel_count(ChannelMode channel_mode) {
+ switch (channel_mode) {
+ case ChannelMode::MONO:
+ return 1;
+ case ChannelMode::STEREO:
+ return 2;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+LeAudioSoftwareOutputAudioProvider::LeAudioSoftwareOutputAudioProvider()
+ : LeAudioSoftwareAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+}
+
+LeAudioSoftwareInputAudioProvider::LeAudioSoftwareInputAudioProvider()
+ : LeAudioSoftwareAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH;
+}
+
+LeAudioSoftwareAudioProvider::LeAudioSoftwareAudioProvider()
+ : BluetoothAudioProvider(), data_mq_(nullptr) {}
+
+bool LeAudioSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus LeAudioSoftwareAudioProvider::startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+ if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+ << audio_config.toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const auto& pcm_config = audio_config.get<AudioConfiguration::pcmConfig>();
+ if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+ LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+ << pcm_config.toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ uint32_t buffer_modifier = 0;
+ if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH)
+ buffer_modifier = kBufferOutCount;
+ else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH)
+ buffer_modifier = kBufferInCount;
+
+ uint32_t data_mq_size =
+ (ceil(pcm_config.sampleRateHz) / 1000) *
+ channel_mode_to_channel_count(pcm_config.channelMode) *
+ (pcm_config.bitsPerSample / 8) * (pcm_config.dataIntervalUs / 1000) *
+ buffer_modifier;
+ if (data_mq_size <= 0) {
+ LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
+ << ", SampleRateHz: " << pcm_config.sampleRateHz
+ << ", ChannelMode: " << toString(pcm_config.channelMode)
+ << ", BitsPerSample: "
+ << static_cast<int>(pcm_config.bitsPerSample)
+ << ", DataIntervalUs: " << pcm_config.dataIntervalUs
+ << ", SessionType: " << toString(session_type_);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size
+ << " byte(s)";
+
+ std::unique_ptr<DataMQ> temp_data_mq(
+ new DataMQ(data_mq_size, /* EventFlag */ true));
+ if (temp_data_mq == nullptr || !temp_data_mq->isValid()) {
+ ALOGE_IF(!temp_data_mq, "failed to allocate data MQ");
+ ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid");
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ data_mq_ = std::move(temp_data_mq);
+
+ return BluetoothAudioProvider::startSession(host_if, audio_config,
+ _aidl_return);
+}
+
+ndk::ScopedAStatus LeAudioSoftwareAudioProvider::onSessionReady(
+ DataMQDesc* _aidl_return) {
+ if (data_mq_ == nullptr || !data_mq_->isValid()) {
+ *_aidl_return = DataMQDesc();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = data_mq_->dupeDesc();
+ auto desc = data_mq_->dupeDesc();
+ BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+ &desc, *audio_config_);
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
new file mode 100644
index 0000000..fa58182
--- /dev/null
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class LeAudioSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+ LeAudioSoftwareAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+
+ ndk::ScopedAStatus startSession(
+ const std::shared_ptr<IBluetoothAudioPort>& host_if,
+ const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+
+ private:
+ // audio data queue for software encoding
+ std::unique_ptr<DataMQ> data_mq_;
+
+ ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class LeAudioSoftwareOutputAudioProvider : public LeAudioSoftwareAudioProvider {
+ public:
+ LeAudioSoftwareOutputAudioProvider();
+};
+
+class LeAudioSoftwareInputAudioProvider : public LeAudioSoftwareAudioProvider {
+ public:
+ LeAudioSoftwareInputAudioProvider();
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/OWNERS b/bluetooth/audio/aidl/default/OWNERS
new file mode 100644
index 0000000..17ea464
--- /dev/null
+++ b/bluetooth/audio/aidl/default/OWNERS
@@ -0,0 +1,4 @@
+include platform/packages/modules/Bluetooth:/OWNERS
+
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/default/bluetooth_audio.xml b/bluetooth/audio/aidl/default/bluetooth_audio.xml
new file mode 100644
index 0000000..1859a1a
--- /dev/null
+++ b/bluetooth/audio/aidl/default/bluetooth_audio.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.bluetooth.audio</name>
+ <fqname>IBluetoothAudioProviderFactory/default</fqname>
+ </hal>
+</manifest>
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/vts/OWNERS b/bluetooth/audio/aidl/vts/OWNERS
new file mode 100644
index 0000000..17ea464
--- /dev/null
+++ b/bluetooth/audio/aidl/vts/OWNERS
@@ -0,0 +1,4 @@
+include platform/packages/modules/Bluetooth:/OWNERS
+
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 4f712bf..974357e 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -32,5 +32,30 @@
"libhidlbase",
"liblog",
"libutils",
+ "libbluetooth_audio_session_aidl",
+ ],
+}
+
+cc_library_shared {
+ name: "libbluetooth_audio_session_aidl",
+ vendor: true,
+ srcs: [
+ "aidl_session/BluetoothAudioCodecs.cpp",
+ "aidl_session/BluetoothAudioSession.cpp",
+ "aidl_session/HidlToAidlMiddleware.cpp",
+ ],
+ export_include_dirs: ["aidl_session/"],
+ header_libs: ["libhardware_headers"],
+ shared_libs: [
+ "android.hardware.bluetooth.audio@2.0",
+ "android.hardware.bluetooth.audio@2.1",
+ "android.hardware.bluetooth.audio@2.2",
+ "libbase",
+ "libcutils",
+ "libbinder_ndk",
+ "libfmq",
+ "liblog",
+ "android.hardware.bluetooth.audio-V1-ndk",
+ "libhidlbase",
],
}
diff --git a/bluetooth/audio/utils/OWNERS b/bluetooth/audio/utils/OWNERS
index ed92847..17ea464 100644
--- a/bluetooth/audio/utils/OWNERS
+++ b/bluetooth/audio/utils/OWNERS
@@ -1,3 +1,4 @@
include platform/packages/modules/Bluetooth:/OWNERS
-cheneyni@google.com
\ No newline at end of file
+cheneyni@google.com
+aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
new file mode 100644
index 0000000..516ebe8
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -0,0 +1,490 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioCodecsAidl"
+
+#include "BluetoothAudioCodecs.h"
+
+#include <aidl/android/hardware/bluetooth/audio/AacCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/AacObjectType.h>
+#include <aidl/android/hardware/bluetooth/audio/AptxCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/LdacQualityIndex.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SbcCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
+ .sampleRateHz = {16000, 24000, 44100, 48000, 88200, 96000},
+ .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
+ .bitsPerSample = {16, 24, 32},
+ .dataIntervalUs = {},
+};
+
+static const SbcCapabilities kDefaultOffloadSbcCapability = {
+ .sampleRateHz = {44100},
+ .channelMode = {SbcChannelMode::MONO, SbcChannelMode::JOINT_STEREO},
+ .blockLength = {4, 8, 12, 16},
+ .numSubbands = {8},
+ .allocMethod = {SbcAllocMethod::ALLOC_MD_L},
+ .bitsPerSample = {16},
+ .minBitpool = 2,
+ .maxBitpool = 53};
+
+static const AacCapabilities kDefaultOffloadAacCapability = {
+ .objectType = {AacObjectType::MPEG2_LC},
+ .sampleRateHz = {44100},
+ .channelMode = {ChannelMode::STEREO},
+ .variableBitRateSupported = true,
+ .bitsPerSample = {16}};
+
+static const LdacCapabilities kDefaultOffloadLdacCapability = {
+ .sampleRateHz = {44100, 48000, 88200, 96000},
+ .channelMode = {LdacChannelMode::DUAL, LdacChannelMode::STEREO},
+ .qualityIndex = {LdacQualityIndex::HIGH},
+ .bitsPerSample = {16, 24, 32}};
+
+static const AptxCapabilities kDefaultOffloadAptxCapability = {
+ .sampleRateHz = {44100, 48000},
+ .channelMode = {ChannelMode::STEREO},
+ .bitsPerSample = {16},
+};
+
+static const AptxCapabilities kDefaultOffloadAptxHdCapability = {
+ .sampleRateHz = {44100, 48000},
+ .channelMode = {ChannelMode::STEREO},
+ .bitsPerSample = {24},
+};
+
+static const Lc3Capabilities kDefaultA2dpOffloadLc3Capability = {
+ .samplingFrequencyHz = {44100, 48000},
+ .frameDurationUs = {7500, 10000},
+ .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
+};
+
+const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
+ {.codecType = CodecType::SBC, .capabilities = {}},
+ {.codecType = CodecType::AAC, .capabilities = {}},
+ {.codecType = CodecType::LDAC, .capabilities = {}},
+ {.codecType = CodecType::APTX, .capabilities = {}},
+ {.codecType = CodecType::APTX_HD, .capabilities = {}},
+ {.codecType = CodecType::LC3, .capabilities = {}}};
+
+std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
+
+static const UnicastCapability kInvalidUnicastCapability = {
+ .codecType = CodecType::UNKNOWN};
+
+static const BroadcastCapability kInvalidBroadcastCapability = {
+ .codecType = CodecType::UNKNOWN};
+
+// Default Supported Codecs
+// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30
+static const Lc3Capabilities kLc3Capability_16_1 = {
+ .samplingFrequencyHz = {16000},
+ .frameDurationUs = {7500},
+ .octetsPerFrame = {30}};
+
+// Default Supported Codecs
+// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
+static const Lc3Capabilities kLc3Capability_16_2 = {
+ .samplingFrequencyHz = {16000},
+ .frameDurationUs = {10000},
+ .octetsPerFrame = {40}};
+
+// Default Supported Codecs
+// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
+static const Lc3Capabilities kLc3Capability_48_4 = {
+ .samplingFrequencyHz = {48000},
+ .frameDurationUs = {10000},
+ .octetsPerFrame = {120}};
+
+static const std::vector<Lc3Capabilities> supportedLc3CapabilityList = {
+ kLc3Capability_48_4, kLc3Capability_16_2, kLc3Capability_16_1};
+
+static AudioLocation stereoAudio = static_cast<AudioLocation>(
+ static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
+ static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
+static AudioLocation monoAudio = AudioLocation::UNKNOWN;
+
+// Stores the supported setting of audio location, connected device, and the
+// channel count for each device
+std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
+ supportedDeviceSetting = {std::make_tuple(stereoAudio, 2, 1),
+ std::make_tuple(monoAudio, 1, 2),
+ std::make_tuple(monoAudio, 1, 1)};
+
+template <class T>
+bool BluetoothAudioCodecs::ContainedInVector(
+ const std::vector<T>& vector, const typename identity<T>::type& target) {
+ return std::find(vector.begin(), vector.end(), target) != vector.end();
+}
+
+bool BluetoothAudioCodecs::IsOffloadSbcConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::sbcConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const SbcConfiguration sbc_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::sbcConfig>();
+
+ if (ContainedInVector(kDefaultOffloadSbcCapability.sampleRateHz,
+ sbc_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.blockLength,
+ sbc_data.blockLength) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.numSubbands,
+ sbc_data.numSubbands) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.bitsPerSample,
+ sbc_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.channelMode,
+ sbc_data.channelMode) &&
+ ContainedInVector(kDefaultOffloadSbcCapability.allocMethod,
+ sbc_data.allocMethod) &&
+ sbc_data.minBitpool <= sbc_data.maxBitpool &&
+ kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool &&
+ kDefaultOffloadSbcCapability.maxBitpool >= sbc_data.maxBitpool) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::aacConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const AacConfiguration aac_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::aacConfig>();
+
+ if (ContainedInVector(kDefaultOffloadAacCapability.sampleRateHz,
+ aac_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadAacCapability.bitsPerSample,
+ aac_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadAacCapability.channelMode,
+ aac_data.channelMode) &&
+ ContainedInVector(kDefaultOffloadAacCapability.objectType,
+ aac_data.objectType) &&
+ (!aac_data.variableBitRateEnabled ||
+ kDefaultOffloadAacCapability.variableBitRateSupported)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLdacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() !=
+ CodecConfiguration::CodecSpecific::ldacConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const LdacConfiguration ldac_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::ldacConfig>();
+
+ if (ContainedInVector(kDefaultOffloadLdacCapability.sampleRateHz,
+ ldac_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadLdacCapability.bitsPerSample,
+ ldac_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadLdacCapability.channelMode,
+ ldac_data.channelMode) &&
+ ContainedInVector(kDefaultOffloadLdacCapability.qualityIndex,
+ ldac_data.qualityIndex)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAptxConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() !=
+ CodecConfiguration::CodecSpecific::aptxConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const AptxConfiguration aptx_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
+
+ if (ContainedInVector(kDefaultOffloadAptxCapability.sampleRateHz,
+ aptx_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadAptxCapability.bitsPerSample,
+ aptx_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadAptxCapability.channelMode,
+ aptx_data.channelMode)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadAptxHdConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() !=
+ CodecConfiguration::CodecSpecific::aptxConfig) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const AptxConfiguration aptx_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
+
+ if (ContainedInVector(kDefaultOffloadAptxHdCapability.sampleRateHz,
+ aptx_data.sampleRateHz) &&
+ ContainedInVector(kDefaultOffloadAptxHdCapability.bitsPerSample,
+ aptx_data.bitsPerSample) &&
+ ContainedInVector(kDefaultOffloadAptxHdCapability.channelMode,
+ aptx_data.channelMode)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLc3ConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific) {
+ if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::lc3Config) {
+ LOG(WARNING) << __func__
+ << ": Invalid CodecSpecific=" << codec_specific.toString();
+ return false;
+ }
+ const Lc3Configuration lc3_data =
+ codec_specific.get<CodecConfiguration::CodecSpecific::lc3Config>();
+
+ if (ContainedInVector(kDefaultA2dpOffloadLc3Capability.samplingFrequencyHz,
+ lc3_data.samplingFrequencyHz) &&
+ ContainedInVector(kDefaultA2dpOffloadLc3Capability.frameDurationUs,
+ lc3_data.frameDurationUs) &&
+ ContainedInVector(kDefaultA2dpOffloadLc3Capability.channelMode,
+ lc3_data.channelMode)) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << codec_specific.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
+ const SessionType& session_type, const LeAudioConfiguration&) {
+ if (session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return false;
+ }
+ return true;
+}
+
+std::vector<PcmCapabilities>
+BluetoothAudioCodecs::GetSoftwarePcmCapabilities() {
+ return {kDefaultSoftwarePcmCapabilities};
+}
+
+std::vector<CodecCapabilities>
+BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(
+ const SessionType& session_type) {
+ if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return {};
+ }
+ std::vector<CodecCapabilities> offload_a2dp_codec_capabilities =
+ kDefaultOffloadA2dpCodecCapabilities;
+ for (auto& codec_capability : offload_a2dp_codec_capabilities) {
+ switch (codec_capability.codecType) {
+ case CodecType::SBC:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::sbcCapabilities>(
+ kDefaultOffloadSbcCapability);
+ break;
+ case CodecType::AAC:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::aacCapabilities>(
+ kDefaultOffloadAacCapability);
+ break;
+ case CodecType::LDAC:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::ldacCapabilities>(
+ kDefaultOffloadLdacCapability);
+ break;
+ case CodecType::APTX:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::aptxCapabilities>(
+ kDefaultOffloadAptxCapability);
+ break;
+ case CodecType::APTX_HD:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::aptxCapabilities>(
+ kDefaultOffloadAptxHdCapability);
+ break;
+ case CodecType::LC3:
+ codec_capability.capabilities
+ .set<CodecCapabilities::Capabilities::lc3Capabilities>(
+ kDefaultA2dpOffloadLc3Capability);
+ break;
+ case CodecType::UNKNOWN:
+ case CodecType::VENDOR:
+ break;
+ }
+ }
+ return offload_a2dp_codec_capabilities;
+}
+
+bool BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(
+ const PcmConfiguration& pcm_config) {
+ if (ContainedInVector(kDefaultSoftwarePcmCapabilities.sampleRateHz,
+ pcm_config.sampleRateHz) &&
+ ContainedInVector(kDefaultSoftwarePcmCapabilities.bitsPerSample,
+ pcm_config.bitsPerSample) &&
+ ContainedInVector(kDefaultSoftwarePcmCapabilities.channelMode,
+ pcm_config.channelMode)
+ // data interval is not checked for now
+ // && pcm_config.dataIntervalUs != 0
+ ) {
+ return true;
+ }
+ LOG(WARNING) << __func__
+ << ": Unsupported CodecSpecific=" << pcm_config.toString();
+ return false;
+}
+
+bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+ const SessionType& session_type, const CodecConfiguration& codec_config) {
+ if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ LOG(ERROR) << __func__
+ << ": Invalid SessionType=" << toString(session_type);
+ return false;
+ }
+ const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config;
+ switch (codec_config.codecType) {
+ case CodecType::SBC:
+ if (IsOffloadSbcConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::AAC:
+ if (IsOffloadAacConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::LDAC:
+ if (IsOffloadLdacConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::APTX:
+ if (IsOffloadAptxConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::APTX_HD:
+ if (IsOffloadAptxHdConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::LC3:
+ if (IsOffloadLc3ConfigurationValid(codec_specific)) {
+ return true;
+ }
+ break;
+ case CodecType::UNKNOWN:
+ case CodecType::VENDOR:
+ break;
+ }
+ return false;
+}
+
+UnicastCapability composeUnicastLc3Capability(
+ AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount,
+ const Lc3Capabilities& capability) {
+ return {
+ .codecType = CodecType::LC3,
+ .supportedChannel = audioLocation,
+ .deviceCount = deviceCnt,
+ .channelCountPerDevice = channelCount,
+ .leAudioCodecCapabilities =
+ UnicastCapability::LeAudioCodecCapabilities(capability),
+ };
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
+ const SessionType& session_type) {
+ if (session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return std::vector<LeAudioCodecCapabilitiesSetting>(0);
+ }
+
+ if (kDefaultOffloadLeAudioCapabilities.empty()) {
+ for (auto [audioLocation, deviceCnt, channelCount] :
+ supportedDeviceSetting) {
+ for (auto capability : supportedLc3CapabilityList) {
+ UnicastCapability lc3Capability = composeUnicastLc3Capability(
+ audioLocation, deviceCnt, channelCount, capability);
+ UnicastCapability lc3MonoDecodeCapability =
+ composeUnicastLc3Capability(monoAudio, 1, 1, capability);
+
+ // Adds the capability for encode only
+ kDefaultOffloadLeAudioCapabilities.push_back(
+ {.unicastEncodeCapability = lc3Capability,
+ .unicastDecodeCapability = kInvalidUnicastCapability,
+ .broadcastCapability = kInvalidBroadcastCapability});
+
+ // Adds the capability for decode only
+ kDefaultOffloadLeAudioCapabilities.push_back(
+ {.unicastEncodeCapability = kInvalidUnicastCapability,
+ .unicastDecodeCapability = lc3Capability,
+ .broadcastCapability = kInvalidBroadcastCapability});
+
+ // Adds the capability for the case that encode and decode exist at the
+ // same time
+ kDefaultOffloadLeAudioCapabilities.push_back(
+ {.unicastEncodeCapability = lc3Capability,
+ .unicastDecodeCapability = lc3MonoDecodeCapability,
+ .broadcastCapability = kInvalidBroadcastCapability});
+ }
+ }
+ }
+
+ return kDefaultOffloadLeAudioCapabilities;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
new file mode 100644
index 0000000..0259a7e
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/CodecCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/Lc3Configuration.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioCodecs {
+ public:
+ static std::vector<PcmCapabilities> GetSoftwarePcmCapabilities();
+ static std::vector<CodecCapabilities> GetA2dpOffloadCodecCapabilities(
+ const SessionType& session_type);
+
+ static bool IsSoftwarePcmConfigurationValid(
+ const PcmConfiguration& pcm_config);
+ static bool IsOffloadCodecConfigurationValid(
+ const SessionType& session_type, const CodecConfiguration& codec_config);
+
+ static bool IsOffloadLeAudioConfigurationValid(
+ const SessionType& session_type, const LeAudioConfiguration&);
+
+ static std::vector<LeAudioCodecCapabilitiesSetting>
+ GetLeAudioOffloadCodecCapabilities(const SessionType& session_type);
+
+ private:
+ template <typename T>
+ struct identity {
+ typedef T type;
+ };
+ template <class T>
+ static bool ContainedInVector(const std::vector<T>& vector,
+ const typename identity<T>::type& target);
+ template <class T>
+ static bool ContainedInBitmask(const T& bitmask, const T& target);
+ static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield);
+ static bool IsOffloadSbcConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadAacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadLdacConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadAptxConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadAptxHdConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+ static bool IsOffloadLc3ConfigurationValid(
+ const CodecConfiguration::CodecSpecific& codec_specific);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
new file mode 100644
index 0000000..f626db8
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -0,0 +1,550 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#define LOG_TAG "BTAudioSessionAidl"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_manager.h>
+
+#include "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr int kFmqSendTimeoutMs = 1000; // 1000 ms timeout for sending
+static constexpr int kFmqReceiveTimeoutMs =
+ 1000; // 1000 ms timeout for receiving
+static constexpr int kWritePollMs = 1; // polled non-blocking interval
+static constexpr int kReadPollMs = 1; // polled non-blocking interval
+
+BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
+ : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {}
+
+/***
+ *
+ * Callback methods
+ *
+ ***/
+
+void BluetoothAudioSession::OnSessionStarted(
+ const std::shared_ptr<IBluetoothAudioPort> stack_iface,
+ const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (stack_iface == nullptr) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", IBluetoothAudioPort Invalid";
+ } else if (!UpdateAudioConfig(audio_config)) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", AudioConfiguration=" << audio_config.toString()
+ << " Invalid";
+ } else if (!UpdateDataPath(mq_desc)) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << " MqDescriptor Invalid";
+ audio_config_ = nullptr;
+ } else {
+ stack_iface_ = stack_iface;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", AudioConfiguration=" << audio_config.toString();
+ ReportSessionStatus();
+ }
+}
+
+void BluetoothAudioSession::OnSessionEnded() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ bool toggled = IsSessionReady();
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+ audio_config_ = nullptr;
+ stack_iface_ = nullptr;
+ UpdateDataPath(nullptr);
+ if (toggled) {
+ ReportSessionStatus();
+ }
+}
+
+/***
+ *
+ * Util methods
+ *
+ ***/
+
+const AudioConfiguration BluetoothAudioSession::GetAudioConfig() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ switch (session_type_) {
+ case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ return AudioConfiguration(CodecConfiguration{});
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ return AudioConfiguration(LeAudioConfiguration{});
+ default:
+ return AudioConfiguration(PcmConfiguration{});
+ }
+ }
+ return *audio_config_;
+}
+
+void BluetoothAudioSession::ReportAudioConfigChanged(
+ const AudioConfiguration& audio_config) {
+ if (session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return;
+ }
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+ if (observers_.empty()) {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO port state observer";
+ return;
+ }
+ for (auto& observer : observers_) {
+ uint16_t cookie = observer.first;
+ std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
+ LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_)
+ << ", bluetooth_audio=0x"
+ << ::android::base::StringPrintf("%04x", cookie);
+ if (cb->audio_configuration_changed_cb_ != nullptr) {
+ cb->audio_configuration_changed_cb_(cookie);
+ }
+ }
+}
+
+bool BluetoothAudioSession::IsSessionReady() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+
+ bool is_mq_valid =
+ (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+ (data_mq_ != nullptr && data_mq_->isValid()));
+ return stack_iface_ != nullptr && is_mq_valid && audio_config_ != nullptr;
+}
+
+/***
+ *
+ * Status callback methods
+ *
+ ***/
+
+uint16_t BluetoothAudioSession::RegisterStatusCback(
+ const PortStatusCallbacks& callbacks) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ uint16_t cookie = ObserversCookieGetInitValue(session_type_);
+ uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
+
+ while (cookie < cookie_upper_bound) {
+ if (observers_.find(cookie) == observers_.end()) {
+ break;
+ }
+ ++cookie;
+ }
+ if (cookie >= cookie_upper_bound) {
+ LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has " << observers_.size()
+ << " observers already (No Resource)";
+ return kObserversCookieUndefined;
+ }
+ std::shared_ptr<PortStatusCallbacks> cb =
+ std::make_shared<PortStatusCallbacks>();
+ *cb = callbacks;
+ observers_[cookie] = cb;
+ return cookie;
+}
+
+void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (observers_.erase(cookie) != 1) {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << " no such provider=0x"
+ << ::android::base::StringPrintf("%04x", cookie);
+ }
+}
+
+/***
+ *
+ * Stream methods
+ *
+ ***/
+
+bool BluetoothAudioSession::StartStream() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+ auto hal_retval = stack_iface_->startStream();
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ return false;
+ }
+ return true;
+}
+
+bool BluetoothAudioSession::SuspendStream() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+ auto hal_retval = stack_iface_->suspendStream();
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ return false;
+ }
+ return true;
+}
+
+void BluetoothAudioSession::StopStream() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ return;
+ }
+ auto hal_retval = stack_iface_->stopStream();
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ }
+}
+
+/***
+ *
+ * Private methods
+ *
+ ***/
+
+bool BluetoothAudioSession::UpdateDataPath(const DataMQDesc* mq_desc) {
+ if (mq_desc == nullptr) {
+ // usecase of reset by nullptr
+ data_mq_ = nullptr;
+ return true;
+ }
+ std::unique_ptr<DataMQ> temp_mq;
+ temp_mq.reset(new DataMQ(*mq_desc));
+ if (!temp_mq || !temp_mq->isValid()) {
+ data_mq_ = nullptr;
+ return false;
+ }
+ data_mq_ = std::move(temp_mq);
+ return true;
+}
+
+bool BluetoothAudioSession::UpdateAudioConfig(
+ const AudioConfiguration& audio_config) {
+ bool is_software_session =
+ (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
+ session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
+ bool is_offload_a2dp_session =
+ (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+ bool is_offload_le_audio_session =
+ (session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+ auto audio_config_tag = audio_config.getTag();
+ bool is_software_audio_config =
+ (is_software_session &&
+ audio_config_tag == AudioConfiguration::pcmConfig);
+ bool is_a2dp_offload_audio_config =
+ (is_offload_a2dp_session &&
+ audio_config_tag == AudioConfiguration::a2dpConfig);
+ bool is_le_audio_offload_audio_config =
+ (is_offload_le_audio_session &&
+ audio_config_tag == AudioConfiguration::leAudioConfig);
+ if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
+ !is_le_audio_offload_audio_config) {
+ return false;
+ }
+ audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+ return true;
+}
+
+void BluetoothAudioSession::ReportSessionStatus() {
+ // This is locked already by OnSessionStarted / OnSessionEnded
+ if (observers_.empty()) {
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO port state observer";
+ return;
+ }
+ for (auto& observer : observers_) {
+ uint16_t cookie = observer.first;
+ std::shared_ptr<PortStatusCallbacks> callback = observer.second;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << " notify to bluetooth_audio=0x"
+ << ::android::base::StringPrintf("%04x", cookie);
+ callback->session_changed_cb_(cookie);
+ }
+}
+
+/***
+ *
+ * PCM methods
+ *
+ ***/
+
+size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
+ size_t bytes) {
+ if (buffer == nullptr || bytes <= 0) {
+ return 0;
+ }
+ size_t total_written = 0;
+ int timeout_ms = kFmqSendTimeoutMs;
+ do {
+ std::unique_lock<std::recursive_mutex> lock(mutex_);
+ if (!IsSessionReady()) {
+ break;
+ }
+ size_t num_bytes_to_write = data_mq_->availableToWrite();
+ if (num_bytes_to_write) {
+ if (num_bytes_to_write > (bytes - total_written)) {
+ num_bytes_to_write = bytes - total_written;
+ }
+
+ if (!data_mq_->write(
+ static_cast<const MQDataType*>(buffer) + total_written,
+ num_bytes_to_write)) {
+ LOG(ERROR) << "FMQ datapath writing " << total_written << "/" << bytes
+ << " failed";
+ return total_written;
+ }
+ total_written += num_bytes_to_write;
+ } else if (timeout_ms >= kWritePollMs) {
+ lock.unlock();
+ usleep(kWritePollMs * 1000);
+ timeout_ms -= kWritePollMs;
+ } else {
+ LOG(DEBUG) << "Data " << total_written << "/" << bytes << " overflow "
+ << (kFmqSendTimeoutMs - timeout_ms) << " ms";
+ return total_written;
+ }
+ } while (total_written < bytes);
+ return total_written;
+}
+
+size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
+ if (buffer == nullptr || bytes <= 0) {
+ return 0;
+ }
+ size_t total_read = 0;
+ int timeout_ms = kFmqReceiveTimeoutMs;
+ do {
+ std::unique_lock<std::recursive_mutex> lock(mutex_);
+ if (!IsSessionReady()) {
+ break;
+ }
+ size_t num_bytes_to_read = data_mq_->availableToRead();
+ if (num_bytes_to_read) {
+ if (num_bytes_to_read > (bytes - total_read)) {
+ num_bytes_to_read = bytes - total_read;
+ }
+ if (!data_mq_->read(static_cast<MQDataType*>(buffer) + total_read,
+ num_bytes_to_read)) {
+ LOG(ERROR) << "FMQ datapath reading " << total_read << "/" << bytes
+ << " failed";
+ return total_read;
+ }
+ total_read += num_bytes_to_read;
+ } else if (timeout_ms >= kReadPollMs) {
+ lock.unlock();
+ usleep(kReadPollMs * 1000);
+ timeout_ms -= kReadPollMs;
+ continue;
+ } else {
+ LOG(DEBUG) << "Data " << total_read << "/" << bytes << " overflow "
+ << (kFmqReceiveTimeoutMs - timeout_ms) << " ms";
+ return total_read;
+ }
+ } while (total_read < bytes);
+ return total_read;
+}
+
+/***
+ *
+ * Other methods
+ *
+ ***/
+
+void BluetoothAudioSession::ReportControlStatus(bool start_resp,
+ BluetoothAudioStatus status) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (observers_.empty()) {
+ LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO port state observer";
+ return;
+ }
+ for (auto& observer : observers_) {
+ uint16_t cookie = observer.first;
+ std::shared_ptr<PortStatusCallbacks> callback = observer.second;
+ LOG(INFO) << __func__ << " - status=" << toString(status)
+ << " for SessionType=" << toString(session_type_)
+ << ", bluetooth_audio=0x"
+ << ::android::base::StringPrintf("%04x", cookie)
+ << (start_resp ? " started" : " suspended");
+ callback->control_result_cb_(cookie, start_resp, status);
+ }
+}
+
+bool BluetoothAudioSession::GetPresentationPosition(
+ PresentationPosition& presentation_position) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+ bool retval = false;
+
+ if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ return false;
+ }
+ return retval;
+}
+
+void BluetoothAudioSession::UpdateSourceMetadata(
+ const struct source_metadata& source_metadata) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return;
+ }
+
+ ssize_t track_count = source_metadata.track_count;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
+ << track_count << " track(s)";
+ if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return;
+ }
+
+ SourceMetadata hal_source_metadata;
+ hal_source_metadata.tracks.resize(track_count);
+ for (int i = 0; i < track_count; i++) {
+ hal_source_metadata.tracks[i].usage =
+ static_cast<media::audio::common::AudioUsage>(
+ source_metadata.tracks[i].usage);
+ hal_source_metadata.tracks[i].contentType =
+ static_cast<media::audio::common::AudioContentType>(
+ source_metadata.tracks[i].content_type);
+ hal_source_metadata.tracks[i].gain = source_metadata.tracks[i].gain;
+ LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", usage=" << toString(hal_source_metadata.tracks[i].usage)
+ << ", content="
+ << toString(hal_source_metadata.tracks[i].contentType)
+ << ", gain=" << hal_source_metadata.tracks[i].gain;
+ }
+
+ auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ }
+}
+
+void BluetoothAudioSession::UpdateSinkMetadata(
+ const struct sink_metadata& sink_metadata) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return;
+ }
+
+ ssize_t track_count = sink_metadata.track_count;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
+ << track_count << " track(s)";
+ if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return;
+ }
+
+ SinkMetadata hal_sink_metadata;
+ hal_sink_metadata.tracks.resize(track_count);
+ for (int i = 0; i < track_count; i++) {
+ hal_sink_metadata.tracks[i].source =
+ static_cast<media::audio::common::AudioSource>(
+ sink_metadata.tracks[i].source);
+ hal_sink_metadata.tracks[i].gain = sink_metadata.tracks[i].gain;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+ << ", source=" << sink_metadata.tracks[i].source
+ << ", dest_device=" << sink_metadata.tracks[i].dest_device
+ << ", gain=" << sink_metadata.tracks[i].gain
+ << ", dest_device_address="
+ << sink_metadata.tracks[i].dest_device_address;
+ }
+
+ auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ }
+}
+
+bool BluetoothAudioSession::IsAidlAvailable() {
+ if (is_aidl_checked) return is_aidl_available;
+ is_aidl_available =
+ (AServiceManager_checkService(
+ kDefaultAudioProviderFactoryInterface.c_str()) != nullptr);
+ is_aidl_checked = true;
+ return is_aidl_available;
+}
+
+/***
+ *
+ * BluetoothAudioSessionInstance
+ *
+ ***/
+std::mutex BluetoothAudioSessionInstance::mutex_;
+std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+ BluetoothAudioSessionInstance::sessions_map_;
+
+std::shared_ptr<BluetoothAudioSession>
+BluetoothAudioSessionInstance::GetSessionInstance(
+ const SessionType& session_type) {
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ if (!sessions_map_.empty()) {
+ auto entry = sessions_map_.find(session_type);
+ if (entry != sessions_map_.end()) {
+ return entry->second;
+ }
+ }
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ std::make_shared<BluetoothAudioSession>(session_type);
+ sessions_map_[session_type] = session_ptr;
+ return session_ptr;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
new file mode 100644
index 0000000..73bc0f8
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/common/SinkMetadata.h>
+#include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hardware/audio.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using ::aidl::android::hardware::audio::common::SinkMetadata;
+using ::aidl::android::hardware::audio::common::SourceMetadata;
+
+using MQDataType = int8_t;
+using MQDataMode = SynchronizedReadWrite;
+using DataMQ = AidlMessageQueue<MQDataType, MQDataMode>;
+using DataMQDesc =
+ ::aidl::android::hardware::common::fmq::MQDescriptor<MQDataType,
+ MQDataMode>;
+
+static constexpr uint16_t kObserversCookieSize = 0x0010; // 0x0000 ~ 0x000f
+static constexpr uint16_t kObserversCookieUndefined =
+ (static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00);
+inline SessionType ObserversCookieGetSessionType(uint16_t cookie) {
+ return static_cast<SessionType>(cookie >> 8 & 0x00ff);
+}
+inline uint16_t ObserversCookieGetInitValue(SessionType session_type) {
+ return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
+}
+inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) {
+ return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
+ kObserversCookieSize;
+}
+
+/***
+ * This presents the callbacks of started / suspended and session changed,
+ * and the bluetooth_audio module uses to receive the status notification
+ ***/
+struct PortStatusCallbacks {
+ /***
+ * control_result_cb_ - when the Bluetooth stack reports results of
+ * streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
+ * this callback to report to the bluetooth_audio module.
+ * @param: cookie - indicates which bluetooth_audio output should handle
+ * @param: start_resp - this report is for startStream or not
+ * @param: status - the result of startStream
+ ***/
+ std::function<void(uint16_t cookie, bool start_resp,
+ BluetoothAudioStatus status)>
+ control_result_cb_;
+ /***
+ * session_changed_cb_ - when the Bluetooth stack start / end session, the
+ * BluetoothAudioProvider will invoke this callback to notify to the
+ * bluetooth_audio module.
+ * @param: cookie - indicates which bluetooth_audio output should handle
+ ***/
+ std::function<void(uint16_t cookie)> session_changed_cb_;
+ /***
+ * audio_configuration_changed_cb_ - when the Bluetooth stack change the audio
+ * configuration, the BluetoothAudioProvider will invoke this callback to
+ * notify to the bluetooth_audio module.
+ * @param: cookie - indicates which bluetooth_audio output should handle
+ ***/
+ std::function<void(uint16_t cookie)> audio_configuration_changed_cb_;
+};
+
+class BluetoothAudioSession {
+ public:
+ BluetoothAudioSession(const SessionType& session_type);
+
+ /***
+ * The function helps to check if this session is ready or not
+ * @return: true if the Bluetooth stack has started the specified session
+ ***/
+ bool IsSessionReady();
+
+ /***
+ * The report function is used to report that the Bluetooth stack has started
+ * this session without any failure, and will invoke session_changed_cb_ to
+ * notify those registered bluetooth_audio outputs
+ ***/
+ void OnSessionStarted(const std::shared_ptr<IBluetoothAudioPort> stack_iface,
+ const DataMQDesc* mq_desc,
+ const AudioConfiguration& audio_config);
+
+ /***
+ * The report function is used to report that the Bluetooth stack has ended
+ * the session, and will invoke session_changed_cb_ to notify registered
+ * bluetooth_audio outputs
+ ***/
+ void OnSessionEnded();
+
+ /***
+ * The report function is used to report that the Bluetooth stack has notified
+ * the result of startStream or suspendStream, and will invoke
+ * control_result_cb_ to notify registered bluetooth_audio outputs
+ ***/
+ void ReportControlStatus(bool start_resp, BluetoothAudioStatus status);
+
+ /***
+ * The control function helps the bluetooth_audio module to register
+ * PortStatusCallbacks
+ * @return: cookie - the assigned number to this bluetooth_audio output
+ ***/
+ uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks);
+
+ /***
+ * The control function helps the bluetooth_audio module to unregister
+ * PortStatusCallbacks
+ * @param: cookie - indicates which bluetooth_audio output is
+ ***/
+ void UnregisterStatusCback(uint16_t cookie);
+
+ /***
+ * The control function is for the bluetooth_audio module to get the current
+ * AudioConfiguration
+ ***/
+ const AudioConfiguration GetAudioConfig();
+
+ /***
+ * The report function is used to report that the Bluetooth stack has notified
+ * the audio configuration changed, and will invoke
+ * audio_configuration_changed_cb_ to notify registered bluetooth_audio
+ * outputs
+ ***/
+ void ReportAudioConfigChanged(const AudioConfiguration& audio_config);
+
+ /***
+ * Those control functions are for the bluetooth_audio module to start,
+ * suspend, stop stream, to check position, and to update metadata.
+ ***/
+ bool StartStream();
+ bool SuspendStream();
+ void StopStream();
+ bool GetPresentationPosition(PresentationPosition& presentation_position);
+ void UpdateSourceMetadata(const struct source_metadata& source_metadata);
+ void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
+
+ // The control function writes stream to FMQ
+ size_t OutWritePcmData(const void* buffer, size_t bytes);
+ // The control function read stream from FMQ
+ size_t InReadPcmData(void* buffer, size_t bytes);
+
+ // Return if IBluetoothAudioProviderFactory implementation existed
+ static bool IsAidlAvailable();
+
+ private:
+ // using recursive_mutex to allow hwbinder to re-enter again.
+ std::recursive_mutex mutex_;
+ SessionType session_type_;
+
+ // audio control path to use for both software and offloading
+ std::shared_ptr<IBluetoothAudioPort> stack_iface_;
+ // audio data path (FMQ) for software encoding
+ std::unique_ptr<DataMQ> data_mq_;
+ // audio data configuration for both software and offloading
+ std::unique_ptr<AudioConfiguration> audio_config_;
+
+ // saving those registered bluetooth_audio's callbacks
+ std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
+ observers_;
+
+ bool UpdateDataPath(const DataMQDesc* mq_desc);
+ bool UpdateAudioConfig(const AudioConfiguration& audio_config);
+ // invoking the registered session_changed_cb_
+ void ReportSessionStatus();
+
+ static inline std::atomic<bool> is_aidl_checked = false;
+ static inline std::atomic<bool> is_aidl_available = false;
+ static inline const std::string kDefaultAudioProviderFactoryInterface =
+ std::string() + IBluetoothAudioProviderFactory::descriptor + "/default";
+};
+
+class BluetoothAudioSessionInstance {
+ public:
+ // The API is to fetch the specified session of A2DP / Hearing Aid
+ static std::shared_ptr<BluetoothAudioSession> GetSessionInstance(
+ const SessionType& session_type);
+
+ private:
+ static std::mutex mutex_;
+ static std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+ sessions_map_;
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
new file mode 100644
index 0000000..aff01e5
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2018 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 "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionControl {
+ public:
+ /***
+ * The control API helps to check if session is ready or not
+ * @return: true if the Bluetooth stack has started th specified session
+ ***/
+ static bool IsSessionReady(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->IsSessionReady();
+ }
+
+ return false;
+ }
+
+ /***
+ * The control API helps the bluetooth_audio module to register
+ * PortStatusCallbacks
+ * @return: cookie - the assigned number to this bluetooth_audio output
+ ***/
+ static uint16_t RegisterControlResultCback(
+ const SessionType& session_type, const PortStatusCallbacks& cbacks) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->RegisterStatusCback(cbacks);
+ }
+ return kObserversCookieUndefined;
+ }
+
+ /***
+ * The control API helps the bluetooth_audio module to unregister
+ * PortStatusCallbacks
+ * @param: cookie - indicates which bluetooth_audio output is
+ ***/
+ static void UnregisterControlResultCback(const SessionType& session_type,
+ uint16_t cookie) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->UnregisterStatusCback(cookie);
+ }
+ }
+
+ /***
+ * The control API for the bluetooth_audio module to get current
+ * AudioConfiguration
+ ***/
+ static const AudioConfiguration GetAudioConfig(
+ const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->GetAudioConfig();
+ }
+ switch (session_type) {
+ case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ return AudioConfiguration(CodecConfiguration{});
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ return AudioConfiguration(LeAudioConfiguration{});
+ default:
+ return AudioConfiguration(PcmConfiguration{});
+ }
+ }
+
+ /***
+ * Those control APIs for the bluetooth_audio module to start / suspend /
+ stop
+ * stream, to check position, and to update metadata.
+ ***/
+ static bool StartStream(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->StartStream();
+ }
+ return false;
+ }
+
+ static bool SuspendStream(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->SuspendStream();
+ }
+ return false;
+ }
+
+ static void StopStream(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->StopStream();
+ }
+ }
+
+ static bool GetPresentationPosition(
+ const SessionType& session_type,
+ PresentationPosition& presentation_position) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->GetPresentationPosition(presentation_position);
+ }
+ return false;
+ }
+
+ static void UpdateSourceMetadata(
+ const SessionType& session_type,
+ const struct source_metadata& source_metadata) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->UpdateSourceMetadata(source_metadata);
+ }
+ }
+
+ static void UpdateSinkMetadata(const SessionType& session_type,
+ const struct sink_metadata& sink_metadata) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->UpdateSinkMetadata(sink_metadata);
+ }
+ }
+
+ /***
+ * The control API writes stream to FMQ
+ ***/
+ static size_t OutWritePcmData(const SessionType& session_type,
+ const void* buffer, size_t bytes) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->OutWritePcmData(buffer, bytes);
+ }
+ return 0;
+ }
+
+ /***
+ * The control API reads stream from FMQ
+ ***/
+ static size_t InReadPcmData(const SessionType& session_type, void* buffer,
+ size_t bytes) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->InReadPcmData(buffer, bytes);
+ }
+ return 0;
+ }
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
new file mode 100644
index 0000000..18569c3
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionReport {
+ public:
+ /***
+ * The API reports the Bluetooth stack has started the session, and will
+ * inform registered bluetooth_audio outputs
+ ***/
+ static void OnSessionStarted(
+ const SessionType& session_type,
+ const std::shared_ptr<IBluetoothAudioPort> host_iface,
+ const DataMQDesc* data_mq, const AudioConfiguration& audio_config) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->OnSessionStarted(host_iface, data_mq, audio_config);
+ }
+ }
+
+ /***
+ * The API reports the Bluetooth stack has ended the session, and will
+ * inform registered bluetooth_audio outputs
+ ***/
+ static void OnSessionEnded(const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->OnSessionEnded();
+ }
+ }
+
+ /***
+ * The API reports the Bluetooth stack has replied the result of startStream
+ * or suspendStream, and will inform registered bluetooth_audio outputs
+ ***/
+ static void ReportControlStatus(const SessionType& session_type,
+ const bool& start_resp,
+ BluetoothAudioStatus status) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->ReportControlStatus(start_resp, status);
+ }
+ }
+ /***
+ * The API reports the Bluetooth stack has replied the changed of the audio
+ * configuration, and will inform registered bluetooth_audio outputs
+ ***/
+ static void ReportAudioConfigChanged(const SessionType& session_type,
+ const AudioConfiguration& audio_config) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->ReportAudioConfigChanged(audio_config);
+ }
+ }
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
new file mode 100644
index 0000000..632a389
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
@@ -0,0 +1,787 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BtAudioNakahara"
+
+#include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <android-base/logging.h>
+
+#include <functional>
+#include <unordered_map>
+
+#include "../aidl_session/BluetoothAudioSession.h"
+#include "../aidl_session/BluetoothAudioSessionControl.h"
+#include "HidlToAidlMiddleware_2_0.h"
+#include "HidlToAidlMiddleware_2_1.h"
+#include "HidlToAidlMiddleware_2_2.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using HidlStatus = ::android::hardware::bluetooth::audio::V2_0::Status;
+using PcmConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using SampleRate_2_0 = ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ChannelMode_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using BitsPerSample_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using CodecConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using CodecType_2_0 = ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using SbcConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+using AacConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using LdacConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using AptxConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using SbcAllocMethod_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using SbcBlockLength_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using SbcChannelMode_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using SbcNumSubbands_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using AacObjectType_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using AacVarBitRate_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using LdacChannelMode_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using LdacQualityIndex_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+
+using PcmConfig_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::PcmParameters;
+using SampleRate_2_1 = ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+using Lc3CodecConfig_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration;
+using Lc3Config_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::Lc3Parameters;
+using Lc3FrameDuration_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::Lc3FrameDuration;
+
+using LeAudioConfig_2_2 =
+ ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
+using LeAudioMode_2_2 =
+ ::android::hardware::bluetooth::audio::V2_2::LeAudioMode;
+
+std::mutex legacy_callback_lock;
+std::unordered_map<
+ SessionType,
+ std::unordered_map<uint16_t, std::shared_ptr<PortStatusCallbacks_2_2>>>
+ legacy_callback_table;
+
+const static std::unordered_map<SessionType_2_1, SessionType>
+ session_type_2_1_to_aidl_map{
+ {SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH},
+ {SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH,
+ SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
+ {SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH,
+ SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
+ {SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH},
+ };
+
+const static std::unordered_map<int32_t, SampleRate_2_1>
+ sample_rate_to_hidl_2_1_map{
+ {44100, SampleRate_2_1::RATE_44100},
+ {48000, SampleRate_2_1::RATE_48000},
+ {88200, SampleRate_2_1::RATE_88200},
+ {96000, SampleRate_2_1::RATE_96000},
+ {176400, SampleRate_2_1::RATE_176400},
+ {192000, SampleRate_2_1::RATE_192000},
+ {16000, SampleRate_2_1::RATE_16000},
+ {24000, SampleRate_2_1::RATE_24000},
+ {8000, SampleRate_2_1::RATE_8000},
+ {32000, SampleRate_2_1::RATE_32000},
+ };
+
+const static std::unordered_map<CodecType, CodecType_2_0>
+ codec_type_to_hidl_2_0_map{
+ {CodecType::UNKNOWN, CodecType_2_0::UNKNOWN},
+ {CodecType::SBC, CodecType_2_0::SBC},
+ {CodecType::AAC, CodecType_2_0::AAC},
+ {CodecType::APTX, CodecType_2_0::APTX},
+ {CodecType::APTX_HD, CodecType_2_0::APTX_HD},
+ {CodecType::LDAC, CodecType_2_0::LDAC},
+ {CodecType::LC3, CodecType_2_0::UNKNOWN},
+ };
+
+const static std::unordered_map<SbcChannelMode, SbcChannelMode_2_0>
+ sbc_channel_mode_to_hidl_2_0_map{
+ {SbcChannelMode::UNKNOWN, SbcChannelMode_2_0::UNKNOWN},
+ {SbcChannelMode::JOINT_STEREO, SbcChannelMode_2_0::JOINT_STEREO},
+ {SbcChannelMode::STEREO, SbcChannelMode_2_0::STEREO},
+ {SbcChannelMode::DUAL, SbcChannelMode_2_0::DUAL},
+ {SbcChannelMode::MONO, SbcChannelMode_2_0::MONO},
+ };
+
+const static std::unordered_map<int8_t, SbcBlockLength_2_0>
+ sbc_block_length_to_hidl_map{
+ {4, SbcBlockLength_2_0::BLOCKS_4},
+ {8, SbcBlockLength_2_0::BLOCKS_8},
+ {12, SbcBlockLength_2_0::BLOCKS_12},
+ {16, SbcBlockLength_2_0::BLOCKS_16},
+ };
+
+const static std::unordered_map<int8_t, SbcNumSubbands_2_0>
+ sbc_subbands_to_hidl_map{
+ {4, SbcNumSubbands_2_0::SUBBAND_4},
+ {8, SbcNumSubbands_2_0::SUBBAND_8},
+ };
+
+const static std::unordered_map<SbcAllocMethod, SbcAllocMethod_2_0>
+ sbc_alloc_method_to_hidl_map{
+ {SbcAllocMethod::ALLOC_MD_S, SbcAllocMethod_2_0::ALLOC_MD_S},
+ {SbcAllocMethod::ALLOC_MD_L, SbcAllocMethod_2_0::ALLOC_MD_L},
+ };
+
+const static std::unordered_map<AacObjectType, AacObjectType_2_0>
+ aac_object_type_to_hidl_map{
+ {AacObjectType::MPEG2_LC, AacObjectType_2_0::MPEG2_LC},
+ {AacObjectType::MPEG4_LC, AacObjectType_2_0::MPEG4_LC},
+ {AacObjectType::MPEG4_LTP, AacObjectType_2_0::MPEG4_LTP},
+ {AacObjectType::MPEG4_SCALABLE, AacObjectType_2_0::MPEG4_SCALABLE},
+ };
+
+const static std::unordered_map<LdacChannelMode, LdacChannelMode_2_0>
+ ldac_channel_mode_to_hidl_map{
+ {LdacChannelMode::UNKNOWN, LdacChannelMode_2_0::UNKNOWN},
+ {LdacChannelMode::STEREO, LdacChannelMode_2_0::STEREO},
+ {LdacChannelMode::DUAL, LdacChannelMode_2_0::DUAL},
+ {LdacChannelMode::MONO, LdacChannelMode_2_0::MONO},
+ };
+
+const static std::unordered_map<LdacQualityIndex, LdacQualityIndex_2_0>
+ ldac_qindex_to_hidl_map{
+ {LdacQualityIndex::HIGH, LdacQualityIndex_2_0::QUALITY_HIGH},
+ {LdacQualityIndex::MID, LdacQualityIndex_2_0::QUALITY_MID},
+ {LdacQualityIndex::LOW, LdacQualityIndex_2_0::QUALITY_LOW},
+ {LdacQualityIndex::ABR, LdacQualityIndex_2_0::QUALITY_ABR},
+ };
+
+inline SessionType from_session_type_2_1(
+ const SessionType_2_1& session_type_hidl) {
+ auto it = session_type_2_1_to_aidl_map.find(session_type_hidl);
+ if (it != session_type_2_1_to_aidl_map.end()) return it->second;
+ return SessionType::UNKNOWN;
+}
+
+inline SessionType from_session_type_2_0(
+ const SessionType_2_0& session_type_hidl) {
+ return from_session_type_2_1(static_cast<SessionType_2_1>(session_type_hidl));
+}
+
+inline HidlStatus to_hidl_status(const BluetoothAudioStatus& status) {
+ switch (status) {
+ case BluetoothAudioStatus::SUCCESS:
+ return HidlStatus::SUCCESS;
+ case BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION:
+ return HidlStatus::UNSUPPORTED_CODEC_CONFIGURATION;
+ default:
+ return HidlStatus::FAILURE;
+ }
+}
+
+inline SampleRate_2_1 to_hidl_sample_rate_2_1(const int32_t sample_rate_hz) {
+ auto it = sample_rate_to_hidl_2_1_map.find(sample_rate_hz);
+ if (it != sample_rate_to_hidl_2_1_map.end()) return it->second;
+ return SampleRate_2_1::RATE_UNKNOWN;
+}
+
+inline SampleRate_2_0 to_hidl_sample_rate_2_0(const int32_t sample_rate_hz) {
+ auto it = sample_rate_to_hidl_2_1_map.find(sample_rate_hz);
+ if (it != sample_rate_to_hidl_2_1_map.end())
+ return static_cast<SampleRate_2_0>(it->second);
+ return SampleRate_2_0::RATE_UNKNOWN;
+}
+
+inline BitsPerSample_2_0 to_hidl_bits_per_sample(const int8_t bit_per_sample) {
+ switch (bit_per_sample) {
+ case 16:
+ return BitsPerSample_2_0::BITS_16;
+ case 24:
+ return BitsPerSample_2_0::BITS_24;
+ case 32:
+ return BitsPerSample_2_0::BITS_32;
+ default:
+ return BitsPerSample_2_0::BITS_UNKNOWN;
+ }
+}
+
+inline ChannelMode_2_0 to_hidl_channel_mode(const ChannelMode channel_mode) {
+ switch (channel_mode) {
+ case ChannelMode::MONO:
+ return ChannelMode_2_0::MONO;
+ case ChannelMode::STEREO:
+ return ChannelMode_2_0::STEREO;
+ default:
+ return ChannelMode_2_0::UNKNOWN;
+ }
+}
+
+inline PcmConfig_2_0 to_hidl_pcm_config_2_0(
+ const PcmConfiguration& pcm_config) {
+ PcmConfig_2_0 hidl_pcm_config;
+ hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_0(pcm_config.sampleRateHz);
+ hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
+ hidl_pcm_config.bitsPerSample =
+ to_hidl_bits_per_sample(pcm_config.bitsPerSample);
+ return hidl_pcm_config;
+}
+
+inline CodecType_2_0 to_hidl_codec_type_2_0(const CodecType codec_type) {
+ auto it = codec_type_to_hidl_2_0_map.find(codec_type);
+ if (it != codec_type_to_hidl_2_0_map.end()) return it->second;
+ return CodecType_2_0::UNKNOWN;
+}
+
+inline SbcConfig_2_0 to_hidl_sbc_config(const SbcConfiguration sbc_config) {
+ SbcConfig_2_0 hidl_sbc_config;
+ hidl_sbc_config.minBitpool = sbc_config.minBitpool;
+ hidl_sbc_config.maxBitpool = sbc_config.maxBitpool;
+ hidl_sbc_config.sampleRate = to_hidl_sample_rate_2_0(sbc_config.sampleRateHz);
+ hidl_sbc_config.bitsPerSample =
+ to_hidl_bits_per_sample(sbc_config.bitsPerSample);
+ if (sbc_channel_mode_to_hidl_2_0_map.find(sbc_config.channelMode) !=
+ sbc_channel_mode_to_hidl_2_0_map.end()) {
+ hidl_sbc_config.channelMode =
+ sbc_channel_mode_to_hidl_2_0_map.at(sbc_config.channelMode);
+ }
+ if (sbc_block_length_to_hidl_map.find(sbc_config.blockLength) !=
+ sbc_block_length_to_hidl_map.end()) {
+ hidl_sbc_config.blockLength =
+ sbc_block_length_to_hidl_map.at(sbc_config.blockLength);
+ }
+ if (sbc_subbands_to_hidl_map.find(sbc_config.numSubbands) !=
+ sbc_subbands_to_hidl_map.end()) {
+ hidl_sbc_config.numSubbands =
+ sbc_subbands_to_hidl_map.at(sbc_config.numSubbands);
+ }
+ if (sbc_alloc_method_to_hidl_map.find(sbc_config.allocMethod) !=
+ sbc_alloc_method_to_hidl_map.end()) {
+ hidl_sbc_config.allocMethod =
+ sbc_alloc_method_to_hidl_map.at(sbc_config.allocMethod);
+ }
+ return hidl_sbc_config;
+}
+
+inline AacConfig_2_0 to_hidl_aac_config(const AacConfiguration aac_config) {
+ AacConfig_2_0 hidl_aac_config;
+ hidl_aac_config.sampleRate = to_hidl_sample_rate_2_0(aac_config.sampleRateHz);
+ hidl_aac_config.bitsPerSample =
+ to_hidl_bits_per_sample(aac_config.bitsPerSample);
+ hidl_aac_config.channelMode = to_hidl_channel_mode(aac_config.channelMode);
+ if (aac_object_type_to_hidl_map.find(aac_config.objectType) !=
+ aac_object_type_to_hidl_map.end()) {
+ hidl_aac_config.objectType =
+ aac_object_type_to_hidl_map.at(aac_config.objectType);
+ }
+ hidl_aac_config.variableBitRateEnabled = aac_config.variableBitRateEnabled
+ ? AacVarBitRate_2_0::ENABLED
+ : AacVarBitRate_2_0::DISABLED;
+ return hidl_aac_config;
+}
+
+inline LdacConfig_2_0 to_hidl_ldac_config(const LdacConfiguration ldac_config) {
+ LdacConfig_2_0 hidl_ldac_config;
+ hidl_ldac_config.sampleRate =
+ to_hidl_sample_rate_2_0(ldac_config.sampleRateHz);
+ hidl_ldac_config.bitsPerSample =
+ to_hidl_bits_per_sample(ldac_config.bitsPerSample);
+ if (ldac_channel_mode_to_hidl_map.find(ldac_config.channelMode) !=
+ ldac_channel_mode_to_hidl_map.end()) {
+ hidl_ldac_config.channelMode =
+ ldac_channel_mode_to_hidl_map.at(ldac_config.channelMode);
+ }
+ if (ldac_qindex_to_hidl_map.find(ldac_config.qualityIndex) !=
+ ldac_qindex_to_hidl_map.end()) {
+ hidl_ldac_config.qualityIndex =
+ ldac_qindex_to_hidl_map.at(ldac_config.qualityIndex);
+ }
+ return hidl_ldac_config;
+}
+
+inline AptxConfig_2_0 to_hidl_aptx_config(const AptxConfiguration aptx_config) {
+ AptxConfig_2_0 hidl_aptx_config;
+ hidl_aptx_config.sampleRate =
+ to_hidl_sample_rate_2_0(aptx_config.sampleRateHz);
+ hidl_aptx_config.bitsPerSample =
+ to_hidl_bits_per_sample(aptx_config.bitsPerSample);
+ hidl_aptx_config.channelMode = to_hidl_channel_mode(aptx_config.channelMode);
+ return hidl_aptx_config;
+}
+
+inline CodecConfig_2_0 to_hidl_codec_config_2_0(
+ const CodecConfiguration& codec_config) {
+ CodecConfig_2_0 hidl_codec_config;
+ hidl_codec_config.codecType = to_hidl_codec_type_2_0(codec_config.codecType);
+ hidl_codec_config.encodedAudioBitrate =
+ static_cast<uint32_t>(codec_config.encodedAudioBitrate);
+ hidl_codec_config.peerMtu = static_cast<uint32_t>(codec_config.peerMtu);
+ hidl_codec_config.isScmstEnabled = codec_config.isScmstEnabled;
+ switch (codec_config.config.getTag()) {
+ case CodecConfiguration::CodecSpecific::sbcConfig:
+ hidl_codec_config.config.sbcConfig(to_hidl_sbc_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::sbcConfig>()));
+ break;
+ case CodecConfiguration::CodecSpecific::aacConfig:
+ hidl_codec_config.config.aacConfig(to_hidl_aac_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::aacConfig>()));
+ break;
+ case CodecConfiguration::CodecSpecific::ldacConfig:
+ hidl_codec_config.config.ldacConfig(to_hidl_ldac_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::ldacConfig>()));
+ break;
+ case CodecConfiguration::CodecSpecific::aptxConfig:
+ hidl_codec_config.config.aptxConfig(to_hidl_aptx_config(
+ codec_config.config
+ .get<CodecConfiguration::CodecSpecific::aptxConfig>()));
+ break;
+ default:
+ break;
+ }
+ return hidl_codec_config;
+}
+
+inline AudioConfig_2_0 to_hidl_audio_config_2_0(
+ const AudioConfiguration& audio_config) {
+ AudioConfig_2_0 hidl_audio_config;
+ if (audio_config.getTag() == AudioConfiguration::pcmConfig) {
+ hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_0(
+ audio_config.get<AudioConfiguration::pcmConfig>()));
+ } else if (audio_config.getTag() == AudioConfiguration::a2dpConfig) {
+ hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+ audio_config.get<AudioConfiguration::a2dpConfig>()));
+ }
+ return hidl_audio_config;
+}
+
+inline PcmConfig_2_1 to_hidl_pcm_config_2_1(
+ const PcmConfiguration& pcm_config) {
+ PcmConfig_2_1 hidl_pcm_config;
+ hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_1(pcm_config.sampleRateHz);
+ hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
+ hidl_pcm_config.bitsPerSample =
+ to_hidl_bits_per_sample(pcm_config.bitsPerSample);
+ hidl_pcm_config.dataIntervalUs =
+ static_cast<uint32_t>(pcm_config.dataIntervalUs);
+ return hidl_pcm_config;
+}
+
+inline Lc3Config_2_1 to_hidl_lc3_config_2_1(
+ const Lc3Configuration& lc3_config) {
+ Lc3Config_2_1 hidl_lc3_config;
+ hidl_lc3_config.pcmBitDepth = to_hidl_bits_per_sample(lc3_config.pcmBitDepth);
+ hidl_lc3_config.samplingFrequency =
+ to_hidl_sample_rate_2_1(lc3_config.samplingFrequencyHz);
+ if (lc3_config.samplingFrequencyHz == 10000)
+ hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_10000US;
+ else if (lc3_config.samplingFrequencyHz == 7500)
+ hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_7500US;
+ hidl_lc3_config.octetsPerFrame =
+ static_cast<uint32_t>(lc3_config.octetsPerFrame);
+ hidl_lc3_config.blocksPerSdu = static_cast<uint32_t>(lc3_config.blocksPerSdu);
+ return hidl_lc3_config;
+}
+
+inline Lc3CodecConfig_2_1 to_hidl_leaudio_config_2_1(
+ const LeAudioConfiguration& leaudio_config) {
+ Lc3CodecConfig_2_1 hidl_lc3_codec_config = {
+ .audioChannelAllocation = 0,
+ };
+ if (leaudio_config.modeConfig.getTag() ==
+ LeAudioConfiguration::LeAudioModeConfig::unicastConfig) {
+ auto& unicast_config =
+ leaudio_config.modeConfig
+ .get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
+ if (unicast_config.leAudioCodecConfig.getTag() ==
+ LeAudioCodecConfiguration::lc3Config) {
+ LOG(FATAL) << __func__ << ": unexpected codec type(vendor?)";
+ }
+ auto& le_codec_config = unicast_config.leAudioCodecConfig
+ .get<LeAudioCodecConfiguration::lc3Config>();
+
+ hidl_lc3_codec_config.lc3Config = to_hidl_lc3_config_2_1(le_codec_config);
+
+ for (const auto& map : unicast_config.streamMap) {
+ hidl_lc3_codec_config.audioChannelAllocation |=
+ map.audioChannelAllocation;
+ }
+ } else {
+ // NOTE: Broadcast is not officially supported in HIDL
+ auto& bcast_config =
+ leaudio_config.modeConfig
+ .get<LeAudioConfiguration::LeAudioModeConfig::broadcastConfig>();
+ if (bcast_config.streamMap.empty()) {
+ return hidl_lc3_codec_config;
+ }
+ if (bcast_config.streamMap[0].leAudioCodecConfig.getTag() !=
+ LeAudioCodecConfiguration::lc3Config) {
+ LOG(FATAL) << __func__ << ": unexpected codec type(vendor?)";
+ }
+ auto& le_codec_config =
+ bcast_config.streamMap[0]
+ .leAudioCodecConfig.get<LeAudioCodecConfiguration::lc3Config>();
+ hidl_lc3_codec_config.lc3Config = to_hidl_lc3_config_2_1(le_codec_config);
+
+ for (const auto& map : bcast_config.streamMap) {
+ hidl_lc3_codec_config.audioChannelAllocation |=
+ map.audioChannelAllocation;
+ }
+ }
+
+ return hidl_lc3_codec_config;
+}
+
+inline LeAudioConfig_2_2 to_hidl_leaudio_config_2_2(
+ const LeAudioConfiguration& leaudio_config) {
+ LeAudioConfig_2_2 hidl_leaudio_config;
+
+ if (leaudio_config.modeConfig.getTag() ==
+ LeAudioConfiguration::LeAudioModeConfig::unicastConfig) {
+ hidl_leaudio_config.mode = LeAudioMode_2_2::UNICAST;
+ auto& unicast_config =
+ leaudio_config.modeConfig
+ .get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
+ ::android::hardware::bluetooth::audio::V2_2::UnicastConfig
+ hidl_unicast_config;
+ hidl_unicast_config.peerDelay =
+ static_cast<uint32_t>(unicast_config.peerDelay);
+
+ auto& lc3_config = unicast_config.leAudioCodecConfig
+ .get<LeAudioCodecConfiguration::lc3Config>();
+ hidl_unicast_config.lc3Config = to_hidl_lc3_config_2_1(lc3_config);
+
+ hidl_unicast_config.streamMap.resize(unicast_config.streamMap.size());
+ for (int i = 0; i < unicast_config.streamMap.size(); i++) {
+ hidl_unicast_config.streamMap[i].audioChannelAllocation =
+ static_cast<uint32_t>(
+ unicast_config.streamMap[i].audioChannelAllocation);
+ hidl_unicast_config.streamMap[i].streamHandle =
+ static_cast<uint16_t>(unicast_config.streamMap[i].streamHandle);
+ }
+ } else if (leaudio_config.modeConfig.getTag() ==
+ LeAudioConfiguration::LeAudioModeConfig::broadcastConfig) {
+ hidl_leaudio_config.mode = LeAudioMode_2_2::BROADCAST;
+ auto bcast_config =
+ leaudio_config.modeConfig
+ .get<LeAudioConfiguration::LeAudioModeConfig::broadcastConfig>();
+ ::android::hardware::bluetooth::audio::V2_2::BroadcastConfig
+ hidl_bcast_config;
+ hidl_bcast_config.streamMap.resize(bcast_config.streamMap.size());
+ for (int i = 0; i < bcast_config.streamMap.size(); i++) {
+ hidl_bcast_config.streamMap[i].audioChannelAllocation =
+ static_cast<uint32_t>(
+ bcast_config.streamMap[i].audioChannelAllocation);
+ hidl_bcast_config.streamMap[i].streamHandle =
+ static_cast<uint16_t>(bcast_config.streamMap[i].streamHandle);
+ hidl_bcast_config.streamMap[i].lc3Config = to_hidl_lc3_config_2_1(
+ bcast_config.streamMap[i]
+ .leAudioCodecConfig.get<LeAudioCodecConfiguration::lc3Config>());
+ }
+ }
+ return hidl_leaudio_config;
+}
+
+inline AudioConfig_2_1 to_hidl_audio_config_2_1(
+ const AudioConfiguration& audio_config) {
+ AudioConfig_2_1 hidl_audio_config;
+ switch (audio_config.getTag()) {
+ case AudioConfiguration::pcmConfig:
+ hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
+ audio_config.get<AudioConfiguration::pcmConfig>()));
+ break;
+ case AudioConfiguration::a2dpConfig:
+ hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+ audio_config.get<AudioConfiguration::a2dpConfig>()));
+ break;
+ case AudioConfiguration::leAudioConfig:
+ hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_config_2_1(
+ audio_config.get<AudioConfiguration::leAudioConfig>()));
+ break;
+ }
+ return hidl_audio_config;
+}
+
+inline AudioConfig_2_2 to_hidl_audio_config_2_2(
+ const AudioConfiguration& audio_config) {
+ AudioConfig_2_2 hidl_audio_config;
+ switch (audio_config.getTag()) {
+ case AudioConfiguration::pcmConfig:
+ hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
+ audio_config.get<AudioConfiguration::pcmConfig>()));
+ break;
+ case AudioConfiguration::a2dpConfig:
+ hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
+ audio_config.get<AudioConfiguration::a2dpConfig>()));
+ break;
+ case AudioConfiguration::leAudioConfig:
+ hidl_audio_config.leAudioConfig(to_hidl_leaudio_config_2_2(
+ audio_config.get<AudioConfiguration::leAudioConfig>()));
+ break;
+ }
+ return hidl_audio_config;
+}
+
+/***
+ *
+ * 2.0
+ *
+ ***/
+
+bool HidlToAidlMiddleware_2_0::IsSessionReady(
+ const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::IsSessionReady(
+ from_session_type_2_0(session_type));
+}
+
+uint16_t HidlToAidlMiddleware_2_0::RegisterControlResultCback(
+ const SessionType_2_0& session_type,
+ const PortStatusCallbacks_2_0& cbacks) {
+ PortStatusCallbacks_2_2 callback_2_2{
+ .control_result_cb_ = cbacks.control_result_cb_,
+ .session_changed_cb_ = cbacks.session_changed_cb_,
+ };
+ return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+ static_cast<SessionType_2_1>(session_type), callback_2_2);
+}
+
+void HidlToAidlMiddleware_2_0::UnregisterControlResultCback(
+ const SessionType_2_0& session_type, uint16_t cookie) {
+ HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+ static_cast<SessionType_2_1>(session_type), cookie);
+}
+
+const AudioConfig_2_0 HidlToAidlMiddleware_2_0::GetAudioConfig(
+ const SessionType_2_0& session_type) {
+ return to_hidl_audio_config_2_0(BluetoothAudioSessionControl::GetAudioConfig(
+ from_session_type_2_0(session_type)));
+}
+
+bool HidlToAidlMiddleware_2_0::StartStream(
+ const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::StartStream(
+ from_session_type_2_0(session_type));
+}
+
+void HidlToAidlMiddleware_2_0::StopStream(const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::StopStream(
+ from_session_type_2_0(session_type));
+}
+
+bool HidlToAidlMiddleware_2_0::SuspendStream(
+ const SessionType_2_0& session_type) {
+ return BluetoothAudioSessionControl::SuspendStream(
+ from_session_type_2_0(session_type));
+}
+
+bool HidlToAidlMiddleware_2_0::GetPresentationPosition(
+ const SessionType_2_0& session_type, uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_readed, timespec* data_position) {
+ PresentationPosition presentation_position;
+ auto ret_val = BluetoothAudioSessionControl::GetPresentationPosition(
+ from_session_type_2_0(session_type), presentation_position);
+ if (remote_delay_report_ns)
+ *remote_delay_report_ns = presentation_position.remoteDeviceAudioDelayNanos;
+ if (total_bytes_readed)
+ *total_bytes_readed = presentation_position.transmittedOctets;
+ if (data_position)
+ *data_position = {
+ .tv_sec = static_cast<__kernel_old_time_t>(
+ presentation_position.transmittedOctetsTimestamp.tvSec),
+ .tv_nsec = static_cast<long>(
+ presentation_position.transmittedOctetsTimestamp.tvNSec)};
+ return ret_val;
+}
+
+void HidlToAidlMiddleware_2_0::UpdateTracksMetadata(
+ const SessionType_2_0& session_type,
+ const struct source_metadata* source_metadata) {
+ return BluetoothAudioSessionControl::UpdateSourceMetadata(
+ from_session_type_2_0(session_type), *source_metadata);
+}
+
+size_t HidlToAidlMiddleware_2_0::OutWritePcmData(
+ const SessionType_2_0& session_type, const void* buffer, size_t bytes) {
+ return BluetoothAudioSessionControl::OutWritePcmData(
+ from_session_type_2_0(session_type), buffer, bytes);
+}
+
+size_t HidlToAidlMiddleware_2_0::InReadPcmData(
+ const SessionType_2_0& session_type, void* buffer, size_t bytes) {
+ return BluetoothAudioSessionControl::InReadPcmData(
+ from_session_type_2_0(session_type), buffer, bytes);
+}
+
+bool HidlToAidlMiddleware_2_0::IsAidlAvailable() {
+ return BluetoothAudioSession::IsAidlAvailable();
+}
+
+/***
+ *
+ * 2.1
+ *
+ ***/
+
+const AudioConfig_2_1 HidlToAidlMiddleware_2_1::GetAudioConfig(
+ const SessionType_2_1& session_type) {
+ return to_hidl_audio_config_2_1(BluetoothAudioSessionControl::GetAudioConfig(
+ from_session_type_2_1(session_type)));
+}
+
+/***
+ *
+ * 2.2
+ *
+ ***/
+
+bool HidlToAidlMiddleware_2_2::IsSessionReady(
+ const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::IsSessionReady(
+ from_session_type_2_1(session_type));
+}
+
+uint16_t HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+ const SessionType_2_1& session_type,
+ const PortStatusCallbacks_2_2& cbacks) {
+ LOG(INFO) << __func__ << ": " << toString(session_type);
+ auto aidl_session_type = from_session_type_2_1(session_type);
+ // Pass the exact reference to the lambda
+ auto& session_legacy_callback_table =
+ legacy_callback_table[aidl_session_type];
+ PortStatusCallbacks aidl_callbacks{};
+ if (cbacks.control_result_cb_) {
+ aidl_callbacks.control_result_cb_ =
+ [&session_legacy_callback_table](uint16_t cookie, bool start_resp,
+ const BluetoothAudioStatus& status) {
+ if (session_legacy_callback_table.find(cookie) ==
+ session_legacy_callback_table.end()) {
+ LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+ return;
+ }
+ auto& cback = session_legacy_callback_table[cookie];
+ cback->control_result_cb_(cookie, start_resp, to_hidl_status(status));
+ };
+ }
+ if (cbacks.session_changed_cb_) {
+ aidl_callbacks.session_changed_cb_ =
+ [&session_legacy_callback_table](uint16_t cookie) {
+ if (session_legacy_callback_table.find(cookie) ==
+ session_legacy_callback_table.end()) {
+ LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+ return;
+ }
+ auto& cback = session_legacy_callback_table[cookie];
+ cback->session_changed_cb_(cookie);
+ };
+ };
+ if (cbacks.audio_configuration_changed_cb_) {
+ aidl_callbacks.audio_configuration_changed_cb_ =
+ [&session_legacy_callback_table](uint16_t cookie) {
+ if (session_legacy_callback_table.find(cookie) ==
+ session_legacy_callback_table.end()) {
+ LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+ return;
+ }
+ auto& cback = session_legacy_callback_table[cookie];
+ cback->audio_configuration_changed_cb_(cookie);
+ };
+ };
+ auto cookie = BluetoothAudioSessionControl::RegisterControlResultCback(
+ aidl_session_type, aidl_callbacks);
+ {
+ std::lock_guard<std::mutex> guard(legacy_callback_lock);
+ session_legacy_callback_table[cookie] =
+ std::make_shared<PortStatusCallbacks_2_2>(cbacks);
+ }
+ return cookie;
+}
+
+void HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+ const SessionType_2_1& session_type, uint16_t cookie) {
+ LOG(INFO) << __func__ << ": " << toString(session_type);
+ auto aidl_session_type = from_session_type_2_1(session_type);
+ BluetoothAudioSessionControl::UnregisterControlResultCback(aidl_session_type,
+ cookie);
+ auto& session_callback_table = legacy_callback_table[aidl_session_type];
+ if (session_callback_table.find(cookie) != session_callback_table.end()) {
+ std::lock_guard<std::mutex> guard(legacy_callback_lock);
+ session_callback_table.erase(cookie);
+ }
+}
+
+const AudioConfig_2_2 HidlToAidlMiddleware_2_2::GetAudioConfig(
+ const SessionType_2_1& session_type) {
+ return to_hidl_audio_config_2_2(BluetoothAudioSessionControl::GetAudioConfig(
+ from_session_type_2_1(session_type)));
+}
+
+bool HidlToAidlMiddleware_2_2::StartStream(
+ const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::StartStream(
+ from_session_type_2_1(session_type));
+}
+
+bool HidlToAidlMiddleware_2_2::SuspendStream(
+ const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::SuspendStream(
+ from_session_type_2_1(session_type));
+}
+
+void HidlToAidlMiddleware_2_2::StopStream(const SessionType_2_1& session_type) {
+ return BluetoothAudioSessionControl::StopStream(
+ from_session_type_2_1(session_type));
+}
+
+void HidlToAidlMiddleware_2_2::UpdateTracksMetadata(
+ const SessionType_2_1& session_type,
+ const struct source_metadata* source_metadata) {
+ return BluetoothAudioSessionControl::UpdateSourceMetadata(
+ from_session_type_2_1(session_type), *source_metadata);
+}
+
+void HidlToAidlMiddleware_2_2::UpdateSinkMetadata(
+ const SessionType_2_1& session_type,
+ const struct sink_metadata* sink_metadata) {
+ return BluetoothAudioSessionControl::UpdateSinkMetadata(
+ from_session_type_2_1(session_type), *sink_metadata);
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h
new file mode 100644
index 0000000..b124d8f
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_0.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.0/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::SessionType;
+using PortStatusCallbacks_2_0 =
+ ::android::bluetooth::audio::PortStatusCallbacks;
+using AudioConfig_2_0 =
+ ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_0 {
+ public:
+ static bool IsAidlAvailable();
+
+ static bool IsSessionReady(const SessionType_2_0& session_type);
+
+ static uint16_t RegisterControlResultCback(
+ const SessionType_2_0& session_type,
+ const PortStatusCallbacks_2_0& cbacks);
+
+ static void UnregisterControlResultCback(const SessionType_2_0& session_type,
+ uint16_t cookie);
+
+ static const AudioConfig_2_0 GetAudioConfig(
+ const SessionType_2_0& session_type);
+
+ static bool StartStream(const SessionType_2_0& session_type);
+
+ static void StopStream(const SessionType_2_0& session_type);
+
+ static bool SuspendStream(const SessionType_2_0& session_type);
+
+ static bool GetPresentationPosition(const SessionType_2_0& session_type,
+ uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_readed,
+ timespec* data_position);
+
+ static void UpdateTracksMetadata(
+ const SessionType_2_0& session_type,
+ const struct source_metadata* source_metadata);
+
+ static size_t OutWritePcmData(const SessionType_2_0& session_type,
+ const void* buffer, size_t bytes);
+
+ static size_t InReadPcmData(const SessionType_2_0& session_type, void* buffer,
+ size_t bytes);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h
new file mode 100644
index 0000000..82dce96
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_1.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.1/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::SessionType;
+using AudioConfig_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_1 {
+ public:
+ static const AudioConfig_2_1 GetAudioConfig(
+ const SessionType_2_1& session_type);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
new file mode 100644
index 0000000..f6c3e5c
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/bluetooth/audio/2.2/types.h>
+
+#include "../session/BluetoothAudioSession.h"
+#include "../session/BluetoothAudioSession_2_2.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using SessionType_2_1 =
+ ::android::hardware::bluetooth::audio::V2_1::SessionType;
+using PortStatusCallbacks_2_0 =
+ ::android::bluetooth::audio::PortStatusCallbacks;
+using PortStatusCallbacks_2_2 =
+ ::android::bluetooth::audio::PortStatusCallbacks_2_2;
+using AudioConfig_2_2 =
+ ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration;
+
+class HidlToAidlMiddleware_2_2 {
+ public:
+ static bool IsSessionReady(const SessionType_2_1& session_type);
+
+ static uint16_t RegisterControlResultCback(
+ const SessionType_2_1& session_type,
+ const PortStatusCallbacks_2_2& cbacks);
+
+ static void UnregisterControlResultCback(const SessionType_2_1& session_type,
+ uint16_t cookie);
+
+ static const AudioConfig_2_2 GetAudioConfig(
+ const SessionType_2_1& session_type);
+
+ static bool StartStream(const SessionType_2_1& session_type);
+
+ static bool SuspendStream(const SessionType_2_1& session_type);
+
+ static void StopStream(const SessionType_2_1& session_type);
+
+ static void UpdateTracksMetadata(
+ const SessionType_2_1& session_type,
+ const struct source_metadata* source_metadata);
+
+ static void UpdateSinkMetadata(const SessionType_2_1& session_type,
+ const struct sink_metadata* sink_metadata);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
index 2f3ddaf..283952e 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession.cpp
@@ -21,10 +21,13 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+
namespace android {
namespace bluetooth {
namespace audio {
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
using ::android::hardware::audio::common::V5_0::AudioContentType;
using ::android::hardware::audio::common::V5_0::AudioUsage;
using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
@@ -149,6 +152,8 @@
// The function helps to check if this session is ready or not
// @return: true if the Bluetooth stack has started the specified session
bool BluetoothAudioSession::IsSessionReady() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::IsSessionReady(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
bool dataMQ_valid =
(session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
@@ -200,6 +205,9 @@
// @return: cookie - the assigned number to this bluetooth_audio output
uint16_t BluetoothAudioSession::RegisterStatusCback(
const PortStatusCallbacks& cbacks) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::RegisterControlResultCback(session_type_,
+ cbacks);
std::lock_guard<std::recursive_mutex> guard(mutex_);
uint16_t cookie = ObserversCookieGetInitValue(session_type_);
uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
@@ -227,6 +235,9 @@
// PortStatusCallbacks
// @param: cookie - indicates which bluetooth_audio output is
void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::UnregisterControlResultCback(session_type_,
+ cookie);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (observers_.erase(cookie) != 1) {
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
@@ -238,6 +249,9 @@
// The control function is for the bluetooth_audio module to get the current
// AudioConfiguration
const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return (audio_config_ =
+ HidlToAidlMiddleware_2_0::GetAudioConfig(session_type_));
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (IsSessionReady()) {
return audio_config_;
@@ -251,6 +265,8 @@
// Those control functions are for the bluetooth_audio module to start, suspend,
// stop stream, to check position, and to update metadata.
bool BluetoothAudioSession::StartStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::StartStream(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -267,6 +283,8 @@
}
bool BluetoothAudioSession::SuspendStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::SuspendStream(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -283,6 +301,8 @@
}
void BluetoothAudioSession::StopStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::StopStream(session_type_);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
return;
@@ -297,6 +317,10 @@
bool BluetoothAudioSession::GetPresentationPosition(
uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed,
timespec* data_position) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::GetPresentationPosition(
+ session_type_, remote_delay_report_ns, total_bytes_readed,
+ data_position);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -330,6 +354,9 @@
void BluetoothAudioSession::UpdateTracksMetadata(
const struct source_metadata* source_metadata) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::UpdateTracksMetadata(session_type_,
+ source_metadata);
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -374,6 +401,9 @@
// The control function writes stream to FMQ
size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
size_t bytes) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::OutWritePcmData(session_type_, buffer,
+ bytes);
if (buffer == nullptr || !bytes) return 0;
size_t totalWritten = 0;
int ms_timeout = kFmqSendTimeoutMs;
@@ -407,6 +437,9 @@
// The control function reads stream from FMQ
size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_0::InReadPcmData(session_type_, buffer,
+ bytes);
if (buffer == nullptr || !bytes) return 0;
size_t totalRead = 0;
int ms_timeout = kFmqReceiveTimeoutMs;
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
index 368939e..c270ef0 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
@@ -152,7 +152,7 @@
std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
if (session_ptr != nullptr) {
- session_ptr->GetAudioSession()->UpdateTracksMetadata(source_metadata);
+ session_ptr->UpdateTracksMetadata(source_metadata);
}
}
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
index bf1f9b5..276a291 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
@@ -21,9 +21,14 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+#include "../aidl_session/HidlToAidlMiddleware_2_1.h"
+
namespace android {
namespace bluetooth {
namespace audio {
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_1;
using SessionType_2_1 =
::android::hardware::bluetooth::audio::V2_1::SessionType;
using SessionType_2_0 =
@@ -72,6 +77,7 @@
} else {
session_type_2_1_ = (session_type);
}
+ raw_session_type_ = session_type;
}
std::shared_ptr<BluetoothAudioSession>
@@ -83,6 +89,8 @@
// AudioConfiguration
const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
BluetoothAudioSession_2_1::GetAudioConfig() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_1::GetAudioConfig(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (audio_session->IsSessionReady()) {
// If session is unknown it means it should be 2.0 type
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
index 5a35153..e634064 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
@@ -31,6 +31,7 @@
std::shared_ptr<BluetoothAudioSession> audio_session;
::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
+ ::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
// audio data configuration for both software and offloading
::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
index 60ac4ec..ceb0662 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
@@ -22,13 +22,22 @@
#include <android-base/stringprintf.h>
#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioPort.h>
+#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
+#include "../aidl_session/HidlToAidlMiddleware_2_2.h"
+
namespace android {
namespace bluetooth {
namespace audio {
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
+using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_2;
+using ::android::hardware::audio::common::V5_0::AudioContentType;
using ::android::hardware::audio::common::V5_0::AudioSource;
+using ::android::hardware::audio::common::V5_0::AudioUsage;
+using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
using ::android::hardware::audio::common::V5_0::RecordTrackMetadata;
using ::android::hardware::audio::common::V5_0::SinkMetadata;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
using ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
@@ -93,6 +102,7 @@
} else {
session_type_2_1_ = (session_type);
}
+ raw_session_type_ = session_type;
invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
invalidOffloadAudioConfiguration.codecConfig(
audio_session->kInvalidCodecConfiguration);
@@ -100,6 +110,8 @@
}
bool BluetoothAudioSession_2_2::IsSessionReady() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::IsSessionReady(raw_session_type_);
if (session_type_2_1_ !=
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
session_type_2_1_ !=
@@ -120,8 +132,58 @@
return audio_session_2_1;
}
+void BluetoothAudioSession_2_2::UpdateTracksMetadata(
+ const struct source_metadata* source_metadata) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::UpdateTracksMetadata(raw_session_type_,
+ source_metadata);
+ std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+ << " has NO session";
+ return;
+ }
+
+ ssize_t track_count = source_metadata->track_count;
+ LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+ << ", " << track_count << " track(s)";
+
+ if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
+ audio_session->UpdateTracksMetadata(source_metadata);
+ return;
+ }
+
+ struct playback_track_metadata* track = source_metadata->tracks;
+ SourceMetadata sourceMetadata;
+ PlaybackTrackMetadata* halMetadata;
+
+ sourceMetadata.tracks.resize(track_count);
+ halMetadata = sourceMetadata.tracks.data();
+ while (track_count && track) {
+ halMetadata->usage = static_cast<AudioUsage>(track->usage);
+ halMetadata->contentType =
+ static_cast<AudioContentType>(track->content_type);
+ halMetadata->gain = track->gain;
+ LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_2_1_)
+ << ", usage=" << toString(halMetadata->usage)
+ << ", content=" << toString(halMetadata->contentType)
+ << ", gain=" << halMetadata->gain;
+ --track_count;
+ ++track;
+ ++halMetadata;
+ }
+ auto hal_retval = audio_session->stack_iface_->updateMetadata(sourceMetadata);
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_2_1_) << " failed";
+ }
+}
+
void BluetoothAudioSession_2_2::UpdateSinkMetadata(
const struct sink_metadata* sink_metadata) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::UpdateSinkMetadata(raw_session_type_,
+ sink_metadata);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
@@ -172,6 +234,8 @@
// AudioConfiguration
const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
BluetoothAudioSession_2_2::GetAudioConfig() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::GetAudioConfig(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (IsSessionReady()) {
auto audio_config_discriminator = audio_config_2_2_.getDiscriminator();
@@ -226,6 +290,8 @@
// Those control functions are for the bluetooth_audio module to start, suspend,
// stop stream, to check position, and to update metadata.
bool BluetoothAudioSession_2_2::StartStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::StartStream(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
@@ -242,6 +308,8 @@
}
bool BluetoothAudioSession_2_2::SuspendStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::SuspendStream(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
@@ -258,6 +326,8 @@
}
void BluetoothAudioSession_2_2::StopStream() {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::StopStream(raw_session_type_);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (!IsSessionReady()) {
return;
@@ -395,6 +465,9 @@
// @return: cookie - the assigned number to this bluetooth_audio output
uint16_t BluetoothAudioSession_2_2::RegisterStatusCback(
const PortStatusCallbacks_2_2& cbacks) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
+ raw_session_type_, cbacks);
if (session_type_2_1_ !=
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
session_type_2_1_ !=
@@ -432,6 +505,9 @@
// PortStatusCallbacks_2_2
// @param: cookie - indicates which bluetooth_audio output is
void BluetoothAudioSession_2_2::UnregisterStatusCback(uint16_t cookie) {
+ if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
+ return HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
+ raw_session_type_, cookie);
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
if (session_type_2_1_ !=
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
index 3673fd8..e04ad80 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
@@ -68,6 +68,7 @@
std::shared_ptr<BluetoothAudioSession_2_1> audio_session_2_1;
::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
+ ::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
// audio data configuration for both software and offloading
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
@@ -151,6 +152,7 @@
const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
GetAudioConfig();
+ void UpdateTracksMetadata(const struct source_metadata* source_metadata);
void UpdateSinkMetadata(const struct sink_metadata* sink_metadata);
static constexpr ::android::hardware::bluetooth::audio::V2_2::
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index 7fcf523..fbe8686 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -30,6 +30,7 @@
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
@@ -123,6 +124,21 @@
return layout;
}
+bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
+ MetadataType metadataType) {
+ auto buffer = const_cast<native_handle_t*>(buf);
+ mapper->get(buffer, metadataType, [] (const auto& tmpError,
+ const auto& tmpMetadata) {
+ if (tmpError == MapperErrorV4::NONE) {
+ return tmpMetadata.size() > 0;
+ } else {
+ ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
+ return false;
+ }});
+
+ return false;
+}
+
std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
auto buffer = const_cast<native_handle_t*>(buf);
std::vector<PlaneLayout> planeLayouts;
@@ -449,6 +465,55 @@
return -1;
}
+bool HandleImporter::isSmpte2086Present(const buffer_handle_t& buf) {
+ Mutex::Autolock lock(mLock);
+
+ if (!mInitialized) {
+ initializeLocked();
+ }
+
+ if (mMapperV4 != nullptr) {
+ return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2086);
+ } else {
+ ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+ }
+
+ return false;
+}
+
+bool HandleImporter::isSmpte2094_10Present(const buffer_handle_t& buf) {
+ Mutex::Autolock lock(mLock);
+
+ if (!mInitialized) {
+ initializeLocked();
+ }
+
+ if (mMapperV4 != nullptr) {
+ return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_10);
+ } else {
+ ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+ }
+
+ return false;
+}
+
+bool HandleImporter::isSmpte2094_40Present(const buffer_handle_t& buf) {
+ Mutex::Autolock lock(mLock);
+
+ if (!mInitialized) {
+ initializeLocked();
+ }
+
+ if (mMapperV4 != nullptr) {
+ return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_40);
+ } else {
+ ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+ }
+
+ return false;
+}
+
+
} // namespace helper
} // namespace V1_0
} // namespace common
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index e404439..83fa755 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -61,6 +61,11 @@
int unlock(buffer_handle_t& buf); // returns release fence
+ // Query Gralloc4 metadata
+ bool isSmpte2086Present(const buffer_handle_t& buf);
+ bool isSmpte2094_10Present(const buffer_handle_t& buf);
+ bool isSmpte2094_40Present(const buffer_handle_t& buf);
+
private:
void initializeLocked();
void cleanup();
diff --git a/camera/device/3.8/Android.bp b/camera/device/3.8/Android.bp
index 2a1f215..c3c2941 100644
--- a/camera/device/3.8/Android.bp
+++ b/camera/device/3.8/Android.bp
@@ -9,7 +9,6 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-
hidl_interface {
name: "android.hardware.camera.device@3.8",
root: "android.hardware",
@@ -17,6 +16,7 @@
"types.hal",
"ICameraDevice.hal",
"ICameraDeviceCallback.hal",
+ "ICameraDeviceSession.hal",
],
interfaces: [
"android.hardware.camera.common@1.0",
@@ -31,6 +31,7 @@
"android.hardware.camera.metadata@3.4",
"android.hardware.camera.metadata@3.5",
"android.hardware.camera.metadata@3.6",
+ "android.hardware.camera.metadata@3.8",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
diff --git a/camera/device/3.8/ICameraDevice.hal b/camera/device/3.8/ICameraDevice.hal
index 1101819..8832c68 100644
--- a/camera/device/3.8/ICameraDevice.hal
+++ b/camera/device/3.8/ICameraDevice.hal
@@ -26,8 +26,8 @@
* API at LIMITED or better hardware level.
*
* ICameraDevice.open() must return @3.2::ICameraDeviceSession,
- * @3.5::ICameraDeviceSession, @3.6::ICameraDeviceSession, or
- * @3.7::ICameraDeviceSession.
+ * @3.5::ICameraDeviceSession, @3.6::ICameraDeviceSession,
+ * @3.7::ICameraDeviceSession, or @3.8::ICameraDeviceSession.
*/
interface ICameraDevice extends @3.7::ICameraDevice {
/**
@@ -107,4 +107,15 @@
*
*/
getTorchStrengthLevel() generates (Status status, int32_t torchStrength);
+
+ /**
+ * isStreamCombinationSupported_3_8:
+ *
+ * Identical to @3.7::ICameraDevice.isStreamCombinationSupported, except
+ * that it takes a @3.8::StreamConfiguration parameter, which could contain
+ * additional information about a specific 10-bit dynamic range profile.
+ *
+ */
+ isStreamCombinationSupported_3_8(StreamConfiguration streams)
+ generates (Status status, bool queryStatus);
};
diff --git a/camera/device/3.8/ICameraDeviceSession.hal b/camera/device/3.8/ICameraDeviceSession.hal
new file mode 100644
index 0000000..88e4338
--- /dev/null
+++ b/camera/device/3.8/ICameraDeviceSession.hal
@@ -0,0 +1,95 @@
+/*
+ * 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.camera.device@3.8;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.5::StreamConfiguration;
+import @3.7::ICameraDeviceSession;
+import @3.6::HalStreamConfiguration;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.7::ICameraDeviceSession {
+ /**
+ * configureStreams_3_8:
+ *
+ * Identical to @3.7::ICameraDeviceSession.configureStreams_3_7, except that:
+ *
+ * - The requestedConfiguration allows the camera framework to configure
+ * 10-bit dynamic range profile.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On successful stream configuration.
+ * INTERNAL_ERROR:
+ * If there has been a fatal error and the device is no longer
+ * operational. Only close() can be called successfully by the
+ * framework after this error is returned.
+ * ILLEGAL_ARGUMENT:
+ * If the requested stream configuration is invalid. Some examples
+ * of invalid stream configurations include:
+ * - Including more than 1 INPUT stream
+ * - Not including any OUTPUT streams
+ * - Including streams with unsupported formats, or an unsupported
+ * size for that format.
+ * - Including too many output streams of a certain format.
+ * - Unsupported rotation configuration
+ * - Stream sizes/formats don't satisfy the
+ * StreamConfigurationMode requirements
+ * for non-NORMAL mode, or the requested operation_mode is not
+ * supported by the HAL.
+ * - Unsupported usage flag
+ * - Unsupported stream groupIds, or unsupported multi-resolution
+ * input stream.
+ * - Invalid combination between a 10-bit dynamic range profile
+ * and none impl. defined 8-bit format for a particular stream.
+ * The camera service cannot filter out all possible illegal stream
+ * configurations, since some devices may support more simultaneous
+ * streams or larger stream resolutions than the minimum required
+ * for a given camera device hardware level. The HAL must return an
+ * ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+ * ready to accept a future valid stream configuration in a later
+ * configureStreams call.
+ * @return halConfiguration The stream parameters desired by the HAL for
+ * each stream, including maximum buffers, the usage flags, and the
+ * override format and dataspace.
+ */
+ configureStreams_3_8(StreamConfiguration requestedConfiguration)
+ generates (Status status, @3.6::HalStreamConfiguration halConfiguration);
+
+ /**
+ * repeatingRequestEnd:
+ *
+ * Notification about the last frame number in a repeating request along with the
+ * ids of all streams included in the repeating request.
+ *
+ * This can be called at any point after 'processCaptureRequest' in response
+ * to camera clients disabling an active repeating request.
+ *
+ * Performance requirements:
+ * The call must not be blocked for extensive periods and should be extremely lightweight. There
+ * must be no frame rate degradation or frame jitter introduced.
+ *
+ * This method must always succeed, even if the device has encountered a
+ * serious error.
+ */
+ repeatingRequestEnd(uint32_t frameNumber, vec<int32_t> streamIds);
+};
diff --git a/camera/device/3.8/types.hal b/camera/device/3.8/types.hal
index 843d050..9d1ac22 100644
--- a/camera/device/3.8/types.hal
+++ b/camera/device/3.8/types.hal
@@ -19,6 +19,11 @@
import @3.2::ErrorMsg;
import @3.2::MsgType;
import @3.2::ShutterMsg;
+import @3.2::CameraMetadata;
+import @3.2::StreamConfigurationMode;
+import @3.7::Stream;
+
+import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
/**
* ShutterMsg:
@@ -67,3 +72,75 @@
ShutterMsg shutter;
} msg;
};
+
+/**
+ * Stream:
+ *
+ * A descriptor for a single camera input or output stream. A stream is defined
+ * by the framework by its buffer resolution and format, and additionally by the
+ * HAL with the gralloc usage flags and the maximum in-flight buffer count.
+ *
+ * This version extends the @3.7 Stream with the dynamic range profile field.
+ */
+struct Stream {
+ /**
+ * The definition of Stream from the prior version.
+ */
+ @3.7::Stream v3_7;
+
+ /**
+ * The dynamic range profile for this stream.
+ *
+ * This field is valid and must only be considered for streams with format
+ * android.hardware.graphics.common.PixelFormat.YCBCR_P010 or
+ * android.hardware.graphics.common.PixelFormat.IMPLEMENTATION_DEFINED on devices supporting the
+ * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_10_BIT capability.
+ *
+ */
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap dynamicRangeProfile;
+};
+
+/**
+ * StreamConfiguration:
+ *
+ * Identical to @3.7::StreamConfiguration, except that the streams
+ * vector contains @3.8::Stream.
+ */
+struct StreamConfiguration {
+ /**
+ * An array of camera stream pointers, defining the input/output
+ * configuration for the camera HAL device.
+ */
+ vec<Stream> streams;
+
+ /**
+ * The definition of operation mode from prior version.
+ *
+ */
+ @3.2::StreamConfigurationMode operationMode;
+
+ /**
+ * The definition of session parameters from prior version.
+ */
+ @3.2::CameraMetadata sessionParams;
+
+ /**
+ * The definition of stream configuration counter from prior version.
+ */
+ uint32_t streamConfigCounter;
+
+ /**
+ * If an input stream is configured, whether the input stream is expected to
+ * receive variable resolution images.
+ *
+ * This flag can only be set to true if the camera device supports
+ * multi-resolution input streams by advertising input stream configurations in
+ * physicalCameraMultiResolutionStreamConfigurations in its physical cameras'
+ * characteristics.
+ *
+ * When this flag is set to true, the input stream's width and height can be
+ * any one of the supported multi-resolution input stream sizes.
+ */
+ bool multiResolutionInputImage;
+};
+
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
index 11360da..4c70eb9 100644
--- a/camera/metadata/3.8/types.hal
+++ b/camera/metadata/3.8/types.hal
@@ -53,6 +53,21 @@
ANDROID_FLASH_INFO_END_3_8,
+ /** android.request.availableDynamicRangeProfilesMap [static, enum[], ndk_public]
+ *
+ * <p>A map of all available 10-bit dynamic range profiles along with their
+ * capture request constraints.</p>
+ */
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_REQUEST_END_3_4,
+
+ /** android.request.recommendedTenBitDynamicRangeProfile [static, int32, java_public]
+ *
+ * <p>Recommended 10-bit dynamic range profile.</p>
+ */
+ ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE,
+
+ ANDROID_REQUEST_END_3_8,
+
};
/*
@@ -66,3 +81,51 @@
@3.2::CameraMetadataEnumAndroidControlVideoStabilizationMode {
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION,
};
+
+/** android.request.availableCapabilities enumeration values added since v3.6
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+ @3.6::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT,
+};
+
+/** android.request.availableDynamicRangeProfilesMap enumeration values
+ * @see ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+ */
+enum CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap : uint32_t {
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD
+ = 0x1,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 0x2,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 = 0x4,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS
+ = 0x8,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF
+ = 0x10,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO
+ = 0x20,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM
+ = 0x40,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO
+ = 0x80,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF
+ = 0x100,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO
+ = 0x200,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM
+ = 0x400,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO
+ = 0x800,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000,
+};
+
+/** android.scaler.availableRecommendedStreamConfigurations enumeration values added since v3.4
+ * @see ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
+ */
+enum CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations :
+ @3.4::CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations {
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_10BIT_OUTPUT
+ = 0x8,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8
+ = 0x9,
+};
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2c141ee..0e62265 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -51,11 +51,15 @@
"android.hardware.camera.device@3.7",
"android.hardware.camera.device@3.8",
"android.hardware.camera.metadata@3.4",
+ "android.hardware.camera.metadata@3.8",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
"android.hardware.camera.provider@2.7",
"android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"libgrallocusage",
"libhidlmemory",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index d39850d..8c44010 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -30,6 +30,7 @@
#include <CameraMetadata.h>
#include <CameraParameters.h>
+#include <HandleImporter.h>
#include <android/hardware/camera/device/1.0/ICameraDevice.h>
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
@@ -45,7 +46,9 @@
#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
#include <android/hardware/camera/metadata/3.4/types.h>
+#include <android/hardware/camera/metadata/3.8/types.h>
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
#include <android/hardware/camera/provider/2.6/ICameraProvider.h>
@@ -97,6 +100,7 @@
using ::android::hardware::camera::common::V1_0::TorchMode;
using ::android::hardware::camera::common::V1_0::TorchModeStatus;
using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
using ::android::hardware::camera::common::V1_0::helper::Size;
using ::android::hardware::camera::device::V1_0::CameraFacing;
using ::android::hardware::camera::device::V1_0::CameraFrameMetadata;
@@ -129,6 +133,8 @@
CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag;
using ::android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
+using ::android::hardware::camera::metadata::V3_8::
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
using ::android::hardware::camera::provider::V2_4::ICameraProvider;
using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
@@ -136,7 +142,6 @@
using ::android::hardware::graphics::common::V1_0::Dataspace;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMapper;
using ::android::hidl::memory::V1_0::IMemory;
using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
using ::android::hidl::manager::V1_0::IServiceManager;
@@ -781,13 +786,15 @@
sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
- sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/);
+ sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
+ sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/);
void castInjectionSession(
const sp<ICameraDeviceSession>& session,
sp<device::V3_7::ICameraInjectionSession>* injectionSession3_7 /*out*/);
void castDevice(const sp<device::V3_2::ICameraDevice>& device, int32_t deviceVersion,
sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
- sp<device::V3_7::ICameraDevice>* device3_7 /*out*/);
+ sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
+ sp<device::V3_8::ICameraDevice>* device3_8 /*out*/);
void createStreamConfiguration(
const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
StreamConfigurationMode configMode,
@@ -817,6 +824,16 @@
uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
bool maxResolution);
+ void configureStreams3_8(const std::string& name, int32_t deviceVersion,
+ sp<ICameraProvider> provider, PixelFormat format,
+ sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
+ V3_2::Stream* previewStream /*out*/,
+ device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
+ bool* supportsPartialResults /*out*/,
+ uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+ sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
+ bool maxResolution,
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof);
void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,
@@ -896,6 +913,9 @@
static bool isDepthOnly(const camera_metadata_t* staticMeta);
static bool isUltraHighResolution(const camera_metadata_t* staticMeta);
+ static void get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
+ std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles);
+ static bool is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta);
static Status getAvailableOutputStreams(const camera_metadata_t* staticMeta,
std::vector<AvailableStream>& outputStreams,
@@ -949,7 +969,6 @@
void getPrivacyTestPatternModes(
const camera_metadata_t* staticMetadata,
std::unordered_set<int32_t>* privacyTestPatternModes/*out*/);
- static bool isColorCamera(const camera_metadata_t *metadata);
static V3_2::DataspaceFlags getDataspace(PixelFormat format);
@@ -1077,6 +1096,10 @@
expectedPhysicalResults(extraPhysicalResult) {}
};
+ static void verify10BitMetadata(HandleImporter& importer,
+ const InFlightRequest& request,
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile);
+
// Map from frame number to the in-flight request state
typedef ::android::KeyedVector<uint32_t, InFlightRequest*> InFlightMap;
@@ -1105,6 +1128,8 @@
// Camera provider type.
std::string mProviderType;
+
+ HandleImporter mHandleImporter;
};
Return<void> CameraHidlTest::Camera1DeviceCb::notifyCallback(
@@ -3342,10 +3367,13 @@
sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
sp<device::V3_6::ICameraDeviceSession> sessionV3_6;
sp<device::V3_7::ICameraDeviceSession> sessionV3_7;
+ sp<device::V3_8::ICameraDeviceSession> sessionV3_8;
castSession(session, deviceVersion, &sessionV3_3,
&sessionV3_4, &sessionV3_5, &sessionV3_6,
- &sessionV3_7);
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7) {
+ &sessionV3_7, &sessionV3_8);
+ if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_8) {
+ ASSERT_TRUE(sessionV3_8.get() != nullptr);
+ } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_7) {
ASSERT_TRUE(sessionV3_7.get() != nullptr);
} else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
ASSERT_TRUE(sessionV3_6.get() != nullptr);
@@ -3513,14 +3541,17 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider,
&session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ &session3_6, &session3_7, &session3_8);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+ &cameraDevice3_8);
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -3616,9 +3647,11 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
::android::hardware::camera::device::V3_7::StreamConfiguration config3_7;
::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
@@ -3655,8 +3688,9 @@
openEmptyDeviceSession(name, mProvider2_6, &cti.session /*out*/,
&cti.staticMeta /*out*/, &cti.cameraDevice /*out*/);
castSession(cti.session, deviceVersion, &cti.session3_3, &cti.session3_4,
- &cti.session3_5, &cti.session3_6, &cti.session3_7);
- castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7);
+ &cti.session3_5, &cti.session3_6, &cti.session3_7, &cti.session3_8);
+ castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7,
+ &cti.cameraDevice3_8);
outputStreams.clear();
ASSERT_EQ(Status::OK, getMandatoryConcurrentStreams(cti.staticMeta, &outputStreams));
@@ -3785,14 +3819,17 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ &session3_6, &session3_7, &session3_8);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+ &cameraDevice3_8);
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -3998,14 +4035,17 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ &session3_6, &session3_7, &session3_8);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+ &cameraDevice3_8);
Status rc = isZSLModeAvailable(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4184,9 +4224,10 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
+ &session3_6, &session3_7, &session3_8);
if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
ASSERT_NE(session3_4, nullptr);
} else {
@@ -4325,14 +4366,17 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ &session3_6, &session3_7, &session3_8);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+ &cameraDevice3_8);
// Check if camera support depth only
if (isDepthOnly(staticMeta)) {
@@ -4459,14 +4503,17 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ &session3_6, &session3_7, &session3_8);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+ &cameraDevice3_8);
Status rc = isConstrainedModeAvailable(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4706,14 +4753,17 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ &session3_6, &session3_7, &session3_8);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
+ &cameraDevice3_8);
// Check if camera support depth only
if (isDepthOnly(staticMeta)) {
@@ -4997,6 +5047,20 @@
ASSERT_EQ(Status::OK, status);
ASSERT_EQ(numRequestProcessed, 1u);
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8) {
+ sp<device::V3_3::ICameraDeviceSession> session3_3;
+ sp<device::V3_4::ICameraDeviceSession> session3_4;
+ sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
+ sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
+ &session3_6, &session3_7, &session3_8);
+ ASSERT_TRUE(session3_8.get() != nullptr);
+ hidl_vec<int32_t> streamIds = { halStreamConfig.streams[0].id };
+ session3_8->repeatingRequestEnd(request.frameNumber, streamIds);
+ }
+
{
std::unique_lock<std::mutex> l(mLock);
while (!inflightReq.errorCodeValid &&
@@ -5640,6 +5704,188 @@
}
}
+// Generate and verify 10-bit dynamic range request
+TEST_P(CameraHidlTest, process10BitDynamicRangeRequest) {
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+ uint64_t bufferId = 1;
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
+ continue;
+ }
+ std::string version, deviceId;
+ ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &deviceId));
+ camera_metadata_t* staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, mProvider, &session, &staticMeta);
+ if (!is10BitDynamicRangeCapable(staticMeta)) {
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+ std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> profileList;
+ get10BitDynamicRangeProfiles(staticMeta, &profileList);
+ ASSERT_FALSE(profileList.empty());
+
+ android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+ ret = session->constructDefaultRequestSettings(
+ RequestTemplate::STILL_CAPTURE,
+ [&defaultSettings](auto status, const auto& req) mutable {
+ ASSERT_EQ(Status::OK, status);
+
+ const camera_metadata_t* metadata =
+ reinterpret_cast<const camera_metadata_t*>(req.data());
+ size_t expectedSize = req.size();
+ int result = validate_camera_metadata_structure(metadata, &expectedSize);
+ ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+ size_t entryCount = get_camera_metadata_entry_count(metadata);
+ ASSERT_GT(entryCount, 0u);
+ defaultSettings = metadata;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
+ settings.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(settingsBuffer)),
+ get_camera_metadata_size(settingsBuffer));
+ overrideRotateAndCrop(&settings);
+
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ V3_6::HalStreamConfiguration halStreamConfig;
+ bool supportsPartialResults = false;
+ bool useHalBufManager = false;
+ uint32_t partialResultCount = 0;
+ V3_2::Stream previewStream;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
+ sp<DeviceCb> cb;
+ for (const auto& profile : profileList) {
+ configureStreams3_8(name, deviceVersion, mProvider, PixelFormat::IMPLEMENTATION_DEFINED,
+ &session3_8, &previewStream, &halStreamConfig,
+ &supportsPartialResults, &partialResultCount, &useHalBufManager,
+ &cb, 0, /*maxResolution*/ false, profile);
+ ASSERT_NE(session3_8, nullptr);
+
+ std::shared_ptr<ResultMetadataQueue> resultQueue;
+ auto resultQueueRet = session3_8->getCaptureResultMetadataQueue(
+ [&resultQueue](const auto& descriptor) {
+ resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
+ if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+ ALOGE("%s: HAL returns empty result metadata fmq,"
+ " not use it",
+ __func__);
+ resultQueue = nullptr;
+ // Don't use the queue onwards.
+ }
+ });
+ ASSERT_TRUE(resultQueueRet.isOk());
+
+ std::vector<hidl_handle> graphicBuffers;
+ graphicBuffers.reserve(halStreamConfig.streams.size());
+ ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
+ outputBuffers.resize(halStreamConfig.streams.size());
+ InFlightRequest inflightReq = {static_cast<ssize_t>(halStreamConfig.streams.size()),
+ false,
+ supportsPartialResults,
+ partialResultCount,
+ std::unordered_set<std::string>(),
+ resultQueue};
+
+ size_t k = 0;
+ for (const auto& halStream : halStreamConfig.streams) {
+ hidl_handle buffer_handle;
+ if (useHalBufManager) {
+ outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
+ 0,
+ buffer_handle,
+ BufferStatus::OK,
+ nullptr,
+ nullptr};
+ } else {
+ allocateGraphicBuffer(
+ previewStream.width, previewStream.height,
+ android_convertGralloc1To0Usage(halStream.v3_4.v3_3.v3_2.producerUsage,
+ halStream.v3_4.v3_3.v3_2.consumerUsage),
+ halStream.v3_4.v3_3.v3_2.overrideFormat, &buffer_handle);
+
+ graphicBuffers.push_back(buffer_handle);
+ outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
+ bufferId,
+ buffer_handle,
+ BufferStatus::OK,
+ nullptr,
+ nullptr};
+ bufferId++;
+ }
+ k++;
+ }
+
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+ V3_4::CaptureRequest request3_4;
+ request3_4.v3_2.frameNumber = frameNumber;
+ request3_4.v3_2.fmqSettingsSize = 0;
+ request3_4.v3_2.settings = settings;
+ request3_4.v3_2.inputBuffer = emptyInputBuffer;
+ request3_4.v3_2.outputBuffers = outputBuffers;
+ V3_7::CaptureRequest request3_7;
+ request3_7.v3_4 = request3_4;
+ request3_7.inputWidth = 0;
+ request3_7.inputHeight = 0;
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mInflightMap.clear();
+ mInflightMap.add(frameNumber, &inflightReq);
+ }
+
+ Status stat = Status::INTERNAL_ERROR;
+ uint32_t numRequestProcessed = 0;
+ hidl_vec<BufferCache> cachesToRemove;
+ Return<void> returnStatus = session3_8->processCaptureRequest_3_7(
+ {request3_7}, cachesToRemove,
+ [&stat, &numRequestProcessed](auto s, uint32_t n) {
+ stat = s;
+ numRequestProcessed = n;
+ });
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, stat);
+ ASSERT_EQ(numRequestProcessed, 1u);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (!inflightReq.errorCodeValid &&
+ ((0 < inflightReq.numBuffersLeft) || (!inflightReq.haveResultMetadata))) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+ }
+
+ ASSERT_FALSE(inflightReq.errorCodeValid);
+ ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+ verify10BitMetadata(mHandleImporter, inflightReq, profile);
+ }
+ if (useHalBufManager) {
+ hidl_vec<int32_t> streamIds(halStreamConfig.streams.size());
+ for (size_t i = 0; i < streamIds.size(); i++) {
+ streamIds[i] = halStreamConfig.streams[i].v3_4.v3_3.v3_2.id;
+ }
+ session3_8->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
+ cb->waitForBuffersReturned();
+ }
+
+ ret = session3_8->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
// Generate and verify a burst containing alternating sensor sensitivity values
TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -6633,142 +6879,6 @@
}
}
-// Test the multi-camera API requirement for Google Requirement Freeze S
-// Note that this requirement can only be partially tested. If a vendor
-// device doesn't expose a physical camera in any shape or form, there is no way
-// the test can catch it.
-TEST_P(CameraHidlTest, grfSMultiCameraTest) {
- const int socGrfApi = property_get_int32("ro.board.first_api_level", /*default*/ -1);
- if (socGrfApi < 31 /*S*/) {
- // Non-GRF devices, or version < 31 Skip
- ALOGI("%s: socGrfApi level is %d. Skipping", __FUNCTION__, socGrfApi);
- return;
- }
-
- // Test that if more than one rear-facing color camera is
- // supported, there must be at least one rear-facing logical camera.
- hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
- // Back facing non-logical color cameras
- std::set<std::string> rearColorCameras;
- // Back facing logical cameras' physical camera Id sets
- std::set<std::set<std::string>> rearPhysicalIds;
- for (const auto& name : cameraDeviceNames) {
- std::string cameraId;
- int deviceVersion = getCameraDeviceVersionAndId(name, mProviderType, &cameraId);
- switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
- case CAMERA_DEVICE_API_VERSION_3_7:
- case CAMERA_DEVICE_API_VERSION_3_6:
- case CAMERA_DEVICE_API_VERSION_3_5:
- case CAMERA_DEVICE_API_VERSION_3_4:
- case CAMERA_DEVICE_API_VERSION_3_3:
- case CAMERA_DEVICE_API_VERSION_3_2: {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
- ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
- Return<void> ret;
- ret = mProvider->getCameraDeviceInterface_V3_x(
- name, [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_x = device;
- });
- ASSERT_TRUE(ret.isOk());
-
- ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
- ASSERT_EQ(Status::OK, status);
- const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
-
- // Skip if this is not a color camera.
- if (!CameraHidlTest::isColorCamera(metadata)) {
- return;
- }
-
- // Check camera facing. Skip if facing is not BACK.
- // If this is not a logical camera, only note down
- // the camera ID, and skip.
- camera_metadata_ro_entry entry;
- int retcode = find_camera_metadata_ro_entry(
- metadata, ANDROID_LENS_FACING, &entry);
- ASSERT_EQ(retcode, 0);
- ASSERT_GT(entry.count, 0);
- uint8_t facing = entry.data.u8[0];
- bool isLogicalCamera = (isLogicalMultiCamera(metadata) == Status::OK);
- if (facing != ANDROID_LENS_FACING_BACK) {
- // Not BACK facing. Skip.
- return;
- }
- if (!isLogicalCamera) {
- rearColorCameras.insert(cameraId);
- return;
- }
-
- // Check logical camera's physical camera IDs for color
- // cameras.
- std::unordered_set<std::string> physicalCameraIds;
- Status s = getPhysicalCameraIds(metadata, &physicalCameraIds);
- ASSERT_EQ(Status::OK, s);
- rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
- for (const auto& physicalId : physicalCameraIds) {
- // Skip if the physicalId is publicly available
- for (auto& deviceName : cameraDeviceNames) {
- std::string publicVersion, publicId;
- ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType,
- &publicVersion, &publicId));
- if (physicalId == publicId) {
- // Skip because public Ids will be iterated in outer loop.
- return;
- }
- }
-
- auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x);
- ASSERT_TRUE(castResult.isOk());
- ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice>
- device3_5 = castResult;
- ASSERT_NE(device3_5, nullptr);
-
- // Check camera characteristics for hidden camera id
- Return<void> ret = device3_5->getPhysicalCameraCharacteristics(
- physicalId, [&](auto status, const auto& chars) {
- ASSERT_EQ(Status::OK, status);
- const camera_metadata_t* physicalMetadata =
- (camera_metadata_t*)chars.data();
-
- if (CameraHidlTest::isColorCamera(physicalMetadata)) {
- rearColorCameras.insert(physicalId);
- }
- });
- ASSERT_TRUE(ret.isOk());
- }
- });
- ASSERT_TRUE(ret.isOk());
- } break;
- case CAMERA_DEVICE_API_VERSION_1_0: {
- // Not applicable
- } break;
- default: {
- ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
- ADD_FAILURE();
- } break;
- }
- }
-
- // If there are more than one rear-facing color camera, a logical
- // multi-camera must be defined consisting of all rear-facing color
- // cameras.
- if (rearColorCameras.size() > 1) {
- bool hasRearLogical = false;
- for (const auto& physicalIds : rearPhysicalIds) {
- if (std::includes(physicalIds.begin(), physicalIds.end(),
- rearColorCameras.begin(), rearColorCameras.end())) {
- hasRearLogical = true;
- break;
- }
- }
- ASSERT_TRUE(hasRearLogical);
- }
-}
-
// Retrieve all valid output stream resolutions from the camera
// static characteristics.
Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
@@ -7276,23 +7386,6 @@
return ret;
}
-bool CameraHidlTest::isColorCamera(const camera_metadata_t *metadata) {
- camera_metadata_ro_entry entry;
- int retcode = find_camera_metadata_ro_entry(
- metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
- if ((0 == retcode) && (entry.count > 0)) {
- bool isBackwardCompatible = (std::find(entry.data.u8, entry.data.u8 + entry.count,
- ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) !=
- entry.data.u8 + entry.count);
- bool isMonochrome = (std::find(entry.data.u8, entry.data.u8 + entry.count,
- ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) !=
- entry.data.u8 + entry.count);
- bool isColor = isBackwardCompatible && !isMonochrome;
- return isColor;
- }
- return false;
-}
-
// Retrieve the reprocess input-output format map from the static
// camera characteristics.
Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta,
@@ -7448,8 +7541,9 @@
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
- session3_7);
+ session3_7, &session3_8);
ASSERT_NE(nullptr, (*session3_7).get());
*useHalBufManager = false;
@@ -7497,7 +7591,8 @@
ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7);
sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
- castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
+ castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
ASSERT_NE(cameraDevice3_7, nullptr);
bool supported = false;
ret = cameraDevice3_7->isStreamCombinationSupported_3_7(
@@ -7530,6 +7625,153 @@
ASSERT_TRUE(ret.isOk());
}
+// Configure streams
+void CameraHidlTest::configureStreams3_8(
+ const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
+ PixelFormat format, sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
+ V3_2::Stream* previewStream /*out*/,
+ device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
+ bool* supportsPartialResults /*out*/, uint32_t* partialResultCount /*out*/,
+ bool* useHalBufManager /*out*/, sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
+ bool maxResolution,
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof) {
+ ASSERT_NE(nullptr, session3_8);
+ ASSERT_NE(nullptr, halStreamConfig);
+ ASSERT_NE(nullptr, previewStream);
+ ASSERT_NE(nullptr, supportsPartialResults);
+ ASSERT_NE(nullptr, partialResultCount);
+ ASSERT_NE(nullptr, useHalBufManager);
+ ASSERT_NE(nullptr, outCb);
+ ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8);
+
+ std::vector<AvailableStream> outputStreams;
+ ::android::sp<ICameraDevice> device3_x;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_x = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ camera_metadata_t* staticMeta;
+ ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ staticMeta =
+ clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+ ASSERT_NE(nullptr, staticMeta);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ camera_metadata_ro_entry entry;
+ auto status =
+ find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+ if ((0 == status) && (entry.count > 0)) {
+ *partialResultCount = entry.data.i32[0];
+ *supportsPartialResults = (*partialResultCount > 1);
+ }
+
+ sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
+ sp<ICameraDeviceSession> session;
+ ret = device3_x->open(cb, [&session](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+ *outCb = cb;
+
+ sp<device::V3_3::ICameraDeviceSession> session3_3;
+ sp<device::V3_4::ICameraDeviceSession> session3_4;
+ sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
+ sp<device::V3_7::ICameraDeviceSession> session3_7;
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7, session3_8);
+ ASSERT_NE(nullptr, (*session3_8).get());
+
+ *useHalBufManager = false;
+ status = find_camera_metadata_ro_entry(
+ staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+ if ((0 == status) && (entry.count == 1)) {
+ *useHalBufManager = (entry.data.u8[0] ==
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+ }
+
+ outputStreams.clear();
+ Size maxSize;
+ auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
+ ASSERT_EQ(Status::OK, rc);
+ free_camera_metadata(staticMeta);
+
+ ::android::hardware::hidl_vec<V3_8::Stream> streams3_8(1);
+ streams3_8[0].v3_7.groupId = -1;
+ streams3_8[0].v3_7.sensorPixelModesUsed = {
+ CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
+ streams3_8[0].v3_7.v3_4.bufferSize = 0;
+ streams3_8[0].v3_7.v3_4.v3_2.id = 0;
+ streams3_8[0].v3_7.v3_4.v3_2.streamType = StreamType::OUTPUT;
+ streams3_8[0].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(maxSize.width);
+ streams3_8[0].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(maxSize.height);
+ streams3_8[0].v3_7.v3_4.v3_2.format = static_cast<PixelFormat>(format);
+ streams3_8[0].v3_7.v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
+ streams3_8[0].v3_7.v3_4.v3_2.dataSpace = 0;
+ streams3_8[0].v3_7.v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
+ streams3_8[0].dynamicRangeProfile = prof;
+
+ ::android::hardware::camera::device::V3_8::StreamConfiguration config3_8;
+ config3_8.streams = streams3_8;
+ config3_8.operationMode = StreamConfigurationMode::NORMAL_MODE;
+ config3_8.streamConfigCounter = streamConfigCounter;
+ config3_8.multiResolutionInputImage = false;
+ RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+ ret = (*session3_8)
+ ->constructDefaultRequestSettings(reqTemplate,
+ [&config3_8](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ config3_8.sessionParams = req;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
+ sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
+ castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
+ ASSERT_NE(cameraDevice3_8, nullptr);
+ bool supported = false;
+ ret = cameraDevice3_8->isStreamCombinationSupported_3_8(
+ config3_8, [&supported](Status s, bool combStatus) {
+ ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
+ if (Status::OK == s) {
+ supported = combStatus;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(supported, true);
+
+ if (*session3_8 != nullptr) {
+ ret = (*session3_8)
+ ->configureStreams_3_8(
+ config3_8,
+ [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ *halStreamConfig = halConfig;
+ if (*useHalBufManager) {
+ hidl_vec<V3_4::Stream> streams(1);
+ hidl_vec<V3_2::HalStream> halStreams(1);
+ streams[0] = streams3_8[0].v3_7.v3_4;
+ halStreams[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
+ cb->setCurrentStreamConfig(streams, halStreams);
+ }
+ });
+ }
+ *previewStream = streams3_8[0].v3_7.v3_4.v3_2;
+ ASSERT_TRUE(ret.isOk());
+}
+
// Configure multiple preview streams using different physical ids.
void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,
@@ -7604,8 +7846,9 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
castSession(session, deviceVersion, &session3_3, session3_4, session3_5,
- &session3_6, &session3_7);
+ &session3_6, &session3_7, &session3_8);
ASSERT_NE(nullptr, (*session3_4).get());
*useHalBufManager = false;
@@ -7650,7 +7893,8 @@
if (allowUnsupport) {
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
+ sp<device::V3_8::ICameraDevice> cameraDevice3_8;
+ castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
bool supported = false;
ret = cameraDevice3_5->isStreamCombinationSupported(config3_4,
@@ -7843,6 +8087,95 @@
return false;
}
+void CameraHidlTest::get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
+ std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles) {
+ ASSERT_NE(nullptr, staticMeta);
+ ASSERT_NE(nullptr, profiles);
+ camera_metadata_ro_entry entry;
+ std::unordered_set<int32_t> entries;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, &entry);
+ ASSERT_EQ(rc, 0);
+ ASSERT_TRUE(entry.count > 0);
+ ASSERT_EQ(entry.count % 2, 0);
+
+ for (uint32_t i = 0; i < entry.count; i += 2) {
+ ASSERT_NE(entry.data.i32[i],
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ ASSERT_EQ(entries.find(entry.data.i32[i]), entries.end());
+ entries.insert(static_cast<int32_t>(entry.data.i32[i]));
+ profiles->emplace_back(
+ static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
+ (entry.data.i32[i]));
+ }
+
+ if (!entries.empty()) {
+ ASSERT_NE(entries.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10),
+ entries.end());
+ }
+}
+
+bool CameraHidlTest::is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta) {
+ camera_metadata_ro_entry scalarEntry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ &scalarEntry);
+ if (rc == 0) {
+ for (uint32_t i = 0; i < scalarEntry.count; i++) {
+ if (scalarEntry.data.u8[i] ==
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void CameraHidlTest::verify10BitMetadata(HandleImporter& importer,
+ const InFlightRequest& request,
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile) {
+ for (const auto& b : request.resultOutputBuffers) {
+ bool smpte2086Present = importer.isSmpte2086Present(b.buffer.buffer.getNativeHandle());
+ bool smpte2094_10Present = importer.isSmpte2094_10Present(
+ b.buffer.buffer.getNativeHandle());
+ bool smpte2094_40Present = importer.isSmpte2094_40Present(
+ b.buffer.buffer.getNativeHandle());
+
+ switch (static_cast<uint32_t>(profile)) {
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
+ ASSERT_FALSE(smpte2086Present);
+ ASSERT_FALSE(smpte2094_10Present);
+ ASSERT_FALSE(smpte2094_40Present);
+ break;
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+ ASSERT_TRUE(smpte2086Present);
+ ASSERT_FALSE(smpte2094_10Present);
+ ASSERT_FALSE(smpte2094_40Present);
+ break;
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+ ASSERT_FALSE(smpte2086Present);
+ ASSERT_FALSE(smpte2094_10Present);
+ ASSERT_TRUE(smpte2094_40Present);
+ break;
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO:
+ ASSERT_FALSE(smpte2086Present);
+ ASSERT_TRUE(smpte2094_10Present);
+ ASSERT_FALSE(smpte2094_40Present);
+ break;
+ default:
+ ALOGE("%s: Unexpected 10-bit dynamic range profile: %d",
+ __FUNCTION__, profile);
+ ADD_FAILURE();
+ }
+ }
+}
+
bool CameraHidlTest::isDepthOnly(const camera_metadata_t* staticMeta) {
camera_metadata_ro_entry scalarEntry;
camera_metadata_ro_entry depthEntry;
@@ -8006,8 +8339,9 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
+ &session3_6, &session3_7, &session3_8);
*useHalBufManager = false;
status = find_camera_metadata_ro_entry(staticMeta,
@@ -8138,12 +8472,19 @@
void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice>& device,
int32_t deviceVersion,
sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
- sp<device::V3_7::ICameraDevice>* device3_7 /*out*/) {
+ sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
+ sp<device::V3_8::ICameraDevice>* device3_8 /*out*/) {
ASSERT_NE(nullptr, device3_5);
ASSERT_NE(nullptr, device3_7);
+ ASSERT_NE(nullptr, device3_8);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
+ case CAMERA_DEVICE_API_VERSION_3_8: {
+ auto castResult = device::V3_8::ICameraDevice::castFrom(device);
+ ASSERT_TRUE(castResult.isOk());
+ *device3_8 = castResult;
+ }
+ [[fallthrough]];
case CAMERA_DEVICE_API_VERSION_3_7: {
auto castResult = device::V3_7::ICameraDevice::castFrom(device);
ASSERT_TRUE(castResult.isOk());
@@ -8192,15 +8533,22 @@
sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
- sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/) {
+ sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
+ sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/) {
ASSERT_NE(nullptr, session3_3);
ASSERT_NE(nullptr, session3_4);
ASSERT_NE(nullptr, session3_5);
ASSERT_NE(nullptr, session3_6);
ASSERT_NE(nullptr, session3_7);
+ ASSERT_NE(nullptr, session3_8);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
+ case CAMERA_DEVICE_API_VERSION_3_8: {
+ auto castResult = device::V3_8::ICameraDeviceSession::castFrom(session);
+ ASSERT_TRUE(castResult.isOk());
+ *session3_8 = castResult;
+ }
+ [[fallthrough]];
case CAMERA_DEVICE_API_VERSION_3_7: {
auto castResult = device::V3_7::ICameraDeviceSession::castFrom(session);
ASSERT_TRUE(castResult.isOk());
@@ -9077,8 +9425,9 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
+ sp<device::V3_8::ICameraDeviceSession> session3_8;
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7);
+ &session3_6, &session3_7, &session3_8);
ASSERT_NE(nullptr, session3_5.get());
hidl_vec<int32_t> streamIds(1);
@@ -9320,7 +9669,7 @@
size_t CONFIG_ENTRY_TYPE_OFFSET = 3;
size_t CONFIG_ENTRY_BITFIELD_OFFSET = 4;
uint32_t maxPublicUsecase =
- ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END;
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8;
uint32_t vendorUsecaseStart =
ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START;
uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1;
diff --git a/camera/provider/2.7/default/Android.bp b/camera/provider/2.7/default/Android.bp
new file mode 100644
index 0000000..bd5da2d
--- /dev/null
+++ b/camera/provider/2.7/default/Android.bp
@@ -0,0 +1,111 @@
+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_library_shared {
+ name: "android.hardware.camera.provider@2.7-external",
+ proprietary: true,
+ srcs: ["ExternalCameraProviderImpl_2_7.cpp"],
+ shared_libs: [
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
+ "android.hardware.camera.device@3.6",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.5",
+ "android.hardware.camera.provider@2.6",
+ "android.hardware.camera.provider@2.7",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "camera.device@3.3-impl",
+ "camera.device@3.4-external-impl",
+ "camera.device@3.4-impl",
+ "camera.device@3.5-external-impl",
+ "camera.device@3.5-impl",
+ "camera.device@3.6-external-impl",
+ "libcamera_metadata",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libtinyxml2",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+ header_libs: [
+ "camera.device@3.4-external-impl_headers",
+ "camera.device@3.5-external-impl_headers",
+ "camera.device@3.6-external-impl_headers",
+ ],
+ export_include_dirs: ["."],
+}
+
+cc_defaults {
+ name: "camera_external_service_2_7_defaults",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["external-service.cpp"],
+ compile_multilib: "32",
+ shared_libs: [
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.4-external",
+ "android.hardware.camera.provider@2.5",
+ "android.hardware.camera.provider@2.5-external",
+ "android.hardware.camera.provider@2.6",
+ "android.hardware.camera.provider@2.7",
+ "android.hardware.camera.provider@2.7-external",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "libbinder",
+ "libcamera_metadata",
+ "libhidlbase",
+ "liblog",
+ "libtinyxml2",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+ header_libs: [
+ "camera.device@3.4-external-impl_headers",
+ "camera.device@3.4-impl_headers",
+ "camera.device@3.5-external-impl_headers",
+ "camera.device@3.5-impl_headers",
+ "camera.device@3.6-external-impl_headers",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.camera.provider@2.7-external-service",
+ defaults: ["camera_external_service_2_7_defaults"],
+ init_rc: ["android.hardware.camera.provider@2.7-external-service.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.camera.provider@2.7-external-service-lazy",
+ overrides: ["android.hardware.camera.provider@2.7-external-service"],
+ defaults: ["camera_external_service_2_7_defaults"],
+ init_rc: ["android.hardware.camera.provider@2.7-external-service-lazy.rc"],
+ cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/camera/provider/2.7/default/CameraProvider_2_7.h b/camera/provider/2.7/default/CameraProvider_2_7.h
new file mode 100644
index 0000000..c34905f
--- /dev/null
+++ b/camera/provider/2.7/default/CameraProvider_2_7.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_CAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_CAMERAPROVIDER_H
+
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
+#include <android/hardware/camera/provider/2.7/ICameraProvider.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_7 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::common::V1_0::VendorTag;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::provider::V2_5::DeviceState;
+using ::android::hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
+using ::android::hardware::camera::provider::V2_7::ICameraProvider;
+using ::android::hidl::base::V1_0::IBase;
+
+// Default recommended RPC thread count for camera provider implementations
+const int HWBINDER_THREAD_COUNT = 6;
+
+template <typename IMPL>
+struct CameraProvider : public ICameraProvider {
+ CameraProvider() : impl() {}
+ ~CameraProvider() {}
+
+ // Caller must use this method to check if CameraProvider ctor failed
+ bool isInitFailed() { return impl.isInitFailed(); }
+
+ // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+ Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override {
+ return impl.setCallback(callback);
+ }
+
+ Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override {
+ return impl.getVendorTags(_hidl_cb);
+ }
+
+ Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override {
+ return impl.getCameraIdList(_hidl_cb);
+ }
+
+ Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override {
+ return impl.isSetTorchModeSupported(_hidl_cb);
+ }
+
+ Return<void> getCameraDeviceInterface_V1_x(const hidl_string& cameraDeviceName,
+ getCameraDeviceInterface_V1_x_cb _hidl_cb) override {
+ return impl.getCameraDeviceInterface_V1_x(cameraDeviceName, _hidl_cb);
+ }
+
+ Return<void> getCameraDeviceInterface_V3_x(const hidl_string& cameraDeviceName,
+ getCameraDeviceInterface_V3_x_cb _hidl_cb) override {
+ return impl.getCameraDeviceInterface_V3_x(cameraDeviceName, _hidl_cb);
+ }
+
+ // Methods from ::android::hardware::camera::provider::V2_5::ICameraProvider follow.
+ Return<void> notifyDeviceStateChange(hardware::hidl_bitfield<DeviceState> newState) override {
+ return impl.notifyDeviceStateChange(newState);
+ }
+
+ // Methods from ::android::hardware::camera::provider::V2_7::ICameraProvider follow.
+ Return<void> getConcurrentStreamingCameraIds(
+ getConcurrentStreamingCameraIds_cb _hidl_cb) override {
+ return impl.getConcurrentStreamingCameraIds(_hidl_cb);
+ }
+
+ Return<void> isConcurrentStreamCombinationSupported(
+ const hidl_vec<
+ ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination>&
+ configs,
+ isConcurrentStreamCombinationSupported_cb _hidl_cb) override {
+ return impl.isConcurrentStreamCombinationSupported(configs, _hidl_cb);
+ }
+
+ Return<void> isConcurrentStreamCombinationSupported_2_7(
+ const hidl_vec<CameraIdAndStreamCombination>& configs,
+ isConcurrentStreamCombinationSupported_2_7_cb _hidl_cb) override {
+ return impl.isConcurrentStreamCombinationSupported_2_7(configs, _hidl_cb);
+ }
+
+ private:
+ IMPL impl;
+};
+
+} // namespace implementation
+} // namespace V2_7
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
\ No newline at end of file
diff --git a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
new file mode 100644
index 0000000..b63e3bb
--- /dev/null
+++ b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
@@ -0,0 +1,393 @@
+/*
+ * 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 "CamPrvdr@2.7-external"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include <cutils/properties.h>
+#include <errno.h>
+#include <linux/videodev2.h>
+#include <sys/inotify.h>
+#include <regex>
+#include "ExternalCameraDevice_3_4.h"
+#include "ExternalCameraDevice_3_5.h"
+#include "ExternalCameraDevice_3_6.h"
+#include "ExternalCameraProviderImpl_2_7.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_7 {
+namespace implementation {
+
+namespace {
+// "device@<version>/external/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
+const int kMaxDevicePathLen = 256;
+const char* kDevicePath = "/dev/";
+constexpr char kPrefix[] = "video";
+constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
+
+bool matchDeviceName(int cameraIdOffset, const hidl_string& deviceName, std::string* deviceVersion,
+ std::string* cameraDevicePath) {
+ std::string deviceNameStd(deviceName.c_str());
+ std::smatch sm;
+ if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
+ if (deviceVersion != nullptr) {
+ *deviceVersion = sm[1];
+ }
+ if (cameraDevicePath != nullptr) {
+ *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
+ }
+ return true;
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+ExternalCameraProviderImpl_2_7::ExternalCameraProviderImpl_2_7()
+ : mCfg(ExternalCameraConfig::loadFromCfg()) {
+ mHotPlugThread = sp<HotplugThread>::make(this);
+ mHotPlugThread->run("ExtCamHotPlug", PRIORITY_BACKGROUND);
+
+ mPreferredHal3MinorVersion =
+ property_get_int32("ro.vendor.camera.external.hal3TrebleMinorVersion", 4);
+ ALOGV("Preferred HAL 3 minor version is %d", mPreferredHal3MinorVersion);
+ switch (mPreferredHal3MinorVersion) {
+ case 4:
+ case 5:
+ case 6:
+ // OK
+ break;
+ default:
+ ALOGW("Unknown minor camera device HAL version %d in property "
+ "'camera.external.hal3TrebleMinorVersion', defaulting to 4",
+ mPreferredHal3MinorVersion);
+ mPreferredHal3MinorVersion = 4;
+ }
+}
+
+ExternalCameraProviderImpl_2_7::~ExternalCameraProviderImpl_2_7() {
+ mHotPlugThread->requestExit();
+}
+
+Return<Status> ExternalCameraProviderImpl_2_7::setCallback(
+ const sp<ICameraProviderCallback>& callback) {
+ Mutex::Autolock _l(mLock);
+ mCallbacks = callback;
+ if (mCallbacks == nullptr) {
+ return Status::OK;
+ }
+ // Send a callback for all devices to initialize
+ {
+ for (const auto& pair : mCameraStatusMap) {
+ mCallbacks->cameraDeviceStatusChange(pair.first, pair.second);
+ }
+ }
+
+ return Status::OK;
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getVendorTags(
+ ICameraProvider::getVendorTags_cb _hidl_cb) {
+ // No vendor tag support for USB camera
+ hidl_vec<VendorTagSection> zeroSections;
+ _hidl_cb(Status::OK, zeroSections);
+ return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getCameraIdList(
+ ICameraProvider::getCameraIdList_cb _hidl_cb) {
+ // External camera HAL always report 0 camera, and extra cameras
+ // are just reported via cameraDeviceStatusChange callbacks
+ hidl_vec<hidl_string> hidlDeviceNameList;
+ _hidl_cb(Status::OK, hidlDeviceNameList);
+ return Void();
+}
+
+void ExternalCameraProviderImpl_2_7::updateAttachedCameras() {
+ ALOGV("%s start scaning for existing V4L2 devices", __FUNCTION__);
+ // Find existing /dev/video* devices
+ DIR* devdir = opendir(kDevicePath);
+ if (devdir == 0) {
+ ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath);
+ return;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(devdir)) != 0) {
+ // Find external v4l devices that's existing before we start watching and add them
+ if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {
+ // TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
+ // is added.
+ std::string deviceId(de->d_name + kPrefixLen);
+ if (mCfg.mInternalDevices.count(deviceId) == 0) {
+ ALOGV("Non-internal v4l device %s found", de->d_name);
+ char v4l2DevicePath[kMaxDevicePathLen];
+ snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath, de->d_name);
+ deviceAdded(v4l2DevicePath);
+ }
+ }
+ }
+ closedir(devdir);
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::isSetTorchModeSupported(
+ ICameraProvider::isSetTorchModeSupported_cb _hidl_cb) {
+ // setTorchMode API is supported, though right now no external camera device
+ // has a flash unit.
+ _hidl_cb(Status::OK, true);
+ return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getCameraDeviceInterface_V1_x(
+ const hidl_string&, ICameraProvider::getCameraDeviceInterface_V1_x_cb _hidl_cb) {
+ // External Camera HAL does not support HAL1
+ _hidl_cb(Status::OPERATION_NOT_SUPPORTED, nullptr);
+ return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getCameraDeviceInterface_V3_x(
+ const hidl_string& cameraDeviceName,
+ ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) {
+ std::string cameraDevicePath, deviceVersion;
+ bool match = matchDeviceName(mCfg.cameraIdOffset, cameraDeviceName, &deviceVersion,
+ &cameraDevicePath);
+ if (!match) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ if (mCameraStatusMap.count(cameraDeviceName) == 0 ||
+ mCameraStatusMap[cameraDeviceName] != CameraDeviceStatus::PRESENT) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl;
+ switch (mPreferredHal3MinorVersion) {
+ case 4: {
+ ALOGV("Constructing v3.4 external camera device");
+ deviceImpl =
+ new device::V3_4::implementation::ExternalCameraDevice(cameraDevicePath, mCfg);
+ break;
+ }
+ case 5: {
+ ALOGV("Constructing v3.5 external camera device");
+ deviceImpl =
+ new device::V3_5::implementation::ExternalCameraDevice(cameraDevicePath, mCfg);
+ break;
+ }
+ case 6: {
+ ALOGV("Constructing v3.6 external camera device");
+ deviceImpl =
+ new device::V3_6::implementation::ExternalCameraDevice(cameraDevicePath, mCfg);
+ break;
+ }
+ default:
+ ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+ ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ IF_ALOGV() {
+ deviceImpl->getInterface()->interfaceChain(
+ [](::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+ ALOGV("Device interface chain:");
+ for (auto iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
+
+ _hidl_cb(Status::OK, deviceImpl->getInterface());
+
+ return Void();
+}
+
+void ExternalCameraProviderImpl_2_7::addExternalCamera(const char* devName) {
+ ALOGV("ExtCam: adding %s to External Camera HAL!", devName);
+ Mutex::Autolock _l(mLock);
+ std::string deviceName;
+ std::string cameraId =
+ std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+ if (mPreferredHal3MinorVersion == 6) {
+ deviceName = std::string("device@3.6/external/") + cameraId;
+ } else if (mPreferredHal3MinorVersion == 5) {
+ deviceName = std::string("device@3.5/external/") + cameraId;
+ } else {
+ deviceName = std::string("device@3.4/external/") + cameraId;
+ }
+ mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
+ if (mCallbacks != nullptr) {
+ mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
+ }
+}
+
+void ExternalCameraProviderImpl_2_7::deviceAdded(const char* devName) {
+ {
+ base::unique_fd fd(::open(devName, O_RDWR));
+ if (fd.get() < 0) {
+ ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
+ return;
+ }
+
+ struct v4l2_capability capability;
+ int ret = ioctl(fd.get(), VIDIOC_QUERYCAP, &capability);
+ if (ret < 0) {
+ ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
+ return;
+ }
+
+ if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+ ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
+ return;
+ }
+ }
+ // See if we can initialize ExternalCameraDevice correctly
+ sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
+ new device::V3_4::implementation::ExternalCameraDevice(devName, mCfg);
+ if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+ ALOGW("%s: Attempt to init camera device %s failed!", __FUNCTION__, devName);
+ return;
+ }
+ deviceImpl.clear();
+
+ addExternalCamera(devName);
+ return;
+}
+
+void ExternalCameraProviderImpl_2_7::deviceRemoved(const char* devName) {
+ Mutex::Autolock _l(mLock);
+ std::string deviceName;
+ std::string cameraId =
+ std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+ if (mPreferredHal3MinorVersion == 6) {
+ deviceName = std::string("device@3.6/external/") + cameraId;
+ } else if (mPreferredHal3MinorVersion == 5) {
+ deviceName = std::string("device@3.5/external/") + cameraId;
+ } else {
+ deviceName = std::string("device@3.4/external/") + cameraId;
+ }
+ if (mCameraStatusMap.erase(deviceName) != 0) {
+ if (mCallbacks != nullptr) {
+ mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::NOT_PRESENT);
+ }
+ } else {
+ ALOGE("%s: cannot find camera device %s", __FUNCTION__, devName);
+ }
+}
+
+ExternalCameraProviderImpl_2_7::HotplugThread::HotplugThread(ExternalCameraProviderImpl_2_7* parent)
+ : Thread(/*canCallJava*/ false),
+ mParent(parent),
+ mInternalDevices(parent->mCfg.mInternalDevices) {}
+
+ExternalCameraProviderImpl_2_7::HotplugThread::~HotplugThread() {}
+
+bool ExternalCameraProviderImpl_2_7::HotplugThread::threadLoop() {
+ // Update existing cameras
+ mParent->updateAttachedCameras();
+
+ // Watch new video devices
+ mINotifyFD = inotify_init();
+ if (mINotifyFD < 0) {
+ ALOGE("%s: inotify init failed! Exiting threadloop", __FUNCTION__);
+ return true;
+ }
+
+ mWd = inotify_add_watch(mINotifyFD, kDevicePath, IN_CREATE | IN_DELETE);
+ if (mWd < 0) {
+ ALOGE("%s: inotify add watch failed! Exiting threadloop", __FUNCTION__);
+ return true;
+ }
+
+ bool done = false;
+ char eventBuf[512];
+ while (!done) {
+ int offset = 0;
+ int ret = read(mINotifyFD, eventBuf, sizeof(eventBuf));
+ if (ret >= (int)sizeof(struct inotify_event)) {
+ while (offset < ret) {
+ struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
+ if (event->wd == mWd) {
+ ALOGV("%s inotify_event %s", __FUNCTION__, event->name);
+ if (!strncmp(kPrefix, event->name, kPrefixLen)) {
+ std::string deviceId(event->name + kPrefixLen);
+ if (mInternalDevices.count(deviceId) == 0) {
+ char v4l2DevicePath[kMaxDevicePathLen];
+ snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath,
+ event->name);
+ if (event->mask & IN_CREATE) {
+ mParent->deviceAdded(v4l2DevicePath);
+ }
+ if (event->mask & IN_DELETE) {
+ mParent->deviceRemoved(v4l2DevicePath);
+ }
+ }
+ }
+ }
+ offset += sizeof(struct inotify_event) + event->len;
+ }
+ }
+ }
+
+ return true;
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::notifyDeviceStateChange(
+ hidl_bitfield<DeviceState> /*newState*/) {
+ return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::getConcurrentStreamingCameraIds(
+ ICameraProvider::getConcurrentStreamingCameraIds_cb _hidl_cb) {
+ hidl_vec<hidl_vec<hidl_string>> hidl_camera_id_combinations;
+ _hidl_cb(Status::OK, hidl_camera_id_combinations);
+ return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::isConcurrentStreamCombinationSupported(
+ const hidl_vec<::android::hardware::camera::provider::V2_6::
+ CameraIdAndStreamCombination>& /* configs */,
+ ICameraProvider::isConcurrentStreamCombinationSupported_cb _hidl_cb) {
+ _hidl_cb(Status::OK, false);
+ return Void();
+}
+
+Return<void> ExternalCameraProviderImpl_2_7::isConcurrentStreamCombinationSupported_2_7(
+ const hidl_vec<CameraIdAndStreamCombination>& /* configs */,
+ ICameraProvider::isConcurrentStreamCombinationSupported_2_7_cb _hidl_cb) {
+ _hidl_cb(Status::OK, false);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_7
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.h b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.h
new file mode 100644
index 0000000..da9f6b3
--- /dev/null
+++ b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_EXTCAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_EXTCAMERAPROVIDER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include "ExternalCameraUtils.h"
+
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
+#include <android/hardware/camera/provider/2.7/ICameraProvider.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_7 {
+namespace implementation {
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::provider::V2_5::DeviceState;
+using ::android::hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
+using ::android::hardware::camera::provider::V2_7::ICameraProvider;
+using ::android::hidl::base::V1_0::IBase;
+
+/**
+ * The implementation of external webcam CameraProvider 2.7, separated
+ * from the HIDL interface layer to allow for implementation reuse by later
+ * provider versions.
+ *
+ * This camera provider supports standard UVC webcameras via the Linux V4L2
+ * UVC driver.
+ */
+struct ExternalCameraProviderImpl_2_7 {
+ ExternalCameraProviderImpl_2_7();
+ ~ExternalCameraProviderImpl_2_7();
+
+ // Caller must use this method to check if CameraProvider ctor failed
+ bool isInitFailed() { return false; }
+
+ // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+ Return<Status> setCallback(const sp<ICameraProviderCallback>& callback);
+ Return<void> getVendorTags(ICameraProvider::getVendorTags_cb _hidl_cb);
+ Return<void> getCameraIdList(ICameraProvider::getCameraIdList_cb _hidl_cb);
+ Return<void> isSetTorchModeSupported(ICameraProvider::isSetTorchModeSupported_cb _hidl_cb);
+ Return<void> getCameraDeviceInterface_V1_x(const hidl_string&,
+ ICameraProvider::getCameraDeviceInterface_V1_x_cb);
+ Return<void> getCameraDeviceInterface_V3_x(const hidl_string&,
+ ICameraProvider::getCameraDeviceInterface_V3_x_cb);
+
+ // Methods from ::android::hardware::camera::provider::V2_5::ICameraProvider follow.
+ Return<void> notifyDeviceStateChange(hidl_bitfield<DeviceState> newState);
+
+ // Methods from ::android::hardware::camera::provider::V2_7::ICameraProvider follow.
+ Return<void> getConcurrentStreamingCameraIds(
+ ICameraProvider::getConcurrentStreamingCameraIds_cb _hidl_cb);
+
+ Return<void> isConcurrentStreamCombinationSupported(
+ const hidl_vec<
+ ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination>&
+ configs,
+ ICameraProvider::isConcurrentStreamCombinationSupported_cb _hidl_cb);
+
+ Return<void> isConcurrentStreamCombinationSupported_2_7(
+ const hidl_vec<CameraIdAndStreamCombination>& configs,
+ ICameraProvider::isConcurrentStreamCombinationSupported_2_7_cb _hidl_cb);
+
+ private:
+ void addExternalCamera(const char* devName);
+
+ void deviceAdded(const char* devName);
+
+ void deviceRemoved(const char* devName);
+
+ void updateAttachedCameras();
+
+ class HotplugThread : public android::Thread {
+ public:
+ HotplugThread(ExternalCameraProviderImpl_2_7* parent);
+ ~HotplugThread();
+
+ virtual bool threadLoop() override;
+
+ private:
+ ExternalCameraProviderImpl_2_7* mParent = nullptr;
+ const std::unordered_set<std::string> mInternalDevices;
+
+ int mINotifyFD = -1;
+ int mWd = -1;
+ };
+
+ Mutex mLock;
+ sp<ICameraProviderCallback> mCallbacks = nullptr;
+ std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
+ const ExternalCameraConfig mCfg;
+ sp<HotplugThread> mHotPlugThread;
+ int mPreferredHal3MinorVersion;
+};
+
+} // namespace implementation
+} // namespace V2_7
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_7_EXTCAMERAPROVIDER_H
diff --git a/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service-lazy.rc b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service-lazy.rc
new file mode 100644
index 0000000..9292c4f
--- /dev/null
+++ b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service-lazy.rc
@@ -0,0 +1,13 @@
+service vendor.camera-provider-2-7-ext /vendor/bin/hw/android.hardware.camera.provider@2.7-external-service-lazy
+ interface android.hardware.camera.provider@2.4::ICameraProvider external/0
+ interface android.hardware.camera.provider@2.5::ICameraProvider external/0
+ interface android.hardware.camera.provider@2.6::ICameraProvider external/0
+ interface android.hardware.camera.provider@2.7::ICameraProvider external/0
+ class hal
+ oneshot
+ disabled
+ user cameraserver
+ group audio camera input drmrpc usb
+ ioprio rt 4
+ capabilities SYS_NICE
+ task_profiles CameraServiceCapacity MaxPerformance
\ No newline at end of file
diff --git a/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service.rc b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service.rc
new file mode 100644
index 0000000..2c9b782
--- /dev/null
+++ b/camera/provider/2.7/default/android.hardware.camera.provider@2.7-external-service.rc
@@ -0,0 +1,11 @@
+service vendor.camera-provider-2-7-ext /vendor/bin/hw/android.hardware.camera.provider@2.7-external-service
+ interface android.hardware.camera.provider@2.4::ICameraProvider external/0
+ interface android.hardware.camera.provider@2.5::ICameraProvider external/0
+ interface android.hardware.camera.provider@2.6::ICameraProvider external/0
+ interface android.hardware.camera.provider@2.7::ICameraProvider external/0
+ class hal
+ user cameraserver
+ group audio camera input drmrpc usb
+ ioprio rt 4
+ capabilities SYS_NICE
+ task_profiles CameraServiceCapacity MaxPerformance
diff --git a/camera/provider/2.7/default/external-service.cpp b/camera/provider/2.7/default/external-service.cpp
new file mode 100644
index 0000000..90b8239
--- /dev/null
+++ b/camera/provider/2.7/default/external-service.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 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.
+ */
+
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.camera.provider@2.7-external-service-lazy"
+#else
+#define LOG_TAG "android.hardware.camera.provider@2.7-external-service"
+#endif
+
+#include <android/hardware/camera/provider/2.7/ICameraProvider.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "CameraProvider_2_7.h"
+#include "ExternalCameraProviderImpl_2_7.h"
+
+using android::status_t;
+using android::hardware::camera::provider::V2_7::ICameraProvider;
+using android::hidl::base::V1_0::IBase;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+ using namespace android::hardware::camera::provider::V2_7::implementation;
+
+ ALOGI("CameraProvider@2.7 external webcam service is starting.");
+
+ ::android::hardware::configureRpcThreadpool(/*threads*/ HWBINDER_THREAD_COUNT,
+ /*willJoin*/ true);
+
+ ::android::sp<CameraProvider<ExternalCameraProviderImpl_2_7>> provider =
+ new CameraProvider<ExternalCameraProviderImpl_2_7>();
+
+ status_t status;
+ if (kLazyService) {
+ auto serviceRegistrar = ::android::hardware::LazyServiceRegistrar::getInstance();
+ status = serviceRegistrar.registerService(provider, "external/0");
+ } else {
+ status = provider->registerAsService("external/0");
+ }
+
+ LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering provider service: %d",
+ status);
+
+ ::android::hardware::joinRpcThreadpool();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 718901e..12ab1f7 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -25,6 +25,7 @@
apex_available: [
"//apex_available:platform",
"com.android.neuralnetworks",
+ "com.android.media.swcodec",
],
min_sdk_version: "29",
}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index b142d0c..e6dd1bf 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -60,6 +60,14 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.automotive.evs</name>
+ <interface>
+ <name>IEvsEnumerator</name>
+ <instance>default</instance>
+ <regex-instance>[a-z]+/[0-9]+</regex-instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.automotive.evs</name>
<version>1.0-1</version>
@@ -77,14 +85,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.automotive.sv</name>
- <version>1.0</version>
- <interface>
- <name>ISurroundViewService</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.vehicle</name>
<interface>
@@ -273,6 +273,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.gnss.measurement_corrections</name>
+ <version>1</version>
+ <interface>
+ <name>IMeasurementCorrectionsInterface</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.allocator</name>
<!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
@@ -284,6 +292,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.graphics.allocator</name>
+ <version>1</version>
+ <interface>
+ <name>IAllocator</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.composer</name>
<version>2.1-4</version>
@@ -456,7 +472,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.neuralnetworks</name>
- <version>1-3</version>
+ <version>1-4</version>
<interface>
<name>IDevice</name>
<regex-instance>.*</regex-instance>
@@ -470,6 +486,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.nfc</name>
+ <interface>
+ <name>INfc</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.oemlock</name>
<version>1.0</version>
@@ -688,7 +711,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="hidl" optional="false">
<name>android.hardware.thermal</name>
<version>2.0</version>
<interface>
@@ -736,6 +759,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>
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
index 41bc9ae..d998478 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
@@ -39,4 +39,6 @@
WIFI_SCANNING = 3,
AIRPLANE_MODE = 4,
MICROPHONE = 5,
+ BT_MAIN = 6,
+ BT_SCANNING = 7,
}
diff --git a/contexthub/aidl/android/hardware/contexthub/Setting.aidl b/contexthub/aidl/android/hardware/contexthub/Setting.aidl
index f2e55db..91d4c3f 100644
--- a/contexthub/aidl/android/hardware/contexthub/Setting.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/Setting.aidl
@@ -39,4 +39,12 @@
* by CHRE.
*/
MICROPHONE,
+ /**
+ * The main BT toggle in the Android settings for BT connectivity.
+ */
+ BT_MAIN,
+ /**
+ * The "BT scanning" setting for location scans.
+ */
+ BT_SCANNING,
}
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index a47f64e..f0583be 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -300,6 +300,14 @@
testSettingChanged(Setting::MICROPHONE);
}
+TEST_P(ContextHubAidl, TestOnBtMainSettingChanged) {
+ testSettingChanged(Setting::BT_MAIN);
+}
+
+TEST_P(ContextHubAidl, TestOnBtScanningSettingChanged) {
+ testSettingChanged(Setting::BT_SCANNING);
+}
+
std::vector<std::tuple<std::string, int32_t>> generateContextHubMapping() {
std::vector<std::tuple<std::string, int32_t>> tuples;
auto contextHubAidlNames = android::getAidlHalInstanceNames(IContextHub::descriptor);
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index c59d5e7..f8fad94 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -36,6 +36,7 @@
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
"android.hardware.gnss@common-vts-lib",
+ "android.hardware.gnss-V2-cpp",
],
shared_libs: [
"android.hardware.gnss.measurement_corrections@1.0",
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 3bbd572..2042dd9 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -39,6 +39,10 @@
"android.hardware.gnss@2.0",
"android.hardware.gnss@2.1",
"android.hardware.gnss@common-vts-lib",
+ "android.hardware.gnss-V2-cpp",
],
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
index aaddd96..d7b6eeb 100644
--- a/gnss/2.1/vts/functional/Android.bp
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -40,6 +40,7 @@
"android.hardware.gnss@2.0",
"android.hardware.gnss@2.1",
"android.hardware.gnss@common-vts-lib",
+ "android.hardware.gnss-V2-cpp",
],
shared_libs: [
"libvintf",
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
index 12dd0ac..4d9c5cc 100644
--- a/gnss/aidl/Android.bp
+++ b/gnss/aidl/Android.bp
@@ -24,27 +24,13 @@
}
aidl_interface {
- name: "android.hardware.gnss.visibility_control",
- vendor_available: true,
- srcs: ["android/hardware/gnss/visibility_control/*.aidl"],
- stability: "vintf",
- backend: {
- java: {
- platform_apis: true,
- },
- ndk: {
- vndk: {
- enabled: true,
- },
- },
- },
-}
-
-aidl_interface {
name: "android.hardware.gnss",
vendor_available: true,
- srcs: ["android/hardware/gnss/*.aidl"],
- imports: ["android.hardware.gnss.visibility_control"],
+ srcs: [
+ "android/hardware/gnss/*.aidl",
+ "android/hardware/gnss/measurement_corrections/*.aidl",
+ "android/hardware/gnss/visibility_control/*.aidl",
+ ],
stability: "vintf",
backend: {
java: {
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
new file mode 100644
index 0000000..73df195
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gnss;
+@VintfStability
+interface IAGnssRil {
+ void setCallback(in android.hardware.gnss.IAGnssRilCallback callback);
+ void setRefLocation(in android.hardware.gnss.IAGnssRil.AGnssRefLocation agnssReflocation);
+ void setSetId(in android.hardware.gnss.IAGnssRil.SetIDType type, in @utf8InCpp String setid);
+ void updateNetworkState(in android.hardware.gnss.IAGnssRil.NetworkAttributes attributes);
+ const int NETWORK_CAPABILITY_NOT_METERED = 1;
+ const int NETWORK_CAPABILITY_NOT_ROAMING = 2;
+ @Backing(type="int") @VintfStability
+ enum AGnssRefLocationType {
+ GSM_CELLID = 1,
+ UMTS_CELLID = 2,
+ LTE_CELLID = 4,
+ NR_CELLID = 8,
+ }
+ @Backing(type="int") @VintfStability
+ enum SetIDType {
+ NONE = 0,
+ IMSI = 1,
+ MSISDM = 2,
+ }
+ @VintfStability
+ parcelable AGnssRefLocationCellID {
+ android.hardware.gnss.IAGnssRil.AGnssRefLocationType type;
+ int mcc;
+ int mnc;
+ int lac;
+ long cid;
+ int tac;
+ int pcid;
+ int arfcn;
+ }
+ @VintfStability
+ parcelable AGnssRefLocation {
+ android.hardware.gnss.IAGnssRil.AGnssRefLocationType type;
+ android.hardware.gnss.IAGnssRil.AGnssRefLocationCellID cellID;
+ }
+ @VintfStability
+ parcelable NetworkAttributes {
+ long networkHandle;
+ boolean isConnected;
+ int capabilities;
+ @utf8InCpp String apn;
+ }
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl
index 7ef08d2..152b10a 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IAGnssRilCallback {
+ void requestSetIdCb(in int setIdflag);
+ void requestRefLocCb();
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
index 1b4c581..a16d27b 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
@@ -44,6 +44,7 @@
@nullable android.hardware.gnss.IGnssGeofence getExtensionGnssGeofence();
@nullable android.hardware.gnss.IGnssNavigationMessageInterface getExtensionGnssNavigationMessage();
android.hardware.gnss.IAGnss getExtensionAGnss();
+ android.hardware.gnss.IAGnssRil getExtensionAGnssRil();
android.hardware.gnss.IGnssDebug getExtensionGnssDebug();
android.hardware.gnss.visibility_control.IGnssVisibilityControl getExtensionGnssVisibilityControl();
void start();
@@ -53,6 +54,8 @@
void injectBestLocation(in android.hardware.gnss.GnssLocation location);
void deleteAidingData(in android.hardware.gnss.IGnss.GnssAidingData aidingDataFlags);
void setPositionMode(in android.hardware.gnss.IGnss.GnssPositionMode mode, in android.hardware.gnss.IGnss.GnssPositionRecurrence recurrence, in int minIntervalMs, in int preferredAccuracyMeters, in int preferredTimeMs, in boolean lowPowerMode);
+ android.hardware.gnss.IGnssAntennaInfo getExtensionGnssAntennaInfo();
+ @nullable android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsInterface getExtensionMeasurementCorrections();
const int ERROR_INVALID_ARGUMENT = 1;
const int ERROR_ALREADY_INIT = 2;
const int ERROR_GENERIC = 3;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
index 7ef08d2..2734ac1 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IGnssAntennaInfo {
+ void setCallback(in android.hardware.gnss.IGnssAntennaInfoCallback callback);
+ void close();
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
similarity index 63%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
index 7ef08d2..ada9707 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
@@ -31,9 +31,30 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IGnssAntennaInfoCallback {
+ void gnssAntennaInfoCb(in android.hardware.gnss.IGnssAntennaInfoCallback.GnssAntennaInfo[] gnssAntennaInfos);
+ @VintfStability
+ parcelable Row {
+ double[] row;
+ }
+ @VintfStability
+ parcelable Coord {
+ double x;
+ double xUncertainty;
+ double y;
+ double yUncertainty;
+ double z;
+ double zUncertainty;
+ }
+ @VintfStability
+ parcelable GnssAntennaInfo {
+ long carrierFrequencyHz;
+ android.hardware.gnss.IGnssAntennaInfoCallback.Coord phaseCenterOffsetCoordinateMillimeters;
+ android.hardware.gnss.IGnssAntennaInfoCallback.Row[] phaseCenterVariationCorrectionMillimeters;
+ android.hardware.gnss.IGnssAntennaInfoCallback.Row[] phaseCenterVariationCorrectionUncertaintyMillimeters;
+ android.hardware.gnss.IGnssAntennaInfoCallback.Row[] signalGainCorrectionDbi;
+ android.hardware.gnss.IGnssAntennaInfoCallback.Row[] signalGainCorrectionUncertaintyDbi;
+ }
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
index 492edc3..e1beed3 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
@@ -36,9 +36,15 @@
interface IGnssBatching {
void init(in android.hardware.gnss.IGnssBatchingCallback callback);
int getBatchSize();
- void start(in long periodNanos, in int flags);
+ void start(in android.hardware.gnss.IGnssBatching.Options options);
void flush();
void stop();
void cleanup();
const int WAKEUP_ON_FIFO_FULL = 1;
+ @VintfStability
+ parcelable Options {
+ long periodNanos;
+ float minDistanceMeters;
+ int flags;
+ }
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
similarity index 85%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
index 7ef08d2..c4cf13f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss.measurement_corrections;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IMeasurementCorrectionsCallback {
+ void setCapabilitiesCb(in int capabilities);
+ const int CAPABILITY_LOS_SATS = 1;
+ const int CAPABILITY_EXCESS_PATH_LENGTH = 2;
+ const int CAPABILITY_REFLECTING_PLANE = 4;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
index 7ef08d2..5dc5596 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss.measurement_corrections;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IMeasurementCorrectionsInterface {
+ void setCorrections(in android.hardware.gnss.measurement_corrections.MeasurementCorrections corrections);
+ void setCallback(in android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsCallback callback);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
similarity index 77%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
index 7ef08d2..f32c8c2 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
@@ -31,9 +31,17 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss.measurement_corrections;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable MeasurementCorrections {
+ double latitudeDegrees;
+ double longitudeDegrees;
+ double altitudeMeters;
+ double horizontalPositionUncertaintyMeters;
+ double verticalPositionUncertaintyMeters;
+ long toaGpsNanosecondsOfWeek;
+ android.hardware.gnss.measurement_corrections.SingleSatCorrection[] satCorrections;
+ boolean hasEnvironmentBearing;
+ float environmentBearingDegrees;
+ float environmentBearingUncertaintyDegrees;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
index 7ef08d2..90c3818 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss.measurement_corrections;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable ReflectingPlane {
+ double latitudeDegrees;
+ double longitudeDegrees;
+ double altitudeMeters;
+ double azimuthDegrees;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
similarity index 72%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
index 7ef08d2..d18c1a7 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -31,9 +31,19 @@
// 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.gnss.visibility_control;
+package android.hardware.gnss.measurement_corrections;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable SingleSatCorrection {
+ int singleSatCorrectionFlags;
+ android.hardware.gnss.GnssConstellationType constellation;
+ int svid;
+ long carrierFrequencyHz;
+ float probSatIsLos;
+ float excessPathLengthMeters;
+ float excessPathLengthUncertaintyMeters;
+ android.hardware.gnss.measurement_corrections.ReflectingPlane reflectingPlane;
+ const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 1;
+ const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 2;
+ const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 4;
+ const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 8;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
similarity index 96%
rename from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
rename to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
index 7ef08d2..f674099 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
@@ -34,6 +34,6 @@
package android.hardware.gnss.visibility_control;
@VintfStability
interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
+ void enableNfwLocationAccess(in @utf8InCpp String[] proxyApps);
void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
similarity index 100%
rename from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
rename to gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
new file mode 100644
index 0000000..c506b04
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
@@ -0,0 +1,166 @@
+/*
+ * 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.gnss;
+
+import android.hardware.gnss.IAGnssRilCallback;
+import android.hardware.gnss.IAGnssRilCallback.SetIDType;
+
+/**
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface
+ * Layer interface allows the GNSS chipset to request radio interface layer
+ * information from Android platform. Examples of such information are reference
+ * location, unique subscriber ID, phone number string and network availability changes.
+ */
+@VintfStability
+interface IAGnssRil {
+ /** Network capability mode bitmask for not metered. */
+ const int NETWORK_CAPABILITY_NOT_METERED = 0x01;
+
+ /** Network capability mode bitmask for not roaming. */
+ const int NETWORK_CAPABILITY_NOT_ROAMING = 0x02;
+
+ /** AGNSS reference location type */
+ @VintfStability
+ @Backing(type="int")
+ enum AGnssRefLocationType {
+ GSM_CELLID = 1,
+ UMTS_CELLID = 2,
+ LTE_CELLID = 4,
+ NR_CELLID = 8,
+ }
+
+ /** SET ID type*/
+ @VintfStability
+ @Backing(type="int")
+ enum SetIDType {
+ NONE = 0,
+ IMSI = 1,
+ MSISDM = 2,
+ }
+
+ /**
+ * CellID for 2G, 3G ,LTE and NR used in AGNSS. This is defined in
+ * UserPlane Location Protocol (Version 2.0.4).
+ */
+ @VintfStability
+ parcelable AGnssRefLocationCellID {
+ AGnssRefLocationType type;
+
+ /** Mobile Country Code. */
+ int mcc;
+
+ /** Mobile Network Code .*/
+ int mnc;
+
+ /**
+ * Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE,
+ * lac is populated with tac, to ensure that we don't break old clients that
+ * might rely on the old (wrong) behavior.
+ */
+ int lac;
+
+ /**
+ * Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE.
+ * Cell Global Id NR in 5G.
+ */
+ long cid;
+
+ /** Tracking Area Code in LTE and NR. */
+ int tac;
+
+ /** Physical Cell id in LTE and NR (not used in 2G and 3G) */
+ int pcid;
+
+ /** Absolute Radio Frequency Channel Number in NR. */
+ int arfcn;
+ }
+
+ /** Represents ref locations */
+ @VintfStability
+ parcelable AGnssRefLocation {
+ AGnssRefLocationType type;
+
+ AGnssRefLocationCellID cellID;
+ }
+
+ /** Represents network connection status and capabilities. */
+ @VintfStability
+ parcelable NetworkAttributes {
+ /** Network handle of the network for use with the NDK API. */
+ long networkHandle;
+
+ /**
+ * True indicates that network connectivity exists and it is possible to
+ * establish connections and pass data. If false, only the networkHandle field
+ * is populated to indicate that this network has just disconnected.
+ */
+ boolean isConnected;
+
+ /**
+ * A bitfield of flags indicating the capabilities of this network. The bit masks are
+ * defined in NETWORK_CAPABILITY_*.
+ */
+ int capabilities;
+
+ /**
+ * Telephony preferred Access Point Name to use for carrier data connection when
+ * connected to a cellular network. Empty string, otherwise.
+ */
+ @utf8InCpp String apn;
+ }
+
+ /**
+ * Opens the AGNSS interface and provides the callback routines
+ * to the implementation of this interface.
+ *
+ * @param callback Interface for AGnssRil callbacks.
+ *
+ */
+ void setCallback(in IAGnssRilCallback callback);
+
+ /**
+ * Sets the reference location.
+ *
+ * @param agnssReflocation AGNSS reference location CellID.
+ *
+ */
+ void setRefLocation(in AGnssRefLocation agnssReflocation);
+
+ /**
+ * Sets the SET ID.
+ *
+ * @param type Must be populated with either IMSI or MSISDN or NONE.
+ * @param setid If type is IMSI then setid is populated with
+ * a string representing the unique Subscriber ID, for example, the IMSI for
+ * a GMS phone. If type is MSISDN, then setid must contain
+ * the phone number string for line 1. For example, the MSISDN for a GSM phone.
+ * If the type is NONE, then the string must be empty.
+ *
+ */
+ void setSetId(in SetIDType type, in @utf8InCpp String setid);
+
+ /**
+ * Notifies GNSS of network status changes.
+ *
+ * The framework calls this method to update the GNSS HAL implementation of network
+ * state changes.
+ *
+ * @param attributes Updated network attributes.
+ *
+ */
+ void updateNetworkState(in NetworkAttributes attributes);
+}
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl b/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl
new file mode 100644
index 0000000..6fb093e
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.gnss;
+
+/**
+ * Callback for IAGnssRil interface. Used to request SET ID and
+ * Reference Location.
+ */
+@VintfStability
+interface IAGnssRilCallback {
+ /**
+ * The Hal uses this API to request a SET ID.
+ *
+ * @param setIdflag A bitfield of IAGnssRil.SetIDType that is required by
+ * the HAL. The framework will inject an empty SET ID if the flag is NONE.
+ *
+ */
+ void requestSetIdCb(in int setIdflag);
+
+ /**
+ * The Hal uses this API to request a reference location.
+ */
+ void requestRefLocCb();
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index 4ddc6a6..99f2ee4 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -18,6 +18,8 @@
import android.hardware.gnss.GnssLocation;
import android.hardware.gnss.IAGnss;
+import android.hardware.gnss.IAGnssRil;
+import android.hardware.gnss.IGnssAntennaInfo;
import android.hardware.gnss.IGnssBatching;
import android.hardware.gnss.IGnssCallback;
import android.hardware.gnss.IGnssConfiguration;
@@ -27,6 +29,7 @@
import android.hardware.gnss.IGnssNavigationMessageInterface;
import android.hardware.gnss.IGnssPowerIndication;
import android.hardware.gnss.IGnssPsds;
+import android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsInterface;
import android.hardware.gnss.visibility_control.IGnssVisibilityControl;
/**
@@ -186,6 +189,13 @@
IAGnss getExtensionAGnss();
/**
+ * This method returns the IAGnssRil interface.
+ *
+ * @return The IAGnssRil interface.
+ */
+ IAGnssRil getExtensionAGnssRil();
+
+ /**
* This method returns the IGnssDebug interface.
*
* This method must return non-null.
@@ -277,4 +287,18 @@
void setPositionMode(in GnssPositionMode mode, in GnssPositionRecurrence recurrence,
in int minIntervalMs, in int preferredAccuracyMeters, in int preferredTimeMs,
in boolean lowPowerMode);
+
+ /*
+ * This method returns the IGnssAntennaInfo.
+ *
+ * @return Handle to the IGnssAntennaInfo.
+ */
+ IGnssAntennaInfo getExtensionGnssAntennaInfo();
+
+ /**
+ * This method returns the IMeasurementCorrectionsInterface.
+ *
+ * @return Handle to the IMeasurementCorrectionsInterface.
+ */
+ @nullable IMeasurementCorrectionsInterface getExtensionMeasurementCorrections();
}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl
new file mode 100644
index 0000000..de83b67
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl
@@ -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.
+ */
+
+package android.hardware.gnss;
+
+import android.hardware.gnss.IGnssAntennaInfoCallback;
+
+/**
+ * Extended interface for GNSS antenna information support.
+ */
+@VintfStability
+interface IGnssAntennaInfo {
+ /**
+ * Registers the callback routines with the HAL.
+ *
+ * @param callback Handle to the GnssAntennaInfo callback interface.
+ */
+ void setCallback(in IGnssAntennaInfoCallback callback);
+
+ /**
+ * Stops updates from the HAL, and unregisters the callback routines.
+ * After a call to close(), the previously registered callbacks must be
+ * considered invalid by the HAL.
+ * If close() is invoked without a previous setCallback, this function must perform
+ * no work.
+ */
+ void close();
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
new file mode 100644
index 0000000..ef0a7fc
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
@@ -0,0 +1,140 @@
+/*
+ * 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.gnss;
+
+/**
+ * The callback interface to report GNSS antenna information from the HAL.
+ */
+@VintfStability
+interface IGnssAntennaInfoCallback {
+ /**
+ * A row of doubles. This is used to represent a row in a 2D array, which are used to
+ * characterize the phase center variation corrections and signal gain corrections.
+ */
+ @VintfStability
+ parcelable Row {
+ double[] row;
+ }
+
+ /**
+ * A point in 3D space, with associated uncertainty.
+ */
+ @VintfStability
+ parcelable Coord {
+ double x;
+
+ double xUncertainty;
+
+ double y;
+
+ double yUncertainty;
+
+ double z;
+
+ double zUncertainty;
+ }
+
+ @VintfStability
+ parcelable GnssAntennaInfo {
+ /**
+ * The carrier frequency in Hz.
+ */
+ long carrierFrequencyHz;
+
+ /**
+ * Phase center offset (PCO) with associated 1-sigma uncertainty. PCO is defined with
+ * respect to the origin of the Android sensor coordinate system, e.g., center of primary
+ * screen for mobiles - see sensor or form factor documents for details.
+ */
+ Coord phaseCenterOffsetCoordinateMillimeters;
+
+ /**
+ * 2D vectors representing the phase center variation (PCV) corrections, in
+ * millimeters, at regularly spaced azimuthal angle (theta) and zenith angle
+ * (phi). The PCV correction is added to the phase measurement to obtain the
+ * corrected value.
+ *
+ * The azimuthal angle, theta, is defined with respect to the X axis of the
+ * Android sensor coordinate system, increasing toward the Y axis. The zenith
+ * angle, phi, is defined with respect to the Z axis of the Android Sensor
+ * coordinate system, increasing toward the X-Y plane.
+ *
+ * Each row vector (outer vectors) represents a fixed theta. The first row
+ * corresponds to a theta angle of 0 degrees. The last row corresponds to a
+ * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+ * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+ *
+ * The columns (inner vectors) represent fixed zenith angles, beginning at 0
+ * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+ * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+ *
+ * This field is optional, i.e., an empty vector.
+ */
+ Row[] phaseCenterVariationCorrectionMillimeters;
+
+ /**
+ * 2D vectors of 1-sigma uncertainty in millimeters associated with the PCV
+ * correction values.
+ *
+ * This field is optional, i.e., an empty vector.
+ */
+ Row[] phaseCenterVariationCorrectionUncertaintyMillimeters;
+
+ /**
+ * 2D vectors representing the signal gain corrections at regularly spaced
+ * azimuthal angle (theta) and zenith angle (phi). The values are calculated or
+ * measured at the antenna feed point without considering the radio and receiver
+ * noise figure and path loss contribution, in dBi, i.e., decibel over isotropic
+ * antenna with the same total power. The signal gain correction is added the
+ * signal gain measurement to obtain the corrected value.
+ *
+ * The azimuthal angle, theta, is defined with respect to the X axis of the
+ * Android sensor coordinate system, increasing toward the Y axis. The zenith
+ * angle, phi, is defined with respect to the Z axis of the Android Sensor
+ * coordinate system, increasing toward the X-Y plane.
+ *
+ * Each row vector (outer vectors) represents a fixed theta. The first row
+ * corresponds to a theta angle of 0 degrees. The last row corresponds to a
+ * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+ * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+ *
+ * The columns (inner vectors) represent fixed zenith angles, beginning at 0
+ * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+ * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+ *
+ * This field is optional, i.e., an empty vector.
+ */
+ Row[] signalGainCorrectionDbi;
+
+ /**
+ * 2D vectors of 1-sigma uncertainty in dBi associated with the signal
+ * gain correction values.
+ *
+ * This field is optional, i.e., an empty vector.
+ */
+ Row[] signalGainCorrectionUncertaintyDbi;
+ }
+
+ /**
+ * Called when on connection, and on known-change to these values, such as upon a known
+ * GNSS RF antenna tuning change, or a foldable device state change.
+ *
+ * This is optional. It can never be called if the GNSS antenna information is not
+ * available.
+ */
+ void gnssAntennaInfoCb(in GnssAntennaInfo[] gnssAntennaInfos);
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl b/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
index 0d48ee1..0d03a0f 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
@@ -46,6 +46,25 @@
*/
const int WAKEUP_ON_FIFO_FULL = 0x01;
+ /** Options specifying the batching request. */
+ @VintfStability
+ parcelable Options {
+ /** Time interval between samples in the location batch, in nanoseconds. */
+ long periodNanos;
+
+ /**
+ * The minimum distance in meters that the batching engine should
+ * accumulate before trying another GPS fix when in a challenging GPS environment.
+ *
+ * This is an optional field. If it is set as 0, the chipset can operate in an automatic
+ * mode.
+ */
+ float minDistanceMeters;
+
+ /** A bit field of Flags (WAKEUP_ON_FIFO_FULL) indicating the batching behavior. */
+ int flags;
+ }
+
/**
* Open the interface and provides the callback routines to the implementation of this
* interface.
@@ -83,10 +102,9 @@
* for using flushBatchedLocation to explicitly ask for the location as needed, to avoid it
* being dropped.
*
- * @param periodNanos Time interval between samples in the location batch, in nanoseconds
- * @param flags A bitfield of flags (WAKEUP_ON_FIFO_FULL) indicating the batching behavior
+ * @param options Options specifying the batching request.
*/
- void start(in long periodNanos, in int flags);
+ void start(in Options options);
/**
* Retrieve all batched locations currently stored.
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
index 157c912..a74d097 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
@@ -67,7 +67,7 @@
/** Capability bit mask indicating that GNSS supports measurement corrections */
const int CAPABILITY_MEASUREMENT_CORRECTIONS = 1 << 10;
- /** Capability bit mask indicating that GNSS supports measurement corrections */
+ /** Capability bit mask indicating that GNSS supports antenna info */
const int CAPABILITY_ANTENNA_INFO = 1 << 11;
/** Capability bit mask indicating that GNSS supports correlation vector */
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
new file mode 100644
index 0000000..d695e70
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
@@ -0,0 +1,57 @@
+/*
+ * 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.gnss.measurement_corrections;
+
+/**
+ * GNSS measurement corrections callback interface.
+ */
+@VintfStability
+interface IMeasurementCorrectionsCallback {
+ /**
+ * Flags to indicate supported measurement corrections capabilities
+ *
+ * Either the LOS_SATS or the EXCESS_PATH_LENGTH capability must be supported.
+ */
+ /**
+ * Capability bit flag indicating that GNSS supports line-of-sight satellite identification
+ * measurement corrections
+ */
+ const int CAPABILITY_LOS_SATS = 1 << 0;
+ /**
+ * Capability bit flag indicating that GNSS supports per satellite excess-path-length
+ * measurement corrections
+ */
+ const int CAPABILITY_EXCESS_PATH_LENGTH = 1 << 1;
+ /**
+ * Capability bit flag indicating that GNSS supports reflecting planes measurement
+ * corrections
+ */
+ const int CAPABILITY_REFLECTING_PLANE = 1 << 2;
+
+ /**
+ * Callback to inform framework the measurement correction specific capabilities of the GNSS
+ * HAL implementation.
+ *
+ * The GNSS HAL must call this method immediately after the framework opens the measurement
+ * corrections interface.
+ *
+ * @param capabilities A bit field of flags indicating the capabilities of measurement
+ * corrections.
+ * It is mandatory to support either LOS_STATS or EXCESS_PATH_LENGTH capability.
+ */
+ void setCapabilitiesCb(in int capabilities);
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
new file mode 100644
index 0000000..eeabc6d
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
@@ -0,0 +1,48 @@
+/*
+ * 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.gnss.measurement_corrections;
+
+import android.hardware.gnss.measurement_corrections.IMeasurementCorrectionsCallback;
+import android.hardware.gnss.measurement_corrections.MeasurementCorrections;
+
+/**
+ * Interface for measurement corrections support.
+ */
+@VintfStability
+interface IMeasurementCorrectionsInterface {
+ /**
+ * Injects measurement corrections to be used by the HAL to improve the GNSS location output.
+ *
+ * These are NOT to be used to adjust the IGnssMeasurementCallback output values -
+ * those remain raw, uncorrected measurements.
+ *
+ * In general, these are injected when conditions defined by the platform are met, such as when
+ * GNSS Location is being requested at a sufficiently high accuracy, based on the capabilities
+ * of the GNSS chipset as reported in the IGnssCallback.
+ *
+ * @param corrections The computed corrections to be used by the HAL.
+ */
+ void setCorrections(in MeasurementCorrections corrections);
+
+ /**
+ * Opens the interface and provides the callback routines to the implementation of this
+ * interface.
+ *
+ * @param callback Callback interface for IMeasurementCorrections.
+ */
+ void setCallback(in IMeasurementCorrectionsCallback callback);
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
new file mode 100644
index 0000000..285c7d4
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
@@ -0,0 +1,102 @@
+/*
+ * 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.gnss.measurement_corrections;
+
+import android.hardware.gnss.measurement_corrections.SingleSatCorrection;
+
+/**
+ * A struct containing a set of measurement corrections for all used GNSS satellites at the location
+ * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified
+ * toaGpsNanosecondsOfWeek
+ */
+@VintfStability
+parcelable MeasurementCorrections {
+ /** Represents latitude in degrees at which the corrections are computed.. */
+ double latitudeDegrees;
+
+ /** Represents longitude in degrees at which the corrections are computed.. */
+ double longitudeDegrees;
+
+ /**
+ * Represents altitude in meters above the WGS 84 reference ellipsoid at which the corrections
+ * are computed.
+ */
+ double altitudeMeters;
+
+ /**
+ * Represents the horizontal uncertainty (63% to 68% confidence) in meters on the device
+ * position at which the corrections are provided.
+ *
+ * This value is useful for example to judge how accurate the provided corrections are.
+ */
+ double horizontalPositionUncertaintyMeters;
+
+ /**
+ * Represents the vertical uncertainty (63% to 68% confidence) in meters on the device position
+ * at which the corrections are provided.
+ *
+ * This value is useful for example to judge how accurate the provided corrections are.
+ */
+ double verticalPositionUncertaintyMeters;
+
+ /** Time Of Applicability, GPS time of week in nanoseconds. */
+ long toaGpsNanosecondsOfWeek;
+
+ /**
+ * A set of SingleSatCorrection each containing measurement corrections for a satellite in view
+ */
+ SingleSatCorrection[] satCorrections;
+
+ /**
+ * Boolean indicating if environment bearing is available.
+ */
+ boolean hasEnvironmentBearing;
+
+ /**
+ * Environment bearing in degrees clockwise from true North (0.0 to 360.0], in direction of
+ * user motion. Environment bearing is provided when it is known with high probability that
+ * velocity is aligned with an environment feature, such as a building or road.
+ *
+ * If user speed is zero, environmentBearingDegrees represents bearing of most recent speed
+ * that was > 0.
+ *
+ * As position approaches another road, environmentBearingUncertaintyDegrees will grow, and at
+ * some stage hasEnvironmentBearing = false.
+ *
+ * As position moves towards an open area, environmentBearingUncertaintyDegrees will grow, and
+ * at some stage hasEnvironmentBearing = false.
+ *
+ * If the road is curved in the vicinity of the user location, then
+ * environmentBearingUncertaintyDegrees will include the amount by which the road direction
+ * changes in the area of position uncertainty.
+ *
+ * hasEnvironmentBearing should be checked to verify the environment bearing is available
+ * before calling this method. The value is undefined if hasEnvironmentBearing is false.
+ */
+ float environmentBearingDegrees;
+
+ /**
+ * Environment bearing uncertainty [0 to 180]. It represents the standard deviation of the
+ * physical structure in the circle of position uncertainty. hasEnvironmentBearing becomes false
+ * as the uncertainty value passes a predefined threshold depending on the physical structure
+ * around the user.
+ *
+ * hasEnvironmentBearing should be checked to verify the environment bearing is available
+ * before calling this method. The value is undefined if hasEnvironmentBearing is false.
+ */
+ float environmentBearingUncertaintyDegrees;
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
new file mode 100644
index 0000000..9bf2b44
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -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.gnss.measurement_corrections;
+
+/**
+ * A struct containing the characteristics of the reflecting plane that the satellite signal has
+ * bounced from.
+ *
+ * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
+ * means either reflection planes serving is not supported or the satellite signal has gone
+ * through multiple reflections.
+ */
+@VintfStability
+parcelable ReflectingPlane {
+ /** Represents latitude of the reflecting plane in degrees. */
+ double latitudeDegrees;
+
+ /** Represents longitude of the reflecting plane in degrees. */
+ double longitudeDegrees;
+
+ /**
+ * Represents altitude of the reflecting point in the plane in meters above the WGS 84 reference
+ * ellipsoid.
+ */
+ double altitudeMeters;
+
+ /** Represents azimuth clockwise from north of the reflecting plane in degrees. */
+ double azimuthDegrees;
+}
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
new file mode 100644
index 0000000..d9f7105
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -0,0 +1,85 @@
+/*
+ * 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.gnss.measurement_corrections;
+
+import android.hardware.gnss.GnssConstellationType;
+import android.hardware.gnss.measurement_corrections.ReflectingPlane;
+
+/**
+ * A struct with measurement corrections for a single visible satellites
+ *
+ * The bit mask singleSatCorrectionFlags indicates which correction values are valid in the struct
+ */
+@VintfStability
+parcelable SingleSatCorrection {
+ /** Bit mask to indicate which values are valid in a SingleSatCorrection object. */
+ /** GnssSingleSatCorrectionFlags has valid satellite-is-line-of-sight-probability field. */
+ const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 0x0001;
+ /** GnssSingleSatCorrectionFlags has valid Excess Path Length field. */
+ const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 0x0002;
+ /** GnssSingleSatCorrectionFlags has valid Excess Path Length Uncertainty field. */
+ const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 0x0004;
+ /** GnssSingleSatCorrectionFlags has valid Reflecting Plane field. */
+ const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 0x0008;
+
+ /** Contains GnssSingleSatCorrectionFlags bits. */
+ int singleSatCorrectionFlags;
+
+ /**
+ * Defines the constellation of the given satellite.
+ */
+ GnssConstellationType constellation;
+
+ /**
+ * Satellite vehicle ID number, as defined in GnssSvInfo::svid
+ */
+ int svid;
+
+ /**
+ * Carrier frequency of the signal to be corrected, for example it can be the
+ * GPS center frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
+ *
+ * For a receiver with capabilities to track multiple frequencies for the same satellite,
+ * multiple corrections for the same satellite may be provided.
+ */
+ long carrierFrequencyHz;
+
+ /**
+ * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
+ * location.
+ */
+ float probSatIsLos;
+
+ /**
+ * Excess path length to be subtracted from pseudorange before using it in calculating location.
+ *
+ * Note this value is NOT to be used to adjust the GnsseasurementCallback outputs.
+ */
+ float excessPathLengthMeters;
+
+ /** Error estimate (1-sigma) for the Excess path length estimate */
+ float excessPathLengthUncertaintyMeters;
+
+ /**
+ * Defines the reflecting plane characteristics such as location and azimuth
+ *
+ * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
+ * means either reflection planes serving is not supported or the satellite signal has gone
+ * through multiple reflections.
+ */
+ ReflectingPlane reflectingPlane;
+}
diff --git a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
index 93c3f2c..c9c1549 100644
--- a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
@@ -71,7 +71,7 @@
* The package name of the proxy Android application follows the standard Java language
* package naming format. For example, com.example.myapp.
*/
- void enableNfwLocationAccess(in String[] proxyApps);
+ void enableNfwLocationAccess(in @utf8InCpp String[] proxyApps);
/**
* Registers the callback for HAL implementation to use.
diff --git a/gnss/aidl/default/AGnssRil.cpp b/gnss/aidl/default/AGnssRil.cpp
new file mode 100644
index 0000000..afe0039
--- /dev/null
+++ b/gnss/aidl/default/AGnssRil.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "AGnssRilAidl"
+
+#include "AGnssRil.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss {
+
+std::shared_ptr<IAGnssRilCallback> AGnssRil::sCallback = nullptr;
+
+ndk::ScopedAStatus AGnssRil::setCallback(const std::shared_ptr<IAGnssRilCallback>& callback) {
+ ALOGD("AGnssRil::setCallback");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnssRil::setRefLocation(const AGnssRefLocation& agnssReflocation) {
+ const AGnssRefLocationCellID& cellInfo = agnssReflocation.cellID;
+ ALOGD("AGnssRil::setRefLocation: type: %s, mcc: %d, mnc: %d, lac: %d, cid: %" PRId64
+ ", tac: %d, pcid: "
+ "%d, arfcn: %d",
+ toString(agnssReflocation.type).c_str(), cellInfo.mcc, cellInfo.mnc, cellInfo.lac,
+ cellInfo.cid, cellInfo.tac, cellInfo.pcid, cellInfo.arfcn);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnssRil::setSetId(SetIDType type, const std::string& setid) {
+ ALOGD("AGnssRil::setSetId: type:%s, setid: %s", toString(type).c_str(), setid.c_str());
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AGnssRil::updateNetworkState(const NetworkAttributes& attributes) {
+ ALOGD("AGnssRil::updateNetworkState: networkHandle:%" PRId64
+ ", isConnected: %d, capabilities: %d, "
+ "apn: %s",
+ attributes.networkHandle, attributes.isConnected, attributes.capabilities,
+ attributes.apn.c_str());
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/AGnssRil.h b/gnss/aidl/default/AGnssRil.h
new file mode 100644
index 0000000..7e429ee
--- /dev/null
+++ b/gnss/aidl/default/AGnssRil.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnAGnssRil.h>
+
+namespace aidl::android::hardware::gnss {
+
+struct AGnssRil : public BnAGnssRil {
+ public:
+ ndk::ScopedAStatus setCallback(const std::shared_ptr<IAGnssRilCallback>& callback) override;
+ ndk::ScopedAStatus setRefLocation(const AGnssRefLocation& agnssReflocation) override;
+ ndk::ScopedAStatus setSetId(SetIDType type, const std::string& setid) override;
+ ndk::ScopedAStatus updateNetworkState(const NetworkAttributes& attributes) override;
+
+ private:
+ // Synchronization lock for sCallback
+ mutable std::mutex mMutex;
+ // Guarded by mMutex
+ static std::shared_ptr<IAGnssRilCallback> sCallback;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index 29c26d1..4543665 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -52,12 +52,13 @@
"android.hardware.gnss.measurement_corrections@1.1",
"android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.visibility_control@1.0",
- "android.hardware.gnss.visibility_control-V1-ndk",
"android.hardware.gnss-V2-ndk",
],
srcs: [
+ "AGnssRil.cpp",
"AGnss.cpp",
"Gnss.cpp",
+ "GnssAntennaInfo.cpp",
"GnssBatching.cpp",
"GnssDebug.cpp",
"GnssGeofence.cpp",
@@ -68,6 +69,7 @@
"GnssConfiguration.cpp",
"GnssMeasurementInterface.cpp",
"GnssVisibilityControl.cpp",
+ "MeasurementCorrectionsInterface.cpp",
"service.cpp",
],
static_libs: [
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 6578778..6331dfd 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -20,7 +20,9 @@
#include <inttypes.h>
#include <log/log.h>
#include "AGnss.h"
+#include "AGnssRil.h"
#include "DeviceFileReader.h"
+#include "GnssAntennaInfo.h"
#include "GnssBatching.h"
#include "GnssConfiguration.h"
#include "GnssDebug.h"
@@ -29,6 +31,7 @@
#include "GnssNavigationMessageInterface.h"
#include "GnssPsds.h"
#include "GnssVisibilityControl.h"
+#include "MeasurementCorrectionsInterface.h"
#include "NmeaFixInfo.h"
#include "Utils.h"
@@ -169,7 +172,7 @@
return ScopedAStatus::ok();
}
-ndk::ScopedAStatus Gnss::getExtensionAGnss(std::shared_ptr<IAGnss>* iAGnss) {
+ScopedAStatus Gnss::getExtensionAGnss(std::shared_ptr<IAGnss>* iAGnss) {
ALOGD("Gnss::getExtensionAGnss");
*iAGnss = SharedRefBase::make<AGnss>();
return ndk::ScopedAStatus::ok();
@@ -181,6 +184,12 @@
return ScopedAStatus::ok();
}
+ScopedAStatus Gnss::getExtensionAGnssRil(std::shared_ptr<IAGnssRil>* iAGnssRil) {
+ ALOGD("Gnss::getExtensionAGnssRil");
+ *iAGnssRil = SharedRefBase::make<AGnssRil>();
+ return ndk::ScopedAStatus::ok();
+}
+
ScopedAStatus Gnss::injectLocation(const GnssLocation& location) {
ALOGD("injectLocation. lat:%lf, lng:%lf, acc:%f", location.latitudeDegrees,
location.longitudeDegrees, location.horizontalAccuracyMeters);
@@ -279,4 +288,22 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Gnss::getExtensionGnssAntennaInfo(
+ std::shared_ptr<IGnssAntennaInfo>* iGnssAntennaInfo) {
+ ALOGD("Gnss::getExtensionGnssAntennaInfo");
+
+ *iGnssAntennaInfo = SharedRefBase::make<GnssAntennaInfo>();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::getExtensionMeasurementCorrections(
+ std::shared_ptr<measurement_corrections::IMeasurementCorrectionsInterface>*
+ iMeasurementCorrections) {
+ ALOGD("Gnss::getExtensionMeasurementCorrections");
+
+ *iMeasurementCorrections =
+ SharedRefBase::make<measurement_corrections::MeasurementCorrectionsInterface>();
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index f21d756..36874b8 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -17,13 +17,16 @@
#pragma once
#include <aidl/android/hardware/gnss/BnAGnss.h>
+#include <aidl/android/hardware/gnss/BnAGnssRil.h>
#include <aidl/android/hardware/gnss/BnGnss.h>
+#include <aidl/android/hardware/gnss/BnGnssAntennaInfo.h>
#include <aidl/android/hardware/gnss/BnGnssBatching.h>
#include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
#include <aidl/android/hardware/gnss/BnGnssDebug.h>
#include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
#include <aidl/android/hardware/gnss/BnGnssPowerIndication.h>
#include <aidl/android/hardware/gnss/BnGnssPsds.h>
+#include <aidl/android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsInterface.h>
#include <aidl/android/hardware/gnss/visibility_control/BnGnssVisibilityControl.h>
#include <atomic>
#include <mutex>
@@ -65,10 +68,17 @@
ndk::ScopedAStatus getExtensionGnssNavigationMessage(
std::shared_ptr<IGnssNavigationMessageInterface>* iGnssNavigationMessage) override;
ndk::ScopedAStatus getExtensionAGnss(std::shared_ptr<IAGnss>* iAGnss) override;
+ ndk::ScopedAStatus getExtensionAGnssRil(std::shared_ptr<IAGnssRil>* iAGnssRil) override;
ndk::ScopedAStatus getExtensionGnssDebug(std::shared_ptr<IGnssDebug>* iGnssDebug) override;
ndk::ScopedAStatus getExtensionGnssVisibilityControl(
std::shared_ptr<android::hardware::gnss::visibility_control::IGnssVisibilityControl>*
iGnssVisibilityControl) override;
+ ndk::ScopedAStatus getExtensionGnssAntennaInfo(
+ std::shared_ptr<IGnssAntennaInfo>* iGnssAntennaInfo) override;
+ ndk::ScopedAStatus getExtensionMeasurementCorrections(
+ std::shared_ptr<android::hardware::gnss::measurement_corrections::
+ IMeasurementCorrectionsInterface>* iMeasurementCorrections)
+ override;
std::shared_ptr<GnssConfiguration> mGnssConfiguration;
std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
diff --git a/gnss/aidl/default/GnssAntennaInfo.cpp b/gnss/aidl/default/GnssAntennaInfo.cpp
new file mode 100644
index 0000000..72def71
--- /dev/null
+++ b/gnss/aidl/default/GnssAntennaInfo.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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 "GnssAntennaInfoAidl"
+
+#include "GnssAntennaInfo.h"
+#include <aidl/android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+#include "Utils.h"
+
+namespace aidl::android::hardware::gnss {
+
+using namespace ::android::hardware::gnss;
+using Row = IGnssAntennaInfoCallback::Row;
+using Coord = IGnssAntennaInfoCallback::Coord;
+
+std::shared_ptr<IGnssAntennaInfoCallback> GnssAntennaInfo::sCallback = nullptr;
+
+GnssAntennaInfo::GnssAntennaInfo() : mMinIntervalMs(1000) {}
+
+GnssAntennaInfo::~GnssAntennaInfo() {
+ stop();
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
+ndk::ScopedAStatus GnssAntennaInfo::setCallback(
+ const std::shared_ptr<IGnssAntennaInfoCallback>& callback) {
+ ALOGD("setCallback");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+
+ if (mIsActive) {
+ ALOGW("GnssAntennaInfo callback already set. Resetting the callback...");
+ stop();
+ }
+ start();
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus GnssAntennaInfo::close() {
+ ALOGD("close");
+ stop();
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = nullptr;
+ return ndk::ScopedAStatus::ok();
+}
+
+void GnssAntennaInfo::start() {
+ ALOGD("start");
+ mIsActive = true;
+ mThread = std::thread([this]() {
+ while (mIsActive == true) {
+ if (sCallback != nullptr) {
+ IGnssAntennaInfoCallback::GnssAntennaInfo mockAntennaInfo_1 = {
+ .carrierFrequencyHz = 1575420000,
+ .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 1,
+ .xUncertainty = 0.1,
+ .y = 2,
+ .yUncertainty = 0.1,
+ .z = 3,
+ .zUncertainty = 0.1},
+ .phaseCenterVariationCorrectionMillimeters =
+ {
+ Row{std::vector<double>{1, -1, 5, -2, 3, -1}},
+ Row{std::vector<double>{-2, 3, 2, 0, 1, 2}},
+ Row{std::vector<double>{1, 3, 2, -1, -3, 5}},
+ },
+ .phaseCenterVariationCorrectionUncertaintyMillimeters =
+ {
+ Row{std::vector<double>{0.1, 0.2, 0.4, 0.1, 0.2, 0.3}},
+ Row{std::vector<double>{0.3, 0.2, 0.3, 0.6, 0.1, 0.1}},
+ Row{std::vector<double>{0.1, 0.1, 0.4, 0.2, 0.5, 0.3}},
+ },
+ .signalGainCorrectionDbi =
+ {
+ Row{std::vector<double>{2, -3, 1, -3, 0, -4}},
+ Row{std::vector<double>{1, 0, -4, 1, 3, -2}},
+ Row{std::vector<double>{3, -2, 0, -2, 3, 0}},
+ },
+ .signalGainCorrectionUncertaintyDbi =
+ {
+ Row{std::vector<double>{0.3, 0.1, 0.2, 0.6, 0.1, 0.3}},
+ Row{std::vector<double>{0.1, 0.1, 0.5, 0.2, 0.3, 0.1}},
+ Row{std::vector<double>{0.2, 0.4, 0.2, 0.1, 0.1, 0.2}},
+ },
+ };
+
+ IGnssAntennaInfoCallback::GnssAntennaInfo mockAntennaInfo_2 = {
+ .carrierFrequencyHz = 1176450000,
+ .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5,
+ .xUncertainty = 0.1,
+ .y = 6,
+ .yUncertainty = 0.1,
+ .z = 7,
+ .zUncertainty = 0.1},
+ };
+
+ std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo> mockAntennaInfos = {
+ mockAntennaInfo_1,
+ mockAntennaInfo_2,
+ };
+ this->reportAntennaInfo(mockAntennaInfos);
+ }
+
+ /** For mock implementation this is good. On real device, we should only report
+ antennaInfo at start and when there is a configuration change. **/
+ std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
+ }
+ });
+}
+
+void GnssAntennaInfo::stop() {
+ ALOGD("stop");
+ mIsActive = false;
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void GnssAntennaInfo::reportAntennaInfo(
+ const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ if (sCallback == nullptr) {
+ ALOGE("%s: No non-null callback", __func__);
+ return;
+ }
+
+ auto ret = sCallback->gnssAntennaInfoCb(antennaInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssAntennaInfo.h b/gnss/aidl/default/GnssAntennaInfo.h
new file mode 100644
index 0000000..2cf7b13
--- /dev/null
+++ b/gnss/aidl/default/GnssAntennaInfo.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnGnssAntennaInfo.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+namespace aidl::android::hardware::gnss {
+
+struct GnssAntennaInfo : public BnGnssAntennaInfo {
+ public:
+ GnssAntennaInfo();
+ ~GnssAntennaInfo();
+ ndk::ScopedAStatus setCallback(
+ const std::shared_ptr<IGnssAntennaInfoCallback>& callback) override;
+ ndk::ScopedAStatus close() override;
+
+ private:
+ void start();
+ void stop();
+ void reportAntennaInfo(
+ const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const;
+
+ // Guarded by mMutex
+ static std::shared_ptr<IGnssAntennaInfoCallback> sCallback;
+
+ std::atomic<bool> mIsActive;
+ std::atomic<long> mMinIntervalMs;
+ std::thread mThread;
+
+ // Synchronization lock for sCallback
+ mutable std::mutex mMutex;
+};
+
+} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssBatching.cpp b/gnss/aidl/default/GnssBatching.cpp
index b8be5e5..33e1fd5 100644
--- a/gnss/aidl/default/GnssBatching.cpp
+++ b/gnss/aidl/default/GnssBatching.cpp
@@ -52,17 +52,19 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus GnssBatching::start(int64_t periodNanos, int flags) {
- ALOGD("start: periodNanos=%" PRId64 ", flags=%d", periodNanos, flags);
+ndk::ScopedAStatus GnssBatching::start(const Options& options) {
+ ALOGD("start: periodNanos=%" PRId64 ", minDistanceMeters=%f, flags=%d", options.periodNanos,
+ options.minDistanceMeters, options.flags);
if (mIsActive) {
ALOGW("Gnss has started. Restarting...");
stop();
}
- mWakeUpOnFifoFull = (flags & IGnssBatching::WAKEUP_ON_FIFO_FULL) ? true : false;
// mMinIntervalMs is not smaller than 1 sec
- periodNanos = (periodNanos < 1e9) ? 1e9 : periodNanos;
+ long periodNanos = (options.periodNanos < 1e9) ? 1e9 : options.periodNanos;
mMinIntervalMs = periodNanos / 1e6;
+ mWakeUpOnFifoFull = (options.flags & IGnssBatching::WAKEUP_ON_FIFO_FULL) ? true : false;
+ mMinDistanceMeters = options.minDistanceMeters;
mIsActive = true;
mThread = std::thread([this]() {
diff --git a/gnss/aidl/default/GnssBatching.h b/gnss/aidl/default/GnssBatching.h
index 7cd6e85..6d1d809 100644
--- a/gnss/aidl/default/GnssBatching.h
+++ b/gnss/aidl/default/GnssBatching.h
@@ -28,7 +28,7 @@
~GnssBatching();
ndk::ScopedAStatus init(const std::shared_ptr<IGnssBatchingCallback>& callback) override;
ndk::ScopedAStatus getBatchSize(int* size) override;
- ndk::ScopedAStatus start(int64_t periodNanos, int flags) override;
+ ndk::ScopedAStatus start(const Options& options) override;
ndk::ScopedAStatus flush() override;
ndk::ScopedAStatus stop() override;
ndk::ScopedAStatus cleanup() override;
@@ -42,6 +42,7 @@
std::thread mThread;
std::atomic<bool> mIsActive;
std::atomic<long> mMinIntervalMs;
+ std::atomic<float> mMinDistanceMeters;
std::atomic<bool> mWakeUpOnFifoFull;
// Synchronization lock for sCallback
diff --git a/gnss/aidl/default/MeasurementCorrectionsInterface.cpp b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
new file mode 100644
index 0000000..0f1851c
--- /dev/null
+++ b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "MeasurementCorrectionsInterface"
+
+#include "MeasurementCorrectionsInterface.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss::measurement_corrections {
+
+std::shared_ptr<IMeasurementCorrectionsCallback> MeasurementCorrectionsInterface::sCallback =
+ nullptr;
+
+ndk::ScopedAStatus MeasurementCorrectionsInterface::setCorrections(
+ const MeasurementCorrections& corrections) {
+ ALOGD("setCorrections");
+ ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
+ "satCorrections.size: %d",
+ corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters,
+ corrections.horizontalPositionUncertaintyMeters,
+ corrections.verticalPositionUncertaintyMeters,
+ static_cast<unsigned long long>(corrections.toaGpsNanosecondsOfWeek),
+ static_cast<int>(corrections.satCorrections.size()));
+ for (auto singleSatCorrection : corrections.satCorrections) {
+ ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d"
+ ", cfHz: %" PRId64 ", probLos: %f, epl: %f, eplUnc: %f",
+ singleSatCorrection.singleSatCorrectionFlags, singleSatCorrection.constellation,
+ singleSatCorrection.svid, singleSatCorrection.carrierFrequencyHz,
+ singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+ singleSatCorrection.excessPathLengthUncertaintyMeters);
+ ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+ singleSatCorrection.reflectingPlane.latitudeDegrees,
+ singleSatCorrection.reflectingPlane.longitudeDegrees,
+ singleSatCorrection.reflectingPlane.altitudeMeters,
+ singleSatCorrection.reflectingPlane.azimuthDegrees);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus MeasurementCorrectionsInterface::setCallback(
+ const std::shared_ptr<IMeasurementCorrectionsCallback>& callback) {
+ ALOGD("MeasurementCorrections::setCallback");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+ auto ret = sCallback->setCapabilitiesCb(
+ IMeasurementCorrectionsCallback::CAPABILITY_LOS_SATS |
+ IMeasurementCorrectionsCallback::CAPABILITY_EXCESS_PATH_LENGTH |
+ IMeasurementCorrectionsCallback::CAPABILITY_REFLECTING_PLANE);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+} // namespace aidl::android::hardware::gnss::measurement_corrections
diff --git a/gnss/aidl/default/MeasurementCorrectionsInterface.h b/gnss/aidl/default/MeasurementCorrectionsInterface.h
new file mode 100644
index 0000000..af58725
--- /dev/null
+++ b/gnss/aidl/default/MeasurementCorrectionsInterface.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <aidl/android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsInterface.h>
+
+namespace aidl::android::hardware::gnss::measurement_corrections {
+
+struct MeasurementCorrectionsInterface : public BnMeasurementCorrectionsInterface {
+ public:
+ ndk::ScopedAStatus setCorrections(const MeasurementCorrections& corrections) override;
+ ndk::ScopedAStatus setCallback(
+ const std::shared_ptr<IMeasurementCorrectionsCallback>& callback) override;
+
+ private:
+ // Synchronization lock for sCallback
+ mutable std::mutex mMutex;
+ // Guarded by mMutex
+ static std::shared_ptr<IMeasurementCorrectionsCallback> sCallback;
+};
+
+} // namespace aidl::android::hardware::gnss::measurement_corrections
diff --git a/gnss/aidl/vts/AGnssRilCallbackAidl.cpp b/gnss/aidl/vts/AGnssRilCallbackAidl.cpp
new file mode 100644
index 0000000..4e4166d
--- /dev/null
+++ b/gnss/aidl/vts/AGnssRilCallbackAidl.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include "AGnssRilCallbackAidl.h"
+#include <log/log.h>
+
+android::binder::Status AGnssRilCallbackAidl::requestSetIdCb(int setIdflag) {
+ ALOGI("requestSetIdCb setIdflag %d", setIdflag);
+ return android::binder::Status::ok();
+}
+
+android::binder::Status AGnssRilCallbackAidl::requestRefLocCb() {
+ ALOGI("requestRefLocCb");
+ return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/AGnssRilCallbackAidl.h b/gnss/aidl/vts/AGnssRilCallbackAidl.h
new file mode 100644
index 0000000..74b34ee
--- /dev/null
+++ b/gnss/aidl/vts/AGnssRilCallbackAidl.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnAGnssRilCallback.h>
+
+/** Implementation for IAGnssRilCallback. */
+class AGnssRilCallbackAidl : public android::hardware::gnss::BnAGnssRilCallback {
+ public:
+ AGnssRilCallbackAidl(){};
+ ~AGnssRilCallbackAidl(){};
+ android::binder::Status requestSetIdCb(int setIdflag) override;
+ android::binder::Status requestRefLocCb() override;
+};
diff --git a/gnss/aidl/vts/Android.bp b/gnss/aidl/vts/Android.bp
index d532fad..f02a41e 100644
--- a/gnss/aidl/vts/Android.bp
+++ b/gnss/aidl/vts/Android.bp
@@ -31,6 +31,8 @@
"gnss_hal_test.cpp",
"gnss_hal_test_cases.cpp",
"AGnssCallbackAidl.cpp",
+ "AGnssRilCallbackAidl.cpp",
+ "GnssAntennaInfoCallbackAidl.cpp",
"GnssBatchingCallback.cpp",
"GnssCallbackAidl.cpp",
"GnssGeofenceCallback.cpp",
@@ -38,6 +40,7 @@
"GnssNavigationMessageCallback.cpp",
"GnssPowerIndicationCallback.cpp",
"GnssVisibilityControlCallback.cpp",
+ "MeasurementCorrectionsCallback.cpp",
"VtsHalGnssTargetTest.cpp",
],
shared_libs: [
@@ -50,7 +53,6 @@
static_libs: [
"android.hardware.gnss-V2-cpp",
"android.hardware.gnss@common-vts-lib",
- "android.hardware.gnss.visibility_control-V1-cpp",
],
test_suites: [
"general-tests",
diff --git a/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.cpp b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.cpp
new file mode 100644
index 0000000..11001cd
--- /dev/null
+++ b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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 "GnssAntennaInfoCallbackAidl.h"
+#include <inttypes.h>
+#include <log/log.h>
+
+android::binder::Status GnssAntennaInfoCallbackAidl::gnssAntennaInfoCb(
+ const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
+ ALOGD("GnssAntennaInfo received. Size = %d", (int)gnssAntennaInfos.size());
+ antenna_info_cbq_.store(gnssAntennaInfos);
+ return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.h b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.h
new file mode 100644
index 0000000..77e1057
--- /dev/null
+++ b/gnss/aidl/vts/GnssAntennaInfoCallbackAidl.h
@@ -0,0 +1,36 @@
+/*
+ * 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/hardware/gnss/BnGnssAntennaInfoCallback.h>
+#include <vector>
+#include "GnssCallbackEventQueue.h"
+
+/** Implementation for IGnssAntennaInfoCallback. */
+class GnssAntennaInfoCallbackAidl : public android::hardware::gnss::BnGnssAntennaInfoCallback {
+ public:
+ GnssAntennaInfoCallbackAidl() : antenna_info_cbq_("info"){};
+ ~GnssAntennaInfoCallbackAidl(){};
+
+ android::binder::Status gnssAntennaInfoCb(
+ const std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos)
+ override;
+
+ android::hardware::gnss::common::GnssCallbackEventQueue<
+ std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo>>
+ antenna_info_cbq_;
+};
diff --git a/gnss/aidl/vts/MeasurementCorrectionsCallback.cpp b/gnss/aidl/vts/MeasurementCorrectionsCallback.cpp
new file mode 100644
index 0000000..db1f7a6
--- /dev/null
+++ b/gnss/aidl/vts/MeasurementCorrectionsCallback.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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 "MeasurementCorrectionsCallback"
+
+#include "MeasurementCorrectionsCallback.h"
+#include <log/log.h>
+
+android::binder::Status MeasurementCorrectionsCallback::setCapabilitiesCb(const int capabilities) {
+ ALOGI("Capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/MeasurementCorrectionsCallback.h b/gnss/aidl/vts/MeasurementCorrectionsCallback.h
new file mode 100644
index 0000000..27e5b3c
--- /dev/null
+++ b/gnss/aidl/vts/MeasurementCorrectionsCallback.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsCallback.h>
+#include "GnssCallbackEventQueue.h"
+
+class MeasurementCorrectionsCallback
+ : public android::hardware::gnss::measurement_corrections::BnMeasurementCorrectionsCallback {
+ public:
+ MeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
+ ~MeasurementCorrectionsCallback(){};
+ android::binder::Status setCapabilitiesCb(const int capabilities) override;
+
+ android::hardware::gnss::common::GnssCallbackEventQueue<int> capabilities_cbq_;
+ int last_capabilities_;
+};
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index eec50b0..1fa6825 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -18,21 +18,27 @@
#include <android/hardware/gnss/IAGnss.h>
#include <android/hardware/gnss/IGnss.h>
+#include <android/hardware/gnss/IGnssAntennaInfo.h>
#include <android/hardware/gnss/IGnssBatching.h>
#include <android/hardware/gnss/IGnssDebug.h>
#include <android/hardware/gnss/IGnssMeasurementCallback.h>
#include <android/hardware/gnss/IGnssMeasurementInterface.h>
#include <android/hardware/gnss/IGnssPowerIndication.h>
#include <android/hardware/gnss/IGnssPsds.h>
+#include <android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.h>
#include <android/hardware/gnss/visibility_control/IGnssVisibilityControl.h>
#include <cutils/properties.h>
#include "AGnssCallbackAidl.h"
+#include "AGnssRilCallbackAidl.h"
+#include "GnssAntennaInfoCallbackAidl.h"
#include "GnssBatchingCallback.h"
#include "GnssGeofenceCallback.h"
#include "GnssMeasurementCallbackAidl.h"
#include "GnssNavigationMessageCallback.h"
#include "GnssPowerIndicationCallback.h"
#include "GnssVisibilityControlCallback.h"
+#include "MeasurementCorrectionsCallback.h"
+#include "Utils.h"
#include "gnss_hal_test.h"
using android::sp;
@@ -43,7 +49,10 @@
using android::hardware::gnss::GnssMeasurement;
using android::hardware::gnss::GnssPowerStats;
using android::hardware::gnss::IAGnss;
+using android::hardware::gnss::IAGnssRil;
using android::hardware::gnss::IGnss;
+using android::hardware::gnss::IGnssAntennaInfo;
+using android::hardware::gnss::IGnssAntennaInfoCallback;
using android::hardware::gnss::IGnssBatching;
using android::hardware::gnss::IGnssBatchingCallback;
using android::hardware::gnss::IGnssCallback;
@@ -58,6 +67,8 @@
using android::hardware::gnss::IGnssPsds;
using android::hardware::gnss::PsdsType;
using android::hardware::gnss::SatellitePvt;
+using android::hardware::gnss::common::Utils;
+using android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface;
using android::hardware::gnss::visibility_control::IGnssVisibilityControl;
using GnssConstellationTypeV2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
@@ -802,6 +813,10 @@
* TestAllExtensions.
*/
TEST_P(GnssHalTest, TestAllExtensions) {
+ if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+ return;
+ }
+
sp<IGnssBatching> iGnssBatching;
auto status = aidl_gnss_hal_->getExtensionGnssBatching(&iGnssBatching);
if (status.isOk() && iGnssBatching != nullptr) {
@@ -858,6 +873,42 @@
}
/*
+ * TestAGnssRilExtension:
+ * 1. Gets the IAGnssRil extension.
+ * 2. Sets AGnssRilCallback.
+ * 3. Sets reference location.
+ */
+TEST_P(GnssHalTest, TestAGnssRilExtension) {
+ if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+ return;
+ }
+ sp<IAGnssRil> iAGnssRil;
+ auto status = aidl_gnss_hal_->getExtensionAGnssRil(&iAGnssRil);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iAGnssRil != nullptr);
+
+ auto agnssRilCallback = sp<AGnssRilCallbackAidl>::make();
+ status = iAGnssRil->setCallback(agnssRilCallback);
+ ASSERT_TRUE(status.isOk());
+
+ // Set RefLocation
+ IAGnssRil::AGnssRefLocationCellID agnssReflocationCellId;
+ agnssReflocationCellId.type = IAGnssRil::AGnssRefLocationType::LTE_CELLID;
+ agnssReflocationCellId.mcc = 466;
+ agnssReflocationCellId.mnc = 97;
+ agnssReflocationCellId.lac = 46697;
+ agnssReflocationCellId.cid = 59168142;
+ agnssReflocationCellId.pcid = 420;
+ agnssReflocationCellId.tac = 11460;
+ IAGnssRil::AGnssRefLocation agnssReflocation;
+ agnssReflocation.type = IAGnssRil::AGnssRefLocationType::LTE_CELLID;
+ agnssReflocation.cellID = agnssReflocationCellId;
+
+ status = iAGnssRil->setRefLocation(agnssReflocation);
+ ASSERT_TRUE(status.isOk());
+}
+
+/*
* GnssDebugValuesSanityTest:
* Ensures that GnssDebug values make sense.
*/
@@ -905,7 +956,6 @@
}
/*
- * TestAGnssExtension:
* TestGnssVisibilityControlExtension:
* 1. Gets the IGnssVisibilityControl extension.
* 2. Sets GnssVisibilityControlCallback
@@ -923,7 +973,8 @@
status = iGnssVisibilityControl->setCallback(gnssVisibilityControlCallback);
ASSERT_TRUE(status.isOk());
- std::vector<String16> proxyApps{String16("com.example.ims"), String16("com.example.mdt")};
+ std::vector<std::string> proxyApps{std::string("com.example.ims"),
+ std::string("com.example.mdt")};
status = iGnssVisibilityControl->enableNfwLocationAccess(proxyApps);
ASSERT_TRUE(status.isOk());
}
@@ -1009,3 +1060,124 @@
status = iGnssMeasurement->close();
ASSERT_TRUE(status.isOk());
}
+
+/*
+ * TestGnssAntennaInfo:
+ * Sets a GnssAntennaInfoCallback, waits for report, and verifies
+ * 1. phaseCenterOffsetCoordinateMillimeters is valid
+ * 2. phaseCenterOffsetCoordinateUncertaintyMillimeters is valid.
+ * PhaseCenterVariationCorrections and SignalGainCorrections are optional.
+ */
+TEST_P(GnssHalTest, TestGnssAntennaInfo) {
+ const int kAntennaInfoTimeoutSeconds = 2;
+
+ if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+ return;
+ }
+
+ sp<IGnssAntennaInfo> iGnssAntennaInfo;
+ auto status = aidl_gnss_hal_->getExtensionGnssAntennaInfo(&iGnssAntennaInfo);
+ ASSERT_TRUE(status.isOk());
+
+ if (!(aidl_gnss_cb_->last_capabilities_ & (int)GnssCallbackAidl::CAPABILITY_ANTENNA_INFO) ||
+ iGnssAntennaInfo == nullptr) {
+ ALOGD("GnssAntennaInfo AIDL is not supported.");
+ return;
+ }
+
+ auto callback = sp<GnssAntennaInfoCallbackAidl>::make();
+ status = iGnssAntennaInfo->setCallback(callback);
+ ASSERT_TRUE(status.isOk());
+
+ std::vector<IGnssAntennaInfoCallback::GnssAntennaInfo> antennaInfos;
+ ASSERT_TRUE(callback->antenna_info_cbq_.retrieve(antennaInfos, kAntennaInfoTimeoutSeconds));
+ EXPECT_EQ(callback->antenna_info_cbq_.calledCount(), 1);
+ ASSERT_TRUE(antennaInfos.size() > 0);
+
+ for (auto antennaInfo : antennaInfos) {
+ // Remaining fields are optional
+ if (!antennaInfo.phaseCenterVariationCorrectionMillimeters.empty()) {
+ int numRows = antennaInfo.phaseCenterVariationCorrectionMillimeters.size();
+ int numColumns = antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size();
+ // Must have at least 1 row and 2 columns
+ ASSERT_TRUE(numRows >= 1 && numColumns >= 2);
+
+ // Corrections and uncertainties must have same dimensions
+ ASSERT_TRUE(antennaInfo.phaseCenterVariationCorrectionMillimeters.size() ==
+ antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.size());
+ ASSERT_TRUE(
+ antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size() ==
+ antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters[0].row.size());
+
+ // Must be rectangular
+ for (auto row : antennaInfo.phaseCenterVariationCorrectionMillimeters) {
+ ASSERT_TRUE(row.row.size() == numColumns);
+ }
+ for (auto row : antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters) {
+ ASSERT_TRUE(row.row.size() == numColumns);
+ }
+ }
+ if (!antennaInfo.signalGainCorrectionDbi.empty()) {
+ int numRows = antennaInfo.signalGainCorrectionDbi.size();
+ int numColumns = antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size();
+ // Must have at least 1 row and 2 columns
+ ASSERT_TRUE(numRows >= 1 && numColumns >= 2);
+
+ // Corrections and uncertainties must have same dimensions
+ ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi.size() ==
+ antennaInfo.signalGainCorrectionUncertaintyDbi.size());
+ ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi[0].row.size() ==
+ antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size());
+
+ // Must be rectangular
+ for (auto row : antennaInfo.signalGainCorrectionDbi) {
+ ASSERT_TRUE(row.row.size() == numColumns);
+ }
+ for (auto row : antennaInfo.signalGainCorrectionUncertaintyDbi) {
+ ASSERT_TRUE(row.row.size() == numColumns);
+ }
+ }
+ }
+
+ iGnssAntennaInfo->close();
+}
+
+/*
+ * TestGnssMeasurementCorrections:
+ * If measurement corrections capability is supported, verifies that the measurement corrections
+ * capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH
+ * capability flag is set.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
+ if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+ return;
+ }
+ if (!(aidl_gnss_cb_->last_capabilities_ &
+ (int)GnssCallbackAidl::CAPABILITY_MEASUREMENT_CORRECTIONS)) {
+ return;
+ }
+
+ sp<IMeasurementCorrectionsInterface> iMeasurementCorrectionsAidl;
+ auto status = aidl_gnss_hal_->getExtensionMeasurementCorrections(&iMeasurementCorrectionsAidl);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iMeasurementCorrectionsAidl != nullptr);
+
+ // Setup measurement corrections callback.
+ auto gnssMeasurementCorrectionsCallback = sp<MeasurementCorrectionsCallback>::make();
+ status = iMeasurementCorrectionsAidl->setCallback(gnssMeasurementCorrectionsCallback);
+ ASSERT_TRUE(status.isOk());
+
+ const int kTimeoutSec = 5;
+ EXPECT_TRUE(gnssMeasurementCorrectionsCallback->capabilities_cbq_.retrieve(
+ gnssMeasurementCorrectionsCallback->last_capabilities_, kTimeoutSec));
+ ASSERT_TRUE(gnssMeasurementCorrectionsCallback->capabilities_cbq_.calledCount() > 0);
+
+ ASSERT_TRUE((gnssMeasurementCorrectionsCallback->last_capabilities_ &
+ (MeasurementCorrectionsCallback::CAPABILITY_LOS_SATS |
+ MeasurementCorrectionsCallback::CAPABILITY_EXCESS_PATH_LENGTH)) != 0);
+
+ // Set a mock MeasurementCorrections.
+ status = iMeasurementCorrectionsAidl->setCorrections(
+ Utils::getMockMeasurementCorrections_aidl());
+ ASSERT_TRUE(status.isOk());
+}
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 06bce9d..da4c07f 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -15,6 +15,7 @@
*/
#include <Utils.h>
+#include <android/hardware/gnss/BnGnss.h>
#include <android/hardware/gnss/IGnss.h>
#include "gtest/gtest.h"
@@ -28,6 +29,12 @@
using namespace measurement_corrections::V1_0;
using V1_0::GnssLocationFlags;
+using MeasurementCorrectionsAidl =
+ android::hardware::gnss::measurement_corrections::MeasurementCorrections;
+using ReflectingPlaneAidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using SingleSatCorrectionAidl =
+ android::hardware::gnss::measurement_corrections::SingleSatCorrection;
+
template <>
int64_t Utils::getLocationTimestampMillis(const android::hardware::gnss::GnssLocation& location) {
return location.timestampMillis;
@@ -63,6 +70,7 @@
.singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY |
GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH |
GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC,
+
.constellation = V1_0::GnssConstellationType::GPS,
.svid = 9,
.carrierFrequencyHz = 1.59975e+09,
@@ -114,6 +122,56 @@
return mockCorrections_1_1;
}
+const MeasurementCorrectionsAidl Utils::getMockMeasurementCorrections_aidl() {
+ ReflectingPlaneAidl reflectingPlane;
+ reflectingPlane.latitudeDegrees = 37.4220039;
+ reflectingPlane.longitudeDegrees = -122.0840991;
+ reflectingPlane.altitudeMeters = 250.35;
+ reflectingPlane.azimuthDegrees = 203.0;
+
+ SingleSatCorrectionAidl singleSatCorrection1;
+ singleSatCorrection1.singleSatCorrectionFlags =
+ SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
+ SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
+ SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC |
+ SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE;
+ singleSatCorrection1.constellation = android::hardware::gnss::GnssConstellationType::GPS;
+ singleSatCorrection1.svid = 12;
+ singleSatCorrection1.carrierFrequencyHz = 1.59975e+09;
+ singleSatCorrection1.probSatIsLos = 0.50001;
+ singleSatCorrection1.excessPathLengthMeters = 137.4802;
+ singleSatCorrection1.excessPathLengthUncertaintyMeters = 25.5;
+ singleSatCorrection1.reflectingPlane = reflectingPlane;
+
+ SingleSatCorrectionAidl singleSatCorrection2;
+ singleSatCorrection2.singleSatCorrectionFlags =
+ SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
+ SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
+ SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC;
+ singleSatCorrection2.constellation = GnssConstellationType::GPS;
+ singleSatCorrection2.svid = 9;
+ singleSatCorrection2.carrierFrequencyHz = 1.59975e+09;
+ singleSatCorrection2.probSatIsLos = 0.873;
+ singleSatCorrection2.excessPathLengthMeters = 26.294;
+ singleSatCorrection2.excessPathLengthUncertaintyMeters = 10.0;
+
+ std::vector<SingleSatCorrectionAidl> singleSatCorrections = {singleSatCorrection1,
+ singleSatCorrection2};
+ MeasurementCorrectionsAidl mockCorrections;
+ mockCorrections.latitudeDegrees = 37.4219999;
+ mockCorrections.longitudeDegrees = -122.0840575;
+ mockCorrections.altitudeMeters = 30.60062531;
+ mockCorrections.horizontalPositionUncertaintyMeters = 9.23542;
+ mockCorrections.verticalPositionUncertaintyMeters = 15.02341;
+ mockCorrections.toaGpsNanosecondsOfWeek = 2935633453L;
+ mockCorrections.hasEnvironmentBearing = true;
+ mockCorrections.environmentBearingDegrees = 45.0;
+ mockCorrections.environmentBearingUncertaintyDegrees = 4.0;
+ mockCorrections.satCorrections = singleSatCorrections;
+
+ return mockCorrections;
+}
+
/*
* MapConstellationType:
* Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index 40f31d2..4ea6cd6 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -21,6 +21,8 @@
#include <android/hardware/gnss/2.0/IGnss.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsInterface.h>
+
#include <gtest/gtest.h>
namespace android {
@@ -36,6 +38,8 @@
getMockMeasurementCorrections();
static const measurement_corrections::V1_1::MeasurementCorrections
getMockMeasurementCorrections_1_1();
+ static const android::hardware::gnss::measurement_corrections::MeasurementCorrections
+ getMockMeasurementCorrections_aidl();
static V1_0::GnssConstellationType mapConstellationType(
V2_0::GnssConstellationType constellation);
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
new file mode 100644
index 0000000..ea8a599
--- /dev/null
+++ b/graphics/allocator/aidl/Android.bp
@@ -0,0 +1,40 @@
+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"],
+}
+
+aidl_interface {
+ name: "android.hardware.graphics.allocator",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: ["android/hardware/graphics/allocator/*.aidl"],
+ imports: [
+ "android.hardware.common-V2",
+ ],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ enabled: false,
+ },
+ ndk: {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+ vndk: {
+ enabled: true,
+ },
+ min_sdk_version: "29",
+ },
+ },
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationError.aidl
similarity index 83%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationError.aidl
index 7ef08d2..6e7b739 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationError.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.graphics.allocator;
+@Backing(type="int") @VintfStability
+enum AllocationError {
+ BAD_DESCRIPTOR = 0,
+ NO_RESOURCES = 1,
+ UNSUPPORTED = 2,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationResult.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationResult.aidl
index 7ef08d2..73cfeb5 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/AllocationResult.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.graphics.allocator;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable AllocationResult {
+ int stride;
+ android.hardware.common.NativeHandle[] buffers;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
index 7ef08d2..fe0b0a2 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -31,9 +31,8 @@
// 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.gnss.visibility_control;
+package android.hardware.graphics.allocator;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IAllocator {
+ android.hardware.graphics.allocator.AllocationResult allocate(in byte[] descriptor, in int count);
}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationError.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationError.aidl
new file mode 100644
index 0000000..c6b77b9
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationError.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.graphics.allocator;
+
+@VintfStability
+@Backing(type="int")
+enum AllocationError {
+ /**
+ * Invalid BufferDescriptor.
+ */
+ BAD_DESCRIPTOR,
+
+ /**
+ * Resource unavailable.
+ */
+ NO_RESOURCES,
+
+ /**
+ * Permanent failure.
+ */
+ UNSUPPORTED
+}
\ No newline at end of file
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
new file mode 100644
index 0000000..0774e25
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.graphics.allocator;
+
+import android.hardware.common.NativeHandle;
+
+ /**
+ * Result of an IAllocator::allocate call.
+ *
+ * @sa +ndk libnativewindow#AHardwareBuffer_Desc
+ */
+@VintfStability
+parcelable AllocationResult {
+ int stride;
+ NativeHandle[] buffers;
+}
\ No newline at end of file
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
new file mode 100644
index 0000000..8c3ca96
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.graphics.allocator;
+
+import android.hardware.graphics.allocator.AllocationResult;
+
+@VintfStability
+interface IAllocator {
+ /**
+ * Allocates buffers with the properties specified by the descriptor.
+ *
+ * Allocations should be optimized for usage bits provided in the
+ * descriptor.
+ *
+ * @param descriptor Properties of the buffers to allocate. This must be
+ * obtained from IMapper::createDescriptor().
+ * @param count The number of buffers to allocate.
+ * @return An AllocationResult containing the result of an error, or
+ * an AllocationError status
+ */
+ AllocationResult allocate(in byte[] descriptor, in int count);
+}
diff --git a/graphics/common/OWNERS b/graphics/common/OWNERS
new file mode 100644
index 0000000..94999ea
--- /dev/null
+++ b/graphics/common/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1075130
+adyabr@google.com
+alecmouri@google.com
+jreck@google.com
+scroggo@google.com
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
index b4ef451..e1edb17 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
@@ -54,10 +54,11 @@
RENDERSCRIPT = 1048576,
VIDEO_DECODER = 4194304,
SENSOR_DIRECT_DATA = 8388608,
+ GPU_DATA_BUFFER = 16777216,
GPU_CUBE_MAP = 33554432,
GPU_MIPMAP_COMPLETE = 67108864,
HW_IMAGE_ENCODER = 134217728,
- GPU_DATA_BUFFER = 16777216,
+ FRONT_BUFFER = 4294967296,
VENDOR_MASK = -268435456,
VENDOR_MASK_HI = -281474976710656,
}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
index 5c3d4cb..359c655 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
@@ -34,6 +34,7 @@
package android.hardware.graphics.common;
@Backing(type="int") @VintfStability
enum Transform {
+ NONE = 0,
FLIP_H = 1,
FLIP_V = 2,
ROT_90 = 4,
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
index d978f46..4b5a306 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
@@ -87,6 +87,12 @@
/** buffer is used as a sensor direct report output */
SENSOR_DIRECT_DATA = 1 << 23,
+ /**
+ * buffer is used as as an OpenGL shader storage or uniform
+ * buffer object
+ */
+ GPU_DATA_BUFFER = 1 << 24,
+
/** buffer is used as a cube map texture */
GPU_CUBE_MAP = 1 << 25,
@@ -98,17 +104,17 @@
*/
HW_IMAGE_ENCODER = 1 << 27,
- /**
- * buffer is used as as an OpenGL shader storage or uniform
- * buffer object
- */
- GPU_DATA_BUFFER = 1 << 24,
+ /* Bits 28-31 are reserved for vendor usage */
- /** bits 25-27 must be zero and are reserved for future versions */
+ /**
+ * Buffer is used for front-buffer rendering
+ */
+ FRONT_BUFFER = 1L << 32,
+
/** bits 28-31 are reserved for vendor extensions */
VENDOR_MASK = 0xf << 28,
- /** bits 32-47 must be zero and are reserved for future versions */
+ /** bits 33-47 must be zero and are reserved for future versions */
/** bits 48-63 are reserved for vendor extensions */
VENDOR_MASK_HI = (1L * 0xffff) << 48,
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 7719d6e..74a9ce3 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -22,8 +22,9 @@
* This is an enum that defines the common types of gralloc 4 buffer metadata. The comments for
* each enum include a description of the metadata that is associated with the type.
*
- * IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may
- * support setting these standard buffer metadata types as well.
+ * IMapper@4.x must support getting the following standard buffer metadata types, with the exception
+ * of SMPTE 2094-10 metadata. IMapper@4.x may support setting these standard buffer metadata types
+ * as well.
*
* When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is
* is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl b/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
index 325816c..4b3a1b1 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
@@ -23,6 +23,11 @@
@Backing(type="int")
enum Transform {
/**
+ * Identity transform (i.e. no rotation or flip).
+ */
+ NONE = 0,
+
+ /**
* Horizontal flip. FLIP_H/FLIP_V is applied before ROT_90.
*/
FLIP_H = 1 << 0,
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index b071f71..fa294ff 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -161,7 +161,8 @@
return mGralloc->allocate(
width, height, /*layerCount*/ 1,
static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN));
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY));
}
struct TestParameters {
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index a8239cd..5593c57 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -51,6 +51,7 @@
int getDisplayVsyncPeriod(long display);
android.hardware.graphics.composer3.DisplayContentSample getDisplayedContentSample(long display, long maxFrames, long timestamp);
android.hardware.graphics.composer3.DisplayContentSamplingAttributes getDisplayedContentSamplingAttributes(long display);
+ android.hardware.graphics.common.Transform getDisplayPhysicalOrientation(long display);
android.hardware.graphics.composer3.HdrCapabilities getHdrCapabilities(long display);
int getMaxVirtualDisplayCount();
android.hardware.graphics.composer3.PerFrameMetadataKey[] getPerFrameMetadataKeys(long display);
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 9a29e7e..c86b9bd 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -16,6 +16,7 @@
package android.hardware.graphics.composer3;
+import android.hardware.graphics.common.Transform;
import android.hardware.graphics.composer3.ClientTargetProperty;
import android.hardware.graphics.composer3.ColorMode;
import android.hardware.graphics.composer3.CommandResultPayload;
@@ -354,6 +355,23 @@
DisplayContentSamplingAttributes getDisplayedContentSamplingAttributes(long display);
/**
+ * Queries the physical orientation of a display. Orientation 'Transform::NONE'
+ * represents a display that doesn't require any transformation on layers
+ * to be presented at their natural orientation.
+ *
+ * @param display is the display where the physical orientation is queried.
+ *
+ * @return is one of the below values:
+ * Transform::NONE
+ * Transform::ROT_90
+ * Transform::ROT_180
+ * Transform::ROT_270
+ *
+ * @exception EX_BAD_DISPLAY when an invalid display was passed in.
+ */
+ Transform getDisplayPhysicalOrientation(long display);
+
+ /**
* Returns the high dynamic range (HDR) capabilities of the given display,
* which are invariant with regard to the active configuration.
*
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
index 741572d..bd2c3b1 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
@@ -50,6 +50,7 @@
"libgui",
"libhidlbase",
"libprocessgroup",
+ "libtinyxml2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
index e519221..3f1e703 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -24,10 +24,18 @@
#include <composer-vts/include/ReadbackVts.h>
#include <composer-vts/include/RenderEngineVts.h>
#include <gtest/gtest.h>
+#include <ui/DisplayId.h>
+#include <ui/DisplayIdentification.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
+
+// tinyxml2 does implicit conversions >:(
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include <tinyxml2.h>
+#pragma clang diagnostic pop
#include "composer-vts/include/GraphicsComposerCallback.h"
namespace aidl::android::hardware::graphics::composer3::vts {
@@ -124,6 +132,76 @@
/*layerCount*/ 1u, usage, "VtsHalGraphicsComposer3_ReadbackTest");
}
+ uint64_t getStableDisplayId(int64_t display) {
+ DisplayIdentification identification;
+ const auto error = mComposerClient->getDisplayIdentificationData(display, &identification);
+ EXPECT_TRUE(error.isOk());
+
+ if (const auto info = ::android::parseDisplayIdentificationData(
+ static_cast<uint8_t>(identification.port), identification.data)) {
+ return info->id.value;
+ }
+
+ return ::android::PhysicalDisplayId::fromPort(static_cast<uint8_t>(identification.port))
+ .value;
+ }
+
+ // Gets the per-display XML config
+ std::unique_ptr<tinyxml2::XMLDocument> getDisplayConfigXml(int64_t display) {
+ std::stringstream pathBuilder;
+ pathBuilder << "/vendor/etc/displayconfig/display_id_" << getStableDisplayId(display)
+ << ".xml";
+ const std::string path = pathBuilder.str();
+ auto document = std::make_unique<tinyxml2::XMLDocument>();
+ const tinyxml2::XMLError error = document->LoadFile(path.c_str());
+ if (error == tinyxml2::XML_SUCCESS) {
+ return document;
+ } else {
+ return nullptr;
+ }
+ }
+
+ // Gets the max display brightness for this display.
+ // If the display config xml does not exist, then assume that the display is not well-configured
+ // enough to provide a display brightness, so return nullopt.
+ std::optional<float> getMaxDisplayBrightnessNits(int64_t display) {
+ const auto document = getDisplayConfigXml(display);
+ if (!document) {
+ // Assume the device doesn't support display brightness
+ return std::nullopt;
+ }
+
+ const auto root = document->RootElement();
+ if (!root) {
+ // If there's somehow no root element, then this isn't a valid config
+ return std::nullopt;
+ }
+
+ const auto screenBrightnessMap = root->FirstChildElement("screenBrightnessMap");
+ if (!screenBrightnessMap) {
+ // A valid display config must have a screen brightness map
+ return std::nullopt;
+ }
+
+ auto point = screenBrightnessMap->FirstChildElement("point");
+ float maxNits = -1.f;
+ while (point != nullptr) {
+ const auto nits = point->FirstChildElement("nits");
+ if (nits) {
+ maxNits = std::max(maxNits, nits->FloatText(-1.f));
+ }
+ point = point->NextSiblingElement("point");
+ }
+
+ if (maxNits < 0.f) {
+ // If we got here, then there were no point elements containing a nit value, so this
+ // config isn't valid
+ return std::nullopt;
+ }
+
+ return maxNits;
+ }
+
void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
for (auto layer : layers) {
layer->write(mWriter);
@@ -250,8 +328,8 @@
std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -286,8 +364,8 @@
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
@@ -363,8 +441,8 @@
std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
@@ -389,8 +467,8 @@
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth, mDisplayHeight,
+ mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
}
@@ -419,8 +497,13 @@
return;
}
- aidl::android::hardware::common::NativeHandle bufferHandle =
- ::android::dupToAidl(mGraphicBuffer->handle);
+ aidl::android::hardware::common::NativeHandle bufferHandle;
+ {
+ ::android::sp<::android::GraphicBuffer> buffer = allocate();
+ ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+ ::android::makeToAidl(mGraphicBuffer->handle);
+ }
+
ndk::ScopedFileDescriptor releaseFence = ndk::ScopedFileDescriptor(-1);
const auto error =
mComposerClient->setReadbackBuffer(mPrimaryDisplay, bufferHandle, releaseFence);
@@ -438,8 +521,9 @@
ndk::ScopedFileDescriptor releaseFence;
const auto error = mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &releaseFence);
- EXPECT_TRUE(error.isOk());
+ ASSERT_FALSE(error.isOk());
EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+ EXPECT_EQ(-1, releaseFence.get());
}
TEST_P(GraphicsCompositionTest, ClientComposition) {
@@ -474,8 +558,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -553,8 +637,8 @@
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
{0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto deviceLayer = std::make_shared<TestBufferLayer>(
@@ -657,8 +741,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -720,8 +804,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -781,8 +865,8 @@
// update expected colors to match crop
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
{0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -834,8 +918,8 @@
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -876,6 +960,90 @@
}
}
+TEST_P(GraphicsCompositionTest, SetLayerWhitePointDims) {
+ std::vector<DisplayCapability> capabilities;
+ const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
+ ASSERT_TRUE(error.isOk());
+
+ const bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
+ DisplayCapability::BRIGHTNESS) != capabilities.end();
+
+ if (!brightnessSupport) {
+ GTEST_SUCCEED() << "Cannot verify dimming behavior without brightness support";
+ return;
+ }
+
+ const std::optional<float> maxBrightnessNitsOptional =
+ getMaxDisplayBrightnessNits(mPrimaryDisplay);
+
+ ASSERT_TRUE(maxBrightnessNitsOptional.has_value());
+
+ const float maxBrightnessNits = *maxBrightnessNitsOptional;
+
+ // Preconditions to successfully run are knowing the max brightness and successfully applying
+ // the max brightness
+ ASSERT_GT(maxBrightnessNits, 0.f);
+ mWriter.setDisplayBrightness(mPrimaryDisplay, 1.f);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ for (ColorMode mode : mTestColorModes) {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ if (!getHasReadbackBuffer()) {
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace for "
+ "color mode: "
+ << toString(mode);
+ continue;
+ }
+ const common::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
+ const common::Rect dimmerRedRect = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+ const auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ redLayer->setColor(RED);
+ redLayer->setDisplayFrame(redRect);
+ redLayer->setWhitePointNits(maxBrightnessNits);
+
+ const auto dimmerRedLayer =
+ std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ dimmerRedLayer->setColor(RED);
+ dimmerRedLayer->setDisplayFrame(dimmerRedRect);
+ // Intentionally use a small dimming ratio as some implementations may be more likely to
+ // kick into GPU composition to apply dithering when the dimming ratio is high.
+ static constexpr float kDimmingRatio = 0.9f;
+ dimmerRedLayer->setWhitePointNits(maxBrightnessNits * kDimmingRatio);
+
+ const std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer};
+ std::vector<Color> expectedColors(static_cast<size_t>(mDisplayWidth * mDisplayHeight));
+
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, dimmerRedRect, DIM_RED);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
+ execute();
+ if (!mReader.takeChangedCompositionTypes(mPrimaryDisplay).empty()) {
+ GTEST_SUCCEED()
+ << "Readback verification not supported for GPU composition for color mode: "
+ << toString(mode);
+ continue;
+ }
+ mWriter.presentDisplay(mPrimaryDisplay);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(layers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+ }
+}
+
class GraphicsBlendModeCompositionTest
: public GraphicsCompositionTestBase,
public testing::WithParamInterface<std::tuple<std::string, std::string>> {
@@ -973,8 +1141,8 @@
setUpLayers(BlendMode::NONE);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1014,8 +1182,8 @@
setUpLayers(BlendMode::COVERAGE);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1050,8 +1218,8 @@
setUpLayers(BlendMode::PREMULTIPLIED);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1120,8 +1288,8 @@
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_H);
mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -1161,8 +1329,8 @@
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_V);
@@ -1202,8 +1370,8 @@
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer,
- mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::ROT_180);
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
index b5ad05f..0a12f1a 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -76,7 +76,10 @@
ASSERT_NE(binder, nullptr);
ASSERT_NO_FATAL_FAILURE(mComposer = IComposer::fromBinder(binder));
ASSERT_NE(mComposer, nullptr);
- ASSERT_NO_FATAL_FAILURE(mComposer->createClient(&mComposerClient));
+
+ ndk::ScopedAStatus status;
+ ASSERT_NO_FATAL_FAILURE(status = mComposer->createClient(&mComposerClient));
+ ASSERT_TRUE(status.isOk());
mComposerCallback = ::ndk::SharedRefBase::make<GraphicsComposerCallback>();
EXPECT_TRUE(mComposerClient->registerCallback(mComposerCallback).isOk());
@@ -188,6 +191,14 @@
resourceIt->second.layers.erase(layer);
}
+ bool hasCapability(Capability capability) {
+ std::vector<Capability> capabilities;
+ EXPECT_TRUE(mComposer->getCapabilities(&capabilities).isOk());
+ return std::any_of(
+ capabilities.begin(), capabilities.end(),
+ [&](const Capability& activeCapability) { return activeCapability == capability; });
+ }
+
// returns an invalid display id (one that has not been registered to a
// display. Currently assuming that a device will never have close to
// std::numeric_limit<uint64_t>::max() displays registered while running tests
@@ -959,6 +970,33 @@
EXPECT_TRUE(mComposerClient->getDisplayName(mPrimaryDisplay, &displayName).isOk());
}
+TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientationBadDisplay) {
+ Transform displayOrientation;
+ const auto error =
+ mComposerClient->getDisplayPhysicalOrientation(mInvalidDisplayId, &displayOrientation);
+
+ EXPECT_FALSE(error.isOk());
+ ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientation) {
+ const auto allowedDisplayOrientations = std::array<Transform, 4>{
+ Transform::NONE,
+ Transform::ROT_90,
+ Transform::ROT_180,
+ Transform::ROT_270,
+ };
+
+ Transform displayOrientation;
+ const auto error =
+ mComposerClient->getDisplayPhysicalOrientation(mPrimaryDisplay, &displayOrientation);
+
+ EXPECT_TRUE(error.isOk());
+ EXPECT_NE(std::find(allowedDisplayOrientations.begin(), allowedDisplayOrientations.end(),
+ displayOrientation),
+ allowedDisplayOrientations.end());
+}
+
TEST_P(GraphicsComposerAidlTest, SetClientTargetSlotCount) {
EXPECT_TRUE(
mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount).isOk());
@@ -1447,6 +1485,11 @@
}
void Test_expectedPresentTime(std::optional<int> framesDelay) {
+ if (hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
+ GTEST_SUCCEED() << "Device has unreliable present fences capability, skipping";
+ return;
+ }
+
ASSERT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk());
const auto vsyncPeriod = getVsyncPeriod();
@@ -1511,7 +1554,7 @@
execute();
const auto errors = mReader.takeErrors();
- if (errors.size() == 1 && errors[0].errorCode == EX_UNSUPPORTED_OPERATION) {
+ if (errors.size() == 1 && errors[0].errorCode == IComposerClient::EX_UNSUPPORTED) {
GTEST_SUCCEED() << "setLayerColorTransform is not supported";
return;
}
@@ -1528,7 +1571,7 @@
execute();
const auto errors = mReader.takeErrors();
EXPECT_EQ(1, errors.size());
- EXPECT_EQ(EX_UNSUPPORTED_OPERATION, errors[0].errorCode);
+ EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errors[0].errorCode);
GTEST_SUCCEED() << "SetDisplayBrightness is not supported";
return;
}
@@ -1623,10 +1666,7 @@
*/
// TODO(b/208441745) fix the test failure
TEST_P(GraphicsComposerAidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
- std::vector<Capability> capabilities;
- EXPECT_TRUE(mComposer->getCapabilities(&capabilities).isOk());
- if (none_of(capabilities.begin(), capabilities.end(),
- [&](auto item) { return item == Capability::SKIP_VALIDATE; })) {
+ if (!hasCapability(Capability::SKIP_VALIDATE)) {
GTEST_SUCCEED() << "Device does not have skip validate capability, skipping";
return;
}
@@ -1854,10 +1894,7 @@
}
TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
- std::vector<Capability> capabilities;
- EXPECT_TRUE(mComposer->getCapabilities(&capabilities).isOk());
- if (none_of(capabilities.begin(), capabilities.end(),
- [&](auto& item) { return item == Capability::SIDEBAND_STREAM; })) {
+ if (!hasCapability(Capability::SIDEBAND_STREAM)) {
GTEST_SUCCEED() << "no sideband stream support";
return;
}
@@ -1997,6 +2034,27 @@
EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk());
}
+TEST_P(GraphicsComposerAidlCommandTest, setLayerWhitePointNits) {
+ int64_t layer;
+ EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk());
+
+ mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, 200.f);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, 1000.f);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, 0.f);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ mWriter.setLayerWhitePointNits(mPrimaryDisplay, layer, -1.f);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints) {
Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = false});
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
index ee597a1..587c523 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
@@ -41,6 +41,7 @@
writer.setLayerTransform(mDisplay, mLayer, mTransform);
writer.setLayerPlaneAlpha(mDisplay, mLayer, mAlpha);
writer.setLayerBlendMode(mDisplay, mLayer, mBlendMode);
+ writer.setLayerWhitePointNits(mDisplay, mLayer, mWhitePointNits);
}
std::string ReadbackHelper::getColorModeString(ColorMode mode) {
@@ -103,6 +104,7 @@
1.0f, 1.0f));
layerSettings.geometry.positionTransform = scale * translation;
+ layerSettings.whitePointNits = mWhitePointNits;
return layerSettings;
}
@@ -175,18 +177,17 @@
return true;
}
-void ReadbackHelper::compareColorBuffers(std::vector<Color>& expectedColors, void* bufferData,
- const int32_t stride, const uint32_t width,
+void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
+ const uint32_t stride, const uint32_t width,
const uint32_t height, common::PixelFormat pixelFormat) {
const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
ASSERT_NE(-1, bytesPerPixel);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
auto pixel = row * static_cast<int32_t>(width) + col;
- int offset = (row * stride + col) * bytesPerPixel;
+ int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
uint8_t* pixelColor = (uint8_t*)bufferData + offset;
const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
-
ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
@@ -195,13 +196,11 @@
}
ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr<IComposerClient>& client,
- const ::android::sp<::android::GraphicBuffer>& graphicBuffer,
int32_t width, int32_t height, common::PixelFormat pixelFormat,
common::Dataspace dataspace) {
mDisplay = display;
mComposerClient = client;
- mGraphicBuffer = graphicBuffer;
mPixelFormat = pixelFormat;
mDataspace = dataspace;
@@ -235,19 +234,24 @@
}
void ReadbackBuffer::checkReadbackBuffer(std::vector<Color> expectedColors) {
+ ASSERT_NE(nullptr, mGraphicBuffer);
// lock buffer for reading
ndk::ScopedFileDescriptor fenceHandle;
EXPECT_TRUE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle).isOk());
- int outBytesPerPixel;
- int outBytesPerStride;
+ int bytesPerPixel = -1;
+ int bytesPerStride = -1;
void* bufData = nullptr;
- auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, fenceHandle.get(),
- &outBytesPerPixel, &outBytesPerStride);
+
+ auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(fenceHandle.get()),
+ &bytesPerPixel, &bytesPerStride);
EXPECT_EQ(::android::OK, status);
ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
- ReadbackHelper::compareColorBuffers(expectedColors, bufData, static_cast<int32_t>(mStride),
- mWidth, mHeight, mPixelFormat);
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : mGraphicBuffer->getStride();
+ ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
+ mPixelFormat);
status = mGraphicBuffer->unlock();
EXPECT_EQ(::android::OK, status);
}
@@ -303,10 +307,7 @@
LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
layerSettings.source.buffer.buffer =
std::make_shared<::android::renderengine::impl::ExternalTexture>(
- ::android::sp<::android::GraphicBuffer>::make(
- mGraphicBuffer->handle, ::android::GraphicBuffer::CLONE_HANDLE, mWidth,
- mHeight, static_cast<int32_t>(mPixelFormat), 1, mUsage, mStride),
- mRenderEngine.getInternalRenderEngine(),
+ mGraphicBuffer, mRenderEngine.getInternalRenderEngine(),
::android::renderengine::impl::ExternalTexture::Usage::READABLE);
layerSettings.source.buffer.usePremultipliedAlpha = mBlendMode == BlendMode::PREMULTIPLIED;
@@ -317,7 +318,7 @@
const float translateY = mSourceCrop.top / (static_cast<float>(mHeight));
layerSettings.source.buffer.textureTransform =
- ::android::mat4::translate(::android::vec4(translateX, translateY, 0, 1)) *
+ ::android::mat4::translate(::android::vec4(translateX, translateY, 0, 1.0)) *
::android::mat4::scale(::android::vec4(scaleX, scaleY, 1.0, 1.0));
return layerSettings;
@@ -325,9 +326,14 @@
void TestBufferLayer::fillBuffer(std::vector<Color>& expectedColors) {
void* bufData;
- auto status = mGraphicBuffer->lock(mUsage, &bufData);
+ int32_t bytesPerPixel = -1;
+ int32_t bytesPerStride = -1;
+ auto status = mGraphicBuffer->lock(mUsage, &bufData, &bytesPerPixel, &bytesPerStride);
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : mGraphicBuffer->getStride();
EXPECT_EQ(::android::OK, status);
- ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData,
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
mPixelFormat, expectedColors));
EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp
index 6ff064f..0a55484 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp
@@ -77,13 +77,18 @@
}
}
-void TestRenderEngine::checkColorBuffer(std::vector<Color>& expectedColors) {
+void TestRenderEngine::checkColorBuffer(const std::vector<Color>& expectedColors) {
void* bufferData;
- ASSERT_EQ(0,
- mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()), &bufferData));
- ReadbackHelper::compareColorBuffers(
- expectedColors, bufferData, static_cast<int32_t>(mGraphicBuffer->getStride()),
- mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(), mFormat);
+ int32_t bytesPerPixel = -1;
+ int32_t bytesPerStride = -1;
+ ASSERT_EQ(0, mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()),
+ &bufferData, &bytesPerPixel, &bytesPerStride));
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : mGraphicBuffer->getStride();
+ ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
+ mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
+ mFormat);
ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
index 0fac2b3..a3ce795 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
@@ -43,6 +43,10 @@
static const Color BLACK = {0.0f, 0.0f, 0.0f, 1.0f};
static const Color RED = {1.0f, 0.0f, 0.0f, 1.0f};
+// DIM_RED is 90% dimmed from RED in linear space
+// hard-code as value 243 in 8-bit space here, as calculating it requires
+// oetf(eotf(value) * .9), which is a complex non-linear transformation
+static const Color DIM_RED = {243.f / 255.f, 0.0f, 0.0f, 1.0f};
static const Color TRANSLUCENT_RED = {1.0f, 0.0f, 0.0f, 0.3f};
static const Color GREEN = {0.0f, 1.0f, 0.0f, 1.0f};
static const Color BLUE = {0.0f, 0.0f, 1.0f, 1.0f};
@@ -67,6 +71,7 @@
void setDisplayFrame(Rect frame) { mDisplayFrame = frame; }
void setSourceCrop(FRect crop) { mSourceCrop = crop; }
void setZOrder(uint32_t z) { mZOrder = z; }
+ void setWhitePointNits(float whitePointNits) { mWhitePointNits = whitePointNits; }
void setSurfaceDamage(std::vector<Rect> surfaceDamage) {
mSurfaceDamage = std::move(surfaceDamage);
@@ -84,10 +89,13 @@
int64_t getLayer() const { return mLayer; }
+ float getWhitePointNits() const { return mWhitePointNits; }
+
protected:
int64_t mDisplay;
int64_t mLayer;
Rect mDisplayFrame = {0, 0, 0, 0};
+ float mWhitePointNits = -1.f;
std::vector<Rect> mSurfaceDamage;
Transform mTransform = static_cast<Transform>(0);
FRect mSourceCrop = {0, 0, 0, 0};
@@ -153,7 +161,6 @@
uint32_t mLayerCount;
PixelFormat mPixelFormat;
uint32_t mUsage;
- uint32_t mStride;
::android::Rect mAccessRegion;
};
@@ -181,15 +188,14 @@
static const std::vector<ColorMode> colorModes;
static const std::vector<Dataspace> dataspaces;
- static void compareColorBuffers(std::vector<Color>& expectedColors, void* bufferData,
- const int32_t stride, const uint32_t width,
+ static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
+ const uint32_t stride, const uint32_t width,
const uint32_t height, PixelFormat pixelFormat);
};
class ReadbackBuffer {
public:
- ReadbackBuffer(int64_t display, const std::shared_ptr<IComposerClient>& client,
- const ::android::sp<::android::GraphicBuffer>& graphicBuffer, int32_t width,
+ ReadbackBuffer(int64_t display, const std::shared_ptr<IComposerClient>& client, int32_t width,
int32_t height, common::PixelFormat pixelFormat, common::Dataspace dataspace);
void setReadbackBuffer();
@@ -203,7 +209,6 @@
uint32_t mHeight;
uint32_t mLayerCount;
uint32_t mUsage;
- uint32_t mStride;
PixelFormat mPixelFormat;
Dataspace mDataspace;
int64_t mDisplay;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h
index 2798e09..a776a27 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h
@@ -54,7 +54,7 @@
mDisplaySettings = displaySettings;
};
void drawLayers();
- void checkColorBuffer(std::vector<Color>& expectedColors);
+ void checkColorBuffer(const std::vector<Color>& expectedColors);
::android::renderengine::RenderEngine& getInternalRenderEngine() { return *mRenderEngine; }
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 2ab9c01..5e012f6 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -21,6 +21,7 @@
#include <thread>
#include <vector>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
#include <android-base/logging.h>
@@ -92,7 +93,13 @@
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));
hidl_vec<uint8_t> vec;
- ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));
+ const auto result = mGralloc->get(bufferHandle, metadataType, &vec);
+
+ if (metadataType == gralloc4::MetadataType_Smpte2094_10 && result == Error::UNSUPPORTED) {
+ GTEST_SKIP() << "getting metadata for Smpte2094-10 is unsupported";
+ }
+
+ ASSERT_EQ(Error::NONE, result);
ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
}
@@ -1205,6 +1212,40 @@
}
/**
+ * Test IMapper::isSupported with optional format R_8
+ */
+TEST_P(GraphicsMapperHidlTest, IsSupportedR8) {
+ auto info = mDummyDescriptorInfo;
+ info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(
+ aidl::android::hardware::graphics::common::PixelFormat::R_8);
+ bool supported = false;
+
+ ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+
+ if (!supported) {
+ GTEST_SUCCEED() << "R_8 is optional; unsupported so skipping allocation test";
+ return;
+ }
+
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));
+
+ constexpr uint32_t count = 1;
+ std::vector<const native_handle_t*> bufferHandles;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandles =
+ mGralloc->allocate(descriptor, count, false,
+ Tolerance::kToleranceStrict, &stride));
+
+ EXPECT_LE(info.width, stride) << "invalid buffer stride";
+ EXPECT_EQ(1u, bufferHandles.size());
+
+ for (auto bufferHandle : bufferHandles) {
+ mGralloc->freeBuffer(bufferHandle);
+ }
+}
+
+/**
* Test IMapper::get(BufferId)
*/
TEST_P(GraphicsMapperHidlTest, GetBufferId) {
diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp
index e2ae803..39bec3f 100644
--- a/keymaster/3.0/vts/functional/Android.bp
+++ b/keymaster/3.0/vts/functional/Android.bp
@@ -38,5 +38,11 @@
"libcrypto_static",
"libsoftkeymasterdevice",
],
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ sanitize: {
+ cfi: false,
+ },
}
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
index c650bec..547ce38 100644
--- a/keymaster/4.1/vts/functional/Android.bp
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -48,4 +48,7 @@
"general-tests",
"vts",
],
+ sanitize: {
+ cfi: false,
+ },
}
diff --git a/neuralnetworks/1.0/utils/Android.bp b/neuralnetworks/1.0/utils/Android.bp
index 31cdded..ad30e30 100644
--- a/neuralnetworks/1.0/utils/Android.bp
+++ b/neuralnetworks/1.0/utils/Android.bp
@@ -31,16 +31,11 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
+ "android.hardware.neuralnetworks@1.0",
"libarect",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
- shared_libs: [
- "android.hardware.neuralnetworks@1.0",
- ],
- export_static_lib_headers: [
- "neuralnetworks_utils_hal_common",
- ],
target: {
android: {
shared_libs: ["libnativewindow"],
@@ -55,19 +50,14 @@
static_libs: [
"android.hardware.neuralnetworks@1.0",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
- "libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
index 8bd2fbe..cef76c6 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
@@ -45,12 +45,15 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
private:
const nn::SharedPreparedModel kPreparedModel;
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
index 0a6ca3e..d7c43ef 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
@@ -65,8 +65,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache,
- const nn::CacheToken& token) const override;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
index bdb5b54..337c132 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
@@ -49,18 +49,23 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
diff --git a/neuralnetworks/1.0/utils/src/Burst.cpp b/neuralnetworks/1.0/utils/src/Burst.cpp
index 1284721..3642bc6 100644
--- a/neuralnetworks/1.0/utils/src/Burst.cpp
+++ b/neuralnetworks/1.0/utils/src/Burst.cpp
@@ -50,15 +50,20 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const {
- return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+ return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
}
nn::GeneralResult<nn::SharedExecution> Burst::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
- return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration);
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+ return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
}
} // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Device.cpp b/neuralnetworks/1.0/utils/src/Device.cpp
index b0c236e..620d040 100644
--- a/neuralnetworks/1.0/utils/src/Device.cpp
+++ b/neuralnetworks/1.0/utils/src/Device.cpp
@@ -143,7 +143,9 @@
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
const nn::Model& model, nn::ExecutionPreference /*preference*/, nn::Priority /*priority*/,
nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
- const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that model is ready for IPC.
std::optional<nn::Model> maybeModelInShared;
const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
index 00e7d22..b8055fc 100644
--- a/neuralnetworks/1.0/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
@@ -59,7 +59,9 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
const nn::Request& request, nn::MeasureTiming /*measure*/,
const nn::OptionalTimePoint& /*deadline*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
@@ -94,19 +96,22 @@
}
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& /*request*/,
- const std::vector<nn::SyncFence>& /*waitFor*/,
- nn::MeasureTiming /*measure*/,
- const nn::OptionalTimePoint& /*deadline*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/,
- const nn::OptionalDuration& /*timeoutDurationAfterFence*/) const {
+PreparedModel::executeFenced(
+ const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+ nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const nn::OptionalDuration& /*timeoutDurationAfterFence*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
<< "IPreparedModel::executeFenced is not supported on 1.0 HAL service";
}
nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
const nn::Request& request, nn::MeasureTiming /*measure*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
diff --git a/neuralnetworks/1.0/utils/test/DeviceTest.cpp b/neuralnetworks/1.0/utils/test/DeviceTest.cpp
index 83e555f..9e9db16 100644
--- a/neuralnetworks/1.0/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.0/utils/test/DeviceTest.cpp
@@ -380,7 +380,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -399,7 +399,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -417,7 +417,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -435,7 +435,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -452,7 +452,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -469,7 +469,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -488,7 +488,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
index 7820c06..e03a98d 100644
--- a/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
@@ -121,7 +121,7 @@
.WillOnce(Invoke(makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
EXPECT_TRUE(result.has_value())
@@ -138,7 +138,7 @@
V1_0::ErrorStatus::GENERAL_FAILURE)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -155,7 +155,7 @@
makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -171,7 +171,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -187,7 +187,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -205,7 +205,7 @@
EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -218,7 +218,7 @@
const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -235,7 +235,7 @@
.WillRepeatedly(Invoke(makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -258,7 +258,7 @@
V1_0::ErrorStatus::GENERAL_FAILURE)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -279,7 +279,7 @@
makeExecute(V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -299,7 +299,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -319,7 +319,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -341,7 +341,7 @@
EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -358,7 +358,7 @@
const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
diff --git a/neuralnetworks/1.1/utils/Android.bp b/neuralnetworks/1.1/utils/Android.bp
index 737ff58..4b8999f 100644
--- a/neuralnetworks/1.1/utils/Android.bp
+++ b/neuralnetworks/1.1/utils/Android.bp
@@ -31,17 +31,12 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
],
- shared_libs: [
- "android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- ],
- export_static_lib_headers: [
- "neuralnetworks_utils_hal_common",
- ],
}
cc_test {
@@ -52,20 +47,15 @@
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
"neuralnetworks_utils_hal_1_1",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
- "libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
index d6bd36a..38ca138 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
@@ -64,8 +64,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache,
- const nn::CacheToken& token) const override;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.1/utils/src/Device.cpp b/neuralnetworks/1.1/utils/src/Device.cpp
index 3effa84..28f3276 100644
--- a/neuralnetworks/1.1/utils/src/Device.cpp
+++ b/neuralnetworks/1.1/utils/src/Device.cpp
@@ -143,7 +143,9 @@
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
- const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that model is ready for IPC.
std::optional<nn::Model> maybeModelInShared;
const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.1/utils/test/DeviceTest.cpp b/neuralnetworks/1.1/utils/test/DeviceTest.cpp
index 2248da6..8ab87bc 100644
--- a/neuralnetworks/1.1/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.1/utils/test/DeviceTest.cpp
@@ -390,7 +390,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -409,7 +409,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -427,7 +427,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -445,7 +445,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -462,7 +462,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -479,7 +479,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -498,7 +498,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.2/utils/Android.bp b/neuralnetworks/1.2/utils/Android.bp
index 4eefb0f..4c5f065 100644
--- a/neuralnetworks/1.2/utils/Android.bp
+++ b/neuralnetworks/1.2/utils/Android.bp
@@ -31,19 +31,14 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
- "neuralnetworks_types",
- "neuralnetworks_utils_hal_common",
- "neuralnetworks_utils_hal_1_0",
- "neuralnetworks_utils_hal_1_1",
- ],
- shared_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"libfmq",
- ],
- export_static_lib_headers: [
+ "neuralnetworks_types",
"neuralnetworks_utils_hal_common",
+ "neuralnetworks_utils_hal_1_0",
+ "neuralnetworks_utils_hal_1_1",
],
product_variables: {
debuggable: { // eng and userdebug builds
@@ -71,7 +66,6 @@
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
@@ -79,13 +73,10 @@
"neuralnetworks_utils_hal_1_2",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
"libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h
index ac9411c..1b28476 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Burst.h
@@ -170,13 +170,16 @@
// See IBurst::execute for information on this method.
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
// See IBurst::createReusableExecution for information on this method.
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
// If fallback is not nullptr, this method will invoke the fallback function to try another
// execution path if the packet could not be sent. Otherwise, failing to send the packet will
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
index c3348aa..4f13adc 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
@@ -37,7 +37,7 @@
GeneralResult<Operand::ExtraParams> unvalidatedConvert(
const hal::V1_2::Operand::ExtraParams& extraParams);
GeneralResult<Model> unvalidatedConvert(const hal::V1_2::Model& model);
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
GeneralResult<OutputShape> unvalidatedConvert(const hal::V1_2::OutputShape& outputShape);
GeneralResult<MeasureTiming> unvalidatedConvert(const hal::V1_2::MeasureTiming& measureTiming);
@@ -78,7 +78,7 @@
const nn::Operand::ExtraParams& extraParams);
nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
nn::GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
- const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
+ const nn::ExtensionNameAndPrefix& extensionNameAndPrefix);
nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape);
nn::GeneralResult<MeasureTiming> unvalidatedConvert(const nn::MeasureTiming& measureTiming);
nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing);
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
index e7ac172..d92cf50 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
@@ -83,8 +83,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache,
- const nn::CacheToken& token) const override;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
index 1150e5e..72a5b2f 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
@@ -49,18 +49,23 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
diff --git a/neuralnetworks/1.2/utils/src/Burst.cpp b/neuralnetworks/1.2/utils/src/Burst.cpp
index 911fbfa..23e8070 100644
--- a/neuralnetworks/1.2/utils/src/Burst.cpp
+++ b/neuralnetworks/1.2/utils/src/Burst.cpp
@@ -305,8 +305,9 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// This is the first point when we know an execution is occurring, so begin to collect
// systraces. Note that the first point we can begin collecting systraces in
// ExecutionBurstServer is when the RequestChannelReceiver realizes there is data in the FMQ, so
@@ -317,7 +318,7 @@
// fall back to another execution path
if (!compliantVersion(request).ok()) {
// fallback to another execution path if the packet could not be sent
- return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
+ return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration, {}, {});
}
// ensure that request is ready for IPC
@@ -346,7 +347,7 @@
// send request packet
const auto requestPacket = serialize(hidlRequest, hidlMeasure, slots);
const auto fallback = [this, &request, measure, &deadline, &loopTimeoutDuration] {
- return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
+ return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration, {}, {});
};
return executeInternal(requestPacket, relocation, fallback);
}
@@ -354,14 +355,17 @@
// See IBurst::createReusableExecution for information on this method.
nn::GeneralResult<nn::SharedExecution> Burst::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
NNTRACE_RT(NNTRACE_PHASE_EXECUTION, "Burst::createReusableExecution");
// if the request is valid but of a higher version than what's supported in burst execution,
// fall back to another execution path
if (!compliantVersion(request).ok()) {
// fallback to another execution path if the packet could not be sent
- return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration);
+ return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration, {},
+ {});
}
// ensure that request is ready for IPC
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index 838d9c4..62ec2ed 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -212,9 +212,9 @@
};
}
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
- return Model::ExtensionNameAndPrefix{
+ return ExtensionNameAndPrefix{
.name = extensionNameAndPrefix.name,
.prefix = extensionNameAndPrefix.prefix,
};
@@ -495,7 +495,7 @@
}
nn::GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
- const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
+ const nn::ExtensionNameAndPrefix& extensionNameAndPrefix) {
return Model::ExtensionNameAndPrefix{
.name = extensionNameAndPrefix.name,
.prefix = extensionNameAndPrefix.prefix,
diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp
index e7acecd..3a58d2c 100644
--- a/neuralnetworks/1.2/utils/src/Device.cpp
+++ b/neuralnetworks/1.2/utils/src/Device.cpp
@@ -236,7 +236,9 @@
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that model is ready for IPC.
std::optional<nn::Model> maybeModelInShared;
const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
index 6df3df3..feb3951 100644
--- a/neuralnetworks/1.2/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
@@ -91,7 +91,9 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
const nn::Request& request, nn::MeasureTiming measure,
const nn::OptionalTimePoint& /*deadline*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
@@ -123,19 +125,22 @@
}
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& /*request*/,
- const std::vector<nn::SyncFence>& /*waitFor*/,
- nn::MeasureTiming /*measure*/,
- const nn::OptionalTimePoint& /*deadline*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/,
- const nn::OptionalDuration& /*timeoutDurationAfterFence*/) const {
+PreparedModel::executeFenced(
+ const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+ nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const nn::OptionalDuration& /*timeoutDurationAfterFence*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
<< "IPreparedModel::executeFenced is not supported on 1.2 HAL service";
}
nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
diff --git a/neuralnetworks/1.2/utils/test/DeviceTest.cpp b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
index 1dc6285..0d8c141 100644
--- a/neuralnetworks/1.2/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
@@ -636,7 +636,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -655,7 +655,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -673,7 +673,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -691,7 +691,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -708,7 +708,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -725,7 +725,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -746,7 +746,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
index 5e2ad79..a5ec9d3 100644
--- a/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
@@ -154,7 +154,7 @@
.WillOnce(Invoke(makeExecuteSynchronously(V1_0::ErrorStatus::NONE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
EXPECT_TRUE(result.has_value())
@@ -172,7 +172,7 @@
makeExecuteSynchronously(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -189,7 +189,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -206,7 +206,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -224,7 +224,7 @@
V1_0::ErrorStatus::NONE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
EXPECT_TRUE(result.has_value())
@@ -243,7 +243,7 @@
kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -261,7 +261,7 @@
V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -278,7 +278,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -295,7 +295,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -314,7 +314,7 @@
EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -328,7 +328,7 @@
PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -347,7 +347,7 @@
Invoke(makeExecuteSynchronously(V1_0::ErrorStatus::NONE, {}, kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -371,7 +371,7 @@
makeExecuteSynchronously(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -392,7 +392,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -413,7 +413,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -436,7 +436,7 @@
V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::NONE, {}, kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -461,7 +461,7 @@
kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -483,7 +483,7 @@
V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -504,7 +504,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -525,7 +525,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -548,7 +548,7 @@
EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -566,7 +566,7 @@
PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
diff --git a/neuralnetworks/1.3/utils/Android.bp b/neuralnetworks/1.3/utils/Android.bp
index 7acb4fc..c512dda 100644
--- a/neuralnetworks/1.3/utils/Android.bp
+++ b/neuralnetworks/1.3/utils/Android.bp
@@ -31,21 +31,16 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
- "neuralnetworks_types",
- "neuralnetworks_utils_hal_common",
- "neuralnetworks_utils_hal_1_0",
- "neuralnetworks_utils_hal_1_1",
- "neuralnetworks_utils_hal_1_2",
- ],
- shared_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"android.hardware.neuralnetworks@1.3",
"libfmq",
- ],
- export_static_lib_headers: [
+ "neuralnetworks_types",
"neuralnetworks_utils_hal_common",
+ "neuralnetworks_utils_hal_1_0",
+ "neuralnetworks_utils_hal_1_1",
+ "neuralnetworks_utils_hal_1_2",
],
target: {
host: {
@@ -69,7 +64,6 @@
"android.hardware.neuralnetworks@1.2",
"android.hardware.neuralnetworks@1.3",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
@@ -78,13 +72,10 @@
"neuralnetworks_utils_hal_1_3",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
"libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
index c3c6fc4..cf5e5ea0 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
@@ -66,8 +66,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache,
- const nn::CacheToken& token) const override;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
index 480438d..124cc43 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
@@ -48,18 +48,23 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index a1d414c..09e9d80 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -396,7 +396,7 @@
}
nn::GeneralResult<V1_2::Model::ExtensionNameAndPrefix> unvalidatedConvert(
- const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
+ const nn::ExtensionNameAndPrefix& extensionNameAndPrefix) {
return V1_2::utils::unvalidatedConvert(extensionNameAndPrefix);
}
diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp
index 9517fda..824cec6 100644
--- a/neuralnetworks/1.3/utils/src/Device.cpp
+++ b/neuralnetworks/1.3/utils/src/Device.cpp
@@ -187,7 +187,9 @@
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that model is ready for IPC.
std::optional<nn::Model> maybeModelInShared;
const nn::Model& modelInShared =
diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
index ce977e5..b92f877 100644
--- a/neuralnetworks/1.3/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
@@ -135,8 +135,9 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
@@ -174,10 +175,13 @@
}
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
- nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const {
+PreparedModel::executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
@@ -230,7 +234,9 @@
nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
diff --git a/neuralnetworks/1.3/utils/test/DeviceTest.cpp b/neuralnetworks/1.3/utils/test/DeviceTest.cpp
index 7eba4bc..6f48837 100644
--- a/neuralnetworks/1.3/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.3/utils/test/DeviceTest.cpp
@@ -658,7 +658,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -677,7 +677,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -695,7 +695,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -713,7 +713,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -730,7 +730,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -747,7 +747,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -768,7 +768,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
index 6dbbd6b..51b5d29 100644
--- a/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
@@ -182,7 +182,7 @@
.WillOnce(Invoke(makeExecuteSynchronously(V1_3::ErrorStatus::NONE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
EXPECT_TRUE(result.has_value())
@@ -200,7 +200,7 @@
makeExecuteSynchronously(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -217,7 +217,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -234,7 +234,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -252,7 +252,7 @@
V1_3::ErrorStatus::NONE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
EXPECT_TRUE(result.has_value())
@@ -271,7 +271,7 @@
kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -289,7 +289,7 @@
V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -306,7 +306,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -323,7 +323,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -344,7 +344,7 @@
.WillOnce(InvokeWithoutArgs(ret));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -366,7 +366,7 @@
.WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -396,7 +396,7 @@
.WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -422,7 +422,7 @@
makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, {}, nullptr)));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -439,7 +439,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -456,7 +456,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -475,7 +475,7 @@
Invoke(makeExecuteSynchronously(V1_3::ErrorStatus::NONE, {}, kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -499,7 +499,7 @@
makeExecuteSynchronously(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -520,7 +520,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -541,7 +541,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -564,7 +564,7 @@
V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, {}, kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -589,7 +589,7 @@
kNoTiming)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -611,7 +611,7 @@
V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -628,7 +628,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -649,7 +649,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -674,7 +674,7 @@
.WillOnce(InvokeWithoutArgs(ret));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -702,7 +702,7 @@
Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -738,7 +738,7 @@
.WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -768,7 +768,7 @@
makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, {}, nullptr)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -789,7 +789,7 @@
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -810,7 +810,7 @@
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionConfig.aidl
similarity index 85%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionConfig.aidl
index 7ef08d2..cb85743 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionConfig.aidl
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
+package android.hardware.neuralnetworks;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable ExecutionConfig {
+ boolean measureTiming;
+ long loopTimeoutDurationNs;
+ android.hardware.neuralnetworks.TokenValuePair[] executionHints;
+ android.hardware.neuralnetworks.ExtensionNameAndPrefix[] extensionNameToPrefix;
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
index eb3d0b0..461fdfa 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
@@ -36,4 +36,5 @@
interface IBurst {
android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
void releaseMemoryResource(in long memoryIdentifierToken);
+ android.hardware.neuralnetworks.ExecutionResult executeSynchronouslyWithConfig(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in android.hardware.neuralnetworks.ExecutionConfig config, in long deadlineNs);
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
index c9c67f2..c0fba47 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
@@ -43,6 +43,7 @@
String getVersionString();
void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+ void prepareModelWithConfig(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.PrepareModelConfig config, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
const int BYTE_SIZE_OF_CACHE_TOKEN = 32;
const int MAX_NUMBER_OF_CACHE_FILES = 32;
const int EXTENSION_TYPE_HIGH_BITS_PREFIX = 15;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IExecution.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IExecution.aidl
index 7ef08d2..ab5275e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IExecution.aidl
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.neuralnetworks;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface IExecution {
+ android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in long deadlineNs);
+ android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in ParcelFileDescriptor[] waitFor, in long deadlineNs, in long durationNs);
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
index fccb5dc..fb0c372 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -37,6 +37,9 @@
android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs, in long durationNs);
android.hardware.neuralnetworks.IBurst configureExecutionBurst();
+ android.hardware.neuralnetworks.IExecution createReusableExecution(in android.hardware.neuralnetworks.Request request, in android.hardware.neuralnetworks.ExecutionConfig config);
+ android.hardware.neuralnetworks.ExecutionResult executeSynchronouslyWithConfig(in android.hardware.neuralnetworks.Request request, in android.hardware.neuralnetworks.ExecutionConfig config, in long deadlineNs);
+ android.hardware.neuralnetworks.FencedExecutionResult executeFencedWithConfig(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in android.hardware.neuralnetworks.ExecutionConfig config, in long deadlineNs, in long durationNs);
const long DEFAULT_LOOP_TIMEOUT_DURATION_NS = 2000000000;
const long MAXIMUM_LOOP_TIMEOUT_DURATION_NS = 15000000000;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PrepareModelConfig.aidl
similarity index 78%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PrepareModelConfig.aidl
index 7ef08d2..85c924f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PrepareModelConfig.aidl
@@ -31,9 +31,15 @@
// 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.gnss.visibility_control;
+package android.hardware.neuralnetworks;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable PrepareModelConfig {
+ android.hardware.neuralnetworks.ExecutionPreference preference;
+ android.hardware.neuralnetworks.Priority priority;
+ long deadlineNs;
+ ParcelFileDescriptor[] modelCache;
+ ParcelFileDescriptor[] dataCache;
+ byte[] cacheToken;
+ android.hardware.neuralnetworks.TokenValuePair[] compilationHints;
+ android.hardware.neuralnetworks.ExtensionNameAndPrefix[] extensionNameToPrefix;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/TokenValuePair.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/TokenValuePair.aidl
index 7ef08d2..e477d6e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/TokenValuePair.aidl
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.neuralnetworks;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable TokenValuePair {
+ int token;
+ byte[] value;
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionConfig.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionConfig.aidl
new file mode 100644
index 0000000..00f1e11
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionConfig.aidl
@@ -0,0 +1,60 @@
+/*
+ * 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.neuralnetworks;
+
+import android.hardware.neuralnetworks.ExtensionNameAndPrefix;
+import android.hardware.neuralnetworks.TokenValuePair;
+
+/**
+ * A type that is used to represent all configuration related to
+ * an Execution.
+ */
+@VintfStability
+parcelable ExecutionConfig {
+ /**
+ * Specifies whether or not to measure duration of the execution.
+ * For {@link IPreparedModel::executeSynchronouslyWithConfig}, the duration runs from the time
+ * the driver sees the corresponding call to the execute function to the time the driver returns
+ * from the function. For {@link IPreparedModel::executeFencedWithConfig}, please refer to
+ * {@link IPreparedModelCallback} for details.
+ */
+ boolean measureTiming;
+ /**
+ * The maximum amount of time in nanoseconds that should be spent
+ * executing a {@link OperationType::WHILE} operation. If a loop
+ * condition model does not output false within this duration,
+ * the execution must be aborted. If -1 is provided, the maximum
+ * amount of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}.
+ * Other negative values are invalid. When provided, the duration
+ * must not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+ */
+ long loopTimeoutDurationNs;
+ /**
+ * A vector of token / value pairs represent vendor specific
+ * execution hints or metadata. The provided TokenValuePairs must not
+ * contain the same token twice. The driver must validate the
+ * data and ignore invalid hints. It is up to the driver to
+ * decide whether to respect the provided hints or not.
+ */
+ TokenValuePair[] executionHints;
+ /**
+ * The mapping between extension names and prefixes of token values.
+ * The driver must ignore the corresponding execution hint, if
+ * the extension is not supported.
+ */
+ ExtensionNameAndPrefix[] extensionNameToPrefix;
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
index 20109bd..9f70a53 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
@@ -20,6 +20,10 @@
/**
* Information about an extension.
+ *
+ * The extension can provide zero or more operation types (which are not enumerated), zero or more
+ * operand types (which are enumerated in {@link Extension::operandTypes}, and compilation and
+ * execution hints (which are not enumerated).
*/
@VintfStability
parcelable Extension {
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
index 29be93f..6c296e0 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
@@ -17,7 +17,8 @@
package android.hardware.neuralnetworks;
/**
- * The mapping between extension names and prefixes of operand and operation type values.
+ * The mapping between extension names and prefixes of values like operand and operation type, and
+ * token in {@link TokenValuePair}.
*
* An operand or operation whose numeric type value is above {@link IDevice::OPERAND_TYPE_BASE_MAX}
* or {@link IDevice::OPERATION_TYPE_BASE_MAX} respectively should be interpreted as an extension
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
index decdc48..a05a7fb 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
@@ -17,6 +17,7 @@
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ErrorStatus;
+import android.hardware.neuralnetworks.ExecutionConfig;
import android.hardware.neuralnetworks.ExecutionResult;
import android.hardware.neuralnetworks.Request;
@@ -68,6 +69,8 @@
*
* Only a single execution on a given burst object may be active at any time.
*
+ * Also see {@link IBurst::executeSynchronouslyWithConfig}.
+ *
* @param request The input and output information on which the prepared model is to be
* executed.
* @param memoryIdentifierTokens A list of tokens where each token is a non-negative number
@@ -78,10 +81,10 @@
* runs from the time the driver sees the call to the executeSynchronously
* function to the time the driver returns from the function.
* @param deadlineNs The time by which the execution is expected to complete. The time is
- * measured in nanoseconds since epoch of the steady clock (as from
- * std::chrono::steady_clock). If the execution cannot be finished by the
- * deadline, the execution may be aborted. Passing -1 means the deadline is
- * omitted. Other negative values are invalid.
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the execution cannot be finished
+ * by the deadline, the execution may be aborted. Passing -1 means the
+ * deadline is omitted. Other negative values are invalid.
* @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
* executing a {@link OperationType::WHILE} operation. If a loop
* condition model does not output false within this duration, the
@@ -117,4 +120,13 @@
* - INVALID_ARGUMENT if one of the input arguments is invalid
*/
void releaseMemoryResource(in long memoryIdentifierToken);
+
+ /**
+ * For detailed specification, please refer to {@link IBurst::executeSynchronously}. The
+ * difference between the two methods is that executeSynchronouslyWithConfig takes {@link
+ * ExecutionConfig} instead of a list of configuration parameters, and ExecutionConfig contains
+ * more configuration parameters than are passed to executeSynchronously.
+ */
+ ExecutionResult executeSynchronouslyWithConfig(in Request request,
+ in long[] memoryIdentifierTokens, in ExecutionConfig config, in long deadlineNs);
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
index 72e2623..821b9fe 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
@@ -28,6 +28,7 @@
import android.hardware.neuralnetworks.IPreparedModelParcel;
import android.hardware.neuralnetworks.Model;
import android.hardware.neuralnetworks.NumberOfCacheFiles;
+import android.hardware.neuralnetworks.PrepareModelConfig;
import android.hardware.neuralnetworks.Priority;
/**
@@ -148,7 +149,7 @@
*
* If the device reports that caching is not supported, the user may avoid calling
* IDevice::prepareModelFromCache or providing cache file descriptors to
- * IDevice::prepareModel.
+ * IDevice::prepareModel or IDevice::prepareModelWithConfig.
*
* @return NumberOfCacheFiles structure indicating how many files for model and data cache the
* driver needs to cache a single prepared model. It must be less than or equal to
@@ -302,6 +303,8 @@
*
* Multiple threads may call prepareModel on the same model concurrently.
*
+ * Also see {@link IDevice::prepareModelWithConfig}.
+ *
* @param model The model to be prepared for execution.
* @param preference Indicates the intended execution behavior of a prepared model.
* @param priority The priority of the prepared model relative to other prepared models owned by
@@ -403,17 +406,17 @@
* @param modelCache A vector of file descriptors for the security-sensitive cache. The length
* of the vector must match the numModelCache returned from
* getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
- * the same order as with prepareModel.
+ * the same order as with prepareModel or prepareModelWithConfig.
* @param dataCache A vector of file descriptors for the constants' cache. The length of the
* vector must match the numDataCache returned from
* getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
- * the same order as with prepareModel.
+ * the same order as with prepareModel or prepareModelWithConfig.
* @param token A caching token of length BYTE_SIZE_OF_CACHE_TOKEN identifying the prepared
* model. It is the same token provided when saving the cache files with
- * prepareModel. Tokens should be chosen to have a low rate of collision for a
- * particular application. The driver cannot detect a collision; a collision will
- * result in a failed execution or in a successful execution that produces
- * incorrect output values.
+ * prepareModel or prepareModelWithConfig. Tokens should be chosen to have a low
+ * rate of collision for a particular application. The driver cannot detect a
+ * collision; a collision will result in a failed execution or in a successful
+ * execution that produces incorrect output values.
* @param callback A callback object used to return the error status of preparing the model for
* execution and the prepared model if successful, nullptr otherwise. The
* callback object's notify function must be called exactly once, even if the
@@ -429,4 +432,28 @@
void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache,
in ParcelFileDescriptor[] dataCache, in byte[] token,
in IPreparedModelCallback callback);
+
+ /**
+ * For detailed specification, please refer to {@link IDevice::prepareModel}. The only
+ * difference between the two methods is that prepareModelWithConfig takes {@link
+ * PrepareModelConfig} instead of standalone configuration parameters, which allows vendor
+ * specific compilation metadata to be passed.
+ *
+ * @param model The model to be prepared for execution.
+ * @param config Configuration parameters to prepare the model.
+ * @param callback A callback object used to return the error status of preparing the model for
+ * execution and the prepared model if successful, nullptr otherwise. The
+ * callback object's notify function must be called exactly once, even if the
+ * model could not be prepared.
+ * @throws ServiceSpecificException with one of the following ErrorStatus values:
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments related to preparing the model is
+ * invalid
+ * - MISSED_DEADLINE_* if the preparation is aborted because the model cannot be prepared by
+ * the deadline
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+ */
+ void prepareModelWithConfig(
+ in Model model, in PrepareModelConfig config, in IPreparedModelCallback callback);
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IExecution.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IExecution.aidl
new file mode 100644
index 0000000..3cb9c1a
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IExecution.aidl
@@ -0,0 +1,153 @@
+/*
+ * 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.neuralnetworks;
+
+import android.hardware.neuralnetworks.ExecutionResult;
+import android.hardware.neuralnetworks.FencedExecutionResult;
+
+/**
+ * IExecution represents a reusable execution object with request and most other execution
+ * properties fixed. It is used to launch executions.
+ *
+ * At most one execution may occur on a reusable execution object at any given time, either by
+ * means of executeSynchronously or executeFenced.
+ *
+ * An IExecution object is used to control a set of executions on the same prepared model with
+ * the same request and properties. IExecution objects enable some optimizations:
+ * (1) An IExecution object can preserve resources between executions. For example, a driver can
+ * map a memory object when the IExecution object is created and cache the mapping for reuse in
+ * subsequent executions. Any cached resource can be released when the IExecution object is
+ * destroyed.
+ * (2) Because an IExecution object may be used for at most one execution at a time, any transient
+ * execution resources such as intermediate tensors can be allocated once when the IExecution
+ * object is created and freed when the IExecution object is destroyed.
+ * (3) An IExecution object is created for a fixed request. This enables the implementation to apply
+ * request-specific optimizations. For example, an implementation can avoid request validation
+ * and conversions when the IExecution object is reused. An implementation may also choose to
+ * specialize the dynamic tensor shapes in the IExecution object according to the request.
+ */
+@VintfStability
+interface IExecution {
+ /**
+ * Performs a synchronous execution on the reusable execution object.
+ *
+ * The execution is performed synchronously with respect to the caller. executeSynchronously
+ * must verify the inputs to the function are correct, and the usages of memory pools allocated
+ * by IDevice::allocate are valid. If there is an error, executeSynchronously must immediately
+ * return a service specific exception with the appropriate ErrorStatus value. If the inputs to
+ * the function are valid and there is no error, executeSynchronously must perform the
+ * execution, and must not return until the execution is complete.
+ *
+ * The caller must not change the content of any data object referenced by the 'request'
+ * provided in {@link IPreparedModel::createReusableExecution} (described by the
+ * {@link DataLocation} of a {@link RequestArgument}) until executeSynchronously returns.
+ * executeSynchronously must not change the content of any of the data objects corresponding to
+ * 'request' inputs.
+ *
+ * If the execution object was configured from a prepared model wherein all tensor operands have
+ * fully specified dimensions, and the inputs to the function are valid, and at execution time
+ * every operation's input operands have legal values, then the execution should complete
+ * successfully: there must be no failure unless the device itself is in a bad state.
+ *
+ * If the execution object was created with measureTiming being true and the execution is
+ * successful, the driver may report the timing information in the returning
+ * {@link ExecutionResult}. The duration runs from the time the driver sees the call to the time
+ * the driver returns from the function.
+ *
+ * executeSynchronously may be called with an optional deadline. If the execution is not able to
+ * be completed before the provided deadline, the execution may be aborted, and either
+ * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+ * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort must be
+ * sent the same way as other errors, described above.
+ *
+ * @param deadlineNs The time by which the execution is expected to complete. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the execution cannot be finished
+ * by the deadline, the execution may be aborted. Passing -1 means the
+ * deadline is omitted. Other negative values are invalid.
+ * @return ExecutionResult parcelable, containing the status of the execution, output shapes
+ * and timing information.
+ * @throws ServiceSpecificException with one of the following ErrorStatus values:
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid
+ * - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+ * deadline
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+ */
+ ExecutionResult executeSynchronously(in long deadlineNs);
+
+ /**
+ * Launch a fenced asynchronous execution on the reusable execution object.
+ *
+ * The execution is performed asynchronously with respect to the caller. executeFenced must
+ * verify the inputs to the function are correct, and the usages of memory pools allocated by
+ * IDevice::allocate are valid. If there is an error, executeFenced must immediately return a
+ * service specific exception with the corresponding ErrorStatus. If the inputs to the function
+ * are valid and there is no error, executeFenced must dispatch an asynchronous task to perform
+ * the execution in the background, and immediately return a {@link FencedExecutionResult}
+ * containing two fields: a callback (which can be used by the client to query the duration and
+ * runtime error status) and a sync fence (which will be signaled once the execution is
+ * completed). If the task has finished before the call returns, syncFence file descriptor may
+ * be set to -1. The execution must wait for all the sync fences (if any) in waitFor to be
+ * signaled before starting the actual execution.
+ *
+ * When the asynchronous task has finished its execution, it must immediately signal the
+ * syncFence returned from the executeFenced call. After the syncFence is signaled, the task
+ * must not modify the content of any data object referenced by the 'request' provided in
+ * IPreparedModel::createReusableExecution (described by the {@link DataLocation} of a
+ * {@link RequestArgument}).
+ *
+ * executeFenced may be called with an optional deadline and an optional duration. If the
+ * execution is not able to be completed before the provided deadline or within the timeout
+ * duration (measured from when all sync fences in waitFor are signaled), whichever comes
+ * earlier, the execution may be aborted, and either
+ * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+ * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort must be
+ * sent the same way as other errors, described above.
+ *
+ * If any of the sync fences in waitFor changes to error status after the executeFenced call
+ * succeeds, or the execution is aborted because it cannot finish before the deadline has been
+ * reached or the duration has elapsed, the driver must immediately set the returned syncFence
+ * to error status.
+ *
+ * @param waitFor A vector of sync fence file descriptors. Execution must not start until all
+ * sync fences have been signaled.
+ * @param deadlineNs The time by which the execution is expected to complete. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the execution cannot be finished
+ * by the deadline, the execution may be aborted. Passing -1 means the
+ * deadline is omitted. Other negative values are invalid.
+ * @param durationNs The length of time in nanoseconds within which the execution is expected
+ * to complete after all sync fences in waitFor are signaled. If the
+ * execution cannot be finished within the duration, the execution may be
+ * aborted. Passing -1 means the duration is omitted. Other negative values
+ * are invalid.
+ * @return The FencedExecutionResult parcelable, containing IFencedExecutionCallback and the
+ * sync fence.
+ * @throws ServiceSpecificException with one of the following ErrorStatus values:
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid, including fences in error
+ * states.
+ * - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+ * deadline
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+ */
+ FencedExecutionResult executeFenced(
+ in ParcelFileDescriptor[] waitFor, in long deadlineNs, in long durationNs);
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
index 956b626..949804e 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -18,9 +18,11 @@
import android.hardware.common.NativeHandle;
import android.hardware.neuralnetworks.ErrorStatus;
+import android.hardware.neuralnetworks.ExecutionConfig;
import android.hardware.neuralnetworks.ExecutionResult;
import android.hardware.neuralnetworks.FencedExecutionResult;
import android.hardware.neuralnetworks.IBurst;
+import android.hardware.neuralnetworks.IExecution;
import android.hardware.neuralnetworks.Request;
/**
@@ -67,6 +69,8 @@
* Any number of calls to the execute* functions, in any combination, may be made concurrently,
* even on the same IPreparedModel object.
*
+ * Also see {@link IPreparedModel::executeSynchronouslyWithConfig}.
+ *
* @param request The input and output information on which the prepared model is to be
* executed.
* @param measure Specifies whether or not to measure duration of the execution. The duration
@@ -105,11 +109,12 @@
* IDevice::allocate are valid. If there is an error, executeFenced must immediately return a
* service specific exception with the corresponding ErrorStatus. If the inputs to the function
* are valid and there is no error, executeFenced must dispatch an asynchronous task to perform
- * the execution in the background, assign a sync fence that will be signaled once the execution
- * is completed and immediately return a callback that can be used by the client to query the
- * duration and runtime error status. If the task has finished before the call returns,
- * syncFence file descriptor may be set to -1. The execution must wait for all the sync fences
- * (if any) in waitFor to be signaled before starting the actual execution.
+ * the execution in the background, and immediately return a {@link FencedExecutionResult}
+ * containing two fields: a callback (which can be used by the client to query the duration and
+ * runtime error status) and a sync fence (which will be signaled once the execution is
+ * completed). If the task has finished before the call returns, syncFence file descriptor may
+ * be set to -1. The execution must wait for all the sync fences (if any) in waitFor to be
+ * signaled before starting the actual execution.
*
* When the asynchronous task has finished its execution, it must immediately signal the
* syncFence returned from the executeFenced call. After the syncFence is signaled, the task
@@ -132,6 +137,8 @@
* Any number of calls to the execute* functions, in any combination, may be made concurrently,
* even on the same IPreparedModel object.
*
+ * Also see {@link IPreparedModel::executeFencedWithConfig}.
+ *
* @param request The input and output information on which the prepared model is to be
* executed. The outputs in the request must have fully specified dimensions.
* @param waitFor A vector of sync fence file descriptors. Execution must not start until all
@@ -186,4 +193,86 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
IBurst configureExecutionBurst();
+
+ /**
+ * Create a reusable execution object to launch multiple executions with the same request and
+ * properties.
+ *
+ * createReusableExecution must verify the inputs to the function are correct, and the usages of
+ * memory pools allocated by IDevice::allocate are valid. If there is an error,
+ * createReusableExecution must immediately return a service specific exception with the
+ * appropriate ErrorStatus value. If the inputs to the function are valid and there is no error,
+ * createReusableExecution must construct a reusable execution.
+ *
+ * @param request The input and output information on which the prepared model is to be
+ * executed.
+ * @param config Specifies the execution configuration parameters.
+ * @return execution An IExecution object representing a reusable execution that has been
+ * specialized for a fixed request.
+ * @throws ServiceSpecificException with one of the following ErrorStatus values:
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+ */
+ IExecution createReusableExecution(in Request request, in ExecutionConfig config);
+
+ /**
+ * For detailed specification, please refer to {@link IPreparedModel::executeSynchronously}. The
+ * difference between the two methods is that executeSynchronouslyWithConfig takes {@link
+ * ExecutionConfig} instead of a list of configuration parameters, and ExecutionConfig contains
+ * more configuration parameters than are passed to executeSynchronously.
+ *
+ * @param request The input and output information on which the prepared model is to be
+ * executed.
+ * @param config Specifies the execution configuration parameters.
+ * @param deadlineNs The time by which the execution is expected to complete. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the execution cannot be finished
+ * by the deadline, the execution may be aborted. Passing -1 means the
+ * deadline is omitted. Other negative valueggs are invalid.
+ * @return ExecutionResult parcelable, containing the status of the execution, output shapes and
+ * timing information.
+ * - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+ * deadline
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+ */
+ ExecutionResult executeSynchronouslyWithConfig(
+ in Request request, in ExecutionConfig config, in long deadlineNs);
+
+ /**
+ * For detailed specification, please refer to {@link IPreparedModel::executeFenced}. The
+ * difference between the two methods is that executeFencedWithConfig takes {@link
+ * ExecutionConfig} instead of a list of configuration parameters, and ExecutionConfig contains
+ * more configuration parameters than are passed to executeFenced.
+ *
+ * @param request The input and output information on which the prepared model is to be
+ * executed. The outputs in the request must have fully specified dimensions.
+ * @param waitFor A vector of sync fence file descriptors. Execution must not start until all
+ * sync fences have been signaled.
+ * @param config Specifies the execution configuration parameters.
+ * @param deadlineNs The time by which the execution is expected to complete. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the execution cannot be finished
+ * by the deadline, the execution may be aborted. Passing -1 means the
+ * deadline is omitted. Other negative values are invalid.
+ * @param durationNs The length of time in nanoseconds within which the execution is expected to
+ * complete after all sync fences in waitFor are signaled. If the execution
+ * cannot be finished within the duration, the execution may be aborted.
+ * Passing -1 means the duration is omitted. Other negative values are
+ * invalid.
+ * @return The FencedExecutionResult parcelable, containing IFencedExecutionCallback and the
+ * sync fence.
+ * @throws ServiceSpecificException with one of the following ErrorStatus values:
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid, including fences in error
+ * states.
+ * - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
+ * deadline
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+ */
+ FencedExecutionResult executeFencedWithConfig(in Request request,
+ in ParcelFileDescriptor[] waitFor, in ExecutionConfig config, in long deadlineNs,
+ in long durationNs);
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/PrepareModelConfig.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/PrepareModelConfig.aidl
new file mode 100644
index 0000000..96df968
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/PrepareModelConfig.aidl
@@ -0,0 +1,95 @@
+/*
+ * 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.neuralnetworks;
+
+import android.hardware.neuralnetworks.ExecutionPreference;
+import android.hardware.neuralnetworks.ExtensionNameAndPrefix;
+import android.hardware.neuralnetworks.Priority;
+import android.hardware.neuralnetworks.TokenValuePair;
+
+/**
+ * A type that is used to represent all configuration needed to
+ * prepare a model.
+ */
+@VintfStability
+parcelable PrepareModelConfig {
+ /**
+ * Indicates the intended execution behavior of a prepared model.
+ */
+ ExecutionPreference preference;
+ /**
+ * The priority of the prepared model relative to other prepared
+ * models owned by the client.
+ */
+ Priority priority;
+ /**
+ * The time by which the model is expected to be prepared. The
+ * time is measured in nanoseconds since boot (as from
+ * clock_gettime(CLOCK_BOOTTIME, &ts) or
+ * ::android::base::boot_clock). If the model cannot be prepared
+ * by the deadline, the preparation may be aborted. Passing -1
+ * means the deadline is omitted. Other negative values are
+ * invalid.
+ */
+ long deadlineNs;
+ /**
+ * A vector of file descriptors for the security-sensitive cache.
+ * The length of the vector must either be 0 indicating that
+ * caching information is not provided, or match the
+ * numModelCache returned from IDevice::getNumberOfCacheFilesNeeded. The
+ * cache file descriptors will be provided in the same order when
+ * retrieving the preparedModel from cache files with
+ * IDevice::prepareModelFromCache.
+ */
+ ParcelFileDescriptor[] modelCache;
+ /**
+ * A vector of file descriptors for the constants' cache. The
+ * length of the vector must either be 0 indicating that caching
+ * information is not provided, or match the numDataCache
+ * returned from IDevice::getNumberOfCacheFilesNeeded. The cache file
+ * descriptors will be provided in the same order when retrieving
+ * the preparedModel from cache files with IDevice::prepareModelFromCache.
+ */
+ ParcelFileDescriptor[] dataCache;
+ /**
+ * A caching token of length IDevice::BYTE_SIZE_OF_CACHE_TOKEN identifying
+ * the prepared model. The same token will be provided when
+ * retrieving the prepared model from the cache files with
+ * IDevice::prepareModelFromCache. Tokens should be chosen to have a low
+ * rate of collision for a particular application. The driver
+ * cannot detect a collision; a collision will result in a failed
+ * execution or in a successful execution that produces incorrect
+ * output values. If both modelCache and dataCache are empty
+ * indicating that caching information is not provided, this
+ * token must be ignored.
+ */
+ byte[] cacheToken;
+ /**
+ * A vector of token / value pairs represent vendor specific
+ * compilation hints or metadata. The provided TokenValuePairs must not
+ * contain the same token twice. The driver must validate the
+ * data and ignore invalid hints. It is up to the driver to
+ * decide whether to respect the provided hints or not.
+ */
+ TokenValuePair[] compilationHints;
+ /**
+ * The mapping between extension names and prefixes of token values.
+ * The driver must ignore the corresponding compilation hint, if
+ * the extension is not supported.
+ */
+ ExtensionNameAndPrefix[] extensionNameToPrefix;
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/TokenValuePair.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/TokenValuePair.aidl
new file mode 100644
index 0000000..ec665b4
--- /dev/null
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/TokenValuePair.aidl
@@ -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.
+ */
+
+package android.hardware.neuralnetworks;
+
+/**
+ * A type that is used to represent a token / byte array data pair.
+ */
+@VintfStability
+parcelable TokenValuePair {
+ /**
+ * A 32bit integer token. The token is created by combining the
+ * extension prefix and enum defined within the extension.
+ * The low {@link IDevice::EXTENSION_TYPE_LOW_BITS_TYPE} bits of the value
+ * correspond to the hint within the extension and the high
+ * {@link IDevice::EXTENSION_TYPE_HIGH_BITS_PREFIX} bits encode the "prefix", which maps
+ * uniquely to the extension name. The sign bit is always 0.
+ *
+ * For example, if a token value is 0x7AAA000B and the corresponding
+ * {@link ExtensionNameAndPrefix} contains an entry with prefix=0x7AAA and
+ * name="vendor.test.test_extension", then the token should be interpreted as the hint
+ * 0x000B of the extension named vendor.test.test_extension.
+ */
+ int token;
+ /**
+ * A byte array containing the raw data.
+ */
+ byte[] value;
+}
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index e356104..9148eac 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -26,7 +26,14 @@
cc_defaults {
name: "neuralnetworks_utils_hal_aidl_defaults",
defaults: ["neuralnetworks_utils_defaults"],
- srcs: ["src/*"],
+ srcs: [
+ // AIDL utils that a driver may depend on.
+ "src/BufferTracker.cpp",
+ "src/Conversions.cpp",
+ "src/HalUtils.cpp",
+ "src/Utils.cpp",
+ "src/ValidateHal.cpp",
+ ],
local_include_dirs: ["include/nnapi/hal/aidl/"],
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
@@ -47,6 +54,7 @@
},
}
+// Deprecated. Remove once all modules depending on this are migrated away.
cc_library_static {
name: "neuralnetworks_utils_hal_aidl_v1",
defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
@@ -56,19 +64,25 @@
}
cc_library_static {
- name: "neuralnetworks_utils_hal_aidl_v2",
- defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
- shared_libs: [
- "android.hardware.neuralnetworks-V2-ndk",
- ],
-}
-
-cc_library_static {
name: "neuralnetworks_utils_hal_aidl",
defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
- shared_libs: [
- "android.hardware.neuralnetworks-V3-ndk",
+ srcs: [
+ // Additional AIDL utils for the runtime.
+ "src/Assertions.cpp",
+ "src/Buffer.cpp",
+ "src/Burst.cpp",
+ "src/Callbacks.cpp",
+ "src/Device.cpp",
+ "src/Execution.cpp",
+ "src/InvalidDevice.cpp",
+ "src/PreparedModel.cpp",
+ "src/ProtectCallback.cpp",
+ "src/Service.cpp",
],
+ shared_libs: [
+ "android.hardware.neuralnetworks-V4-ndk",
+ ],
+ cflags: ["-DNN_AIDL_V4_OR_ABOVE"],
}
// A cc_defaults that includes the latest non-experimental AIDL utilities and other AIDL libraries
@@ -79,9 +93,10 @@
static_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.graphics.common-V3-ndk",
- "android.hardware.neuralnetworks-V3-ndk",
+ "android.hardware.neuralnetworks-V4-ndk",
"neuralnetworks_utils_hal_aidl",
],
+ cflags: ["-DNN_AIDL_V4_OR_ABOVE"],
}
cc_test {
@@ -96,19 +111,13 @@
static_libs: [
"libaidlcommonsupport",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
shared_libs: [
- "android.hidl.allocator@1.0",
"libbase",
"libbinder_ndk",
"libcutils",
- "libhidlbase",
- "libhidlmemory",
- "liblog",
- "libutils",
],
target: {
android: {
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
index 0cc78d4..f2e6e75 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
@@ -86,10 +86,12 @@
GUARDED_BY(mMutex);
};
+ // featureLevel is for testing purposes.
static nn::GeneralResult<std::shared_ptr<const Burst>> create(
- std::shared_ptr<aidl_hal::IBurst> burst);
+ std::shared_ptr<aidl_hal::IBurst> burst, nn::Version featureLevel);
- Burst(PrivateConstructorTag tag, std::shared_ptr<aidl_hal::IBurst> burst);
+ Burst(PrivateConstructorTag tag, std::shared_ptr<aidl_hal::IBurst> burst,
+ nn::Version featureLevel);
// See IBurst::cacheMemory for information.
OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
@@ -97,23 +99,29 @@
// See IBurst::execute for information.
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
// See IBurst::createReusableExecution for information.
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeInternal(
const aidl_hal::Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
bool measure, int64_t deadline, int64_t loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
const hal::utils::RequestRelocation& relocation) const;
private:
mutable std::atomic_flag mExecutionInFlight = ATOMIC_FLAG_INIT;
const std::shared_ptr<aidl_hal::IBurst> kBurst;
const std::shared_ptr<MemoryCache> kMemoryCache;
+ const nn::Version kFeatureLevel;
};
} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h
index 168264b..960be2b 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Callbacks.h
@@ -36,6 +36,8 @@
public:
using Data = nn::GeneralResult<nn::SharedPreparedModel>;
+ PreparedModelCallback(nn::Version featureLevel) : kFeatureLevel(featureLevel) {}
+
ndk::ScopedAStatus notify(ErrorStatus status,
const std::shared_ptr<IPreparedModel>& preparedModel) override;
@@ -44,6 +46,7 @@
Data get();
private:
+ const nn::Version kFeatureLevel;
hal::utils::TransferValue<Data> mData;
};
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
index 477b311..af58715 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
@@ -46,6 +46,10 @@
#include <aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.h>
#include <aidl/android/hardware/neuralnetworks/Timing.h>
+#ifdef NN_AIDL_V4_OR_ABOVE
+#include <aidl/android/hardware/neuralnetworks/TokenValuePair.h>
+#endif // NN_AIDL_V4_OR_ABOVE
+
#include <android/binder_auto_utils.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
@@ -74,7 +78,7 @@
const aidl_hal::SymmPerChannelQuantParams& symmPerChannelQuantParams);
GeneralResult<Operation> unvalidatedConvert(const aidl_hal::Operation& operation);
GeneralResult<Model> unvalidatedConvert(const aidl_hal::Model& model);
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
const aidl_hal::ExtensionNameAndPrefix& extensionNameAndPrefix);
GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues);
GeneralResult<Model::Subgraph> unvalidatedConvert(const aidl_hal::Subgraph& subgraph);
@@ -97,6 +101,10 @@
const aidl_hal::ExtensionOperandTypeInformation& operandTypeInformation);
GeneralResult<SharedHandle> unvalidatedConvert(const ndk::ScopedFileDescriptor& handle);
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<TokenValuePair> unvalidatedConvert(const aidl_hal::TokenValuePair& tokenValuePair);
+#endif // NN_AIDL_V4_OR_ABOVE
+
GeneralResult<std::vector<Operation>> unvalidatedConvert(
const std::vector<aidl_hal::Operation>& operations);
@@ -116,6 +124,14 @@
GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension);
GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories);
+GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+ const std::vector<aidl_hal::ExtensionNameAndPrefix>& extensionNameAndPrefix);
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<std::vector<TokenValuePair>> convert(
+ const std::vector<aidl_hal::TokenValuePair>& metaData);
+#endif // NN_AIDL_V4_OR_ABOVE
+
GeneralResult<std::vector<OutputShape>> convert(
const std::vector<aidl_hal::OutputShape>& outputShapes);
GeneralResult<std::vector<SharedHandle>> convert(
@@ -152,7 +168,7 @@
nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(
const nn::Model::OperandValues& operandValues);
nn::GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
- const nn::Model::ExtensionNameAndPrefix& extensionNameToPrefix);
+ const nn::ExtensionNameAndPrefix& extensionNameToPrefix);
nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
nn::GeneralResult<Priority> unvalidatedConvert(const nn::Priority& priority);
nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request);
@@ -166,6 +182,10 @@
nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities);
nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension);
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<TokenValuePair> unvalidatedConvert(const nn::TokenValuePair& tokenValuePair);
+#endif // NN_AIDL_V4_OR_ABOVE
+
nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken);
nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc);
nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType);
@@ -190,6 +210,13 @@
nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
const std::vector<nn::SyncFence>& syncFences);
nn::GeneralResult<std::vector<Extension>> convert(const std::vector<nn::Extension>& extensions);
+nn::GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix);
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<std::vector<TokenValuePair>> convert(
+ const std::vector<nn::TokenValuePair>& metaData);
+#endif // NN_AIDL_V4_OR_ABOVE
nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec);
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
index d558f66..615c6de 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
@@ -42,6 +42,7 @@
struct PrivateConstructorTag {};
public:
+ // featureLevel is for testing purposes.
static nn::GeneralResult<std::shared_ptr<const Device>> create(
std::string name, std::shared_ptr<aidl_hal::IDevice> device, nn::Version featureLevel);
@@ -67,8 +68,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache,
- const nn::CacheToken& token) const override;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h
index a77ea98..14802b9 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Execution.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_EXECUTION_H
#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_EXECUTION_H
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
+
#include <nnapi/IExecution.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
@@ -33,17 +35,22 @@
namespace aidl::android::hardware::neuralnetworks::utils {
-class Execution final : public nn::IExecution, public std::enable_shared_from_this<Execution> {
+// A reusable execution implementation with a cached Request, internally it is still passing the
+// request to the driver in every computation.
+class ExecutionWithCachedRequest final
+ : public nn::IExecution,
+ public std::enable_shared_from_this<ExecutionWithCachedRequest> {
struct PrivateConstructorTag {};
public:
- static nn::GeneralResult<std::shared_ptr<const Execution>> create(
+ static nn::GeneralResult<std::shared_ptr<const ExecutionWithCachedRequest>> create(
std::shared_ptr<const PreparedModel> preparedModel, Request request,
hal::utils::RequestRelocation relocation, bool measure, int64_t loopTimeoutDuration);
- Execution(PrivateConstructorTag tag, std::shared_ptr<const PreparedModel> preparedModel,
- Request request, hal::utils::RequestRelocation relocation, bool measure,
- int64_t loopTimeoutDuration);
+ ExecutionWithCachedRequest(PrivateConstructorTag tag,
+ std::shared_ptr<const PreparedModel> preparedModel, Request request,
+ hal::utils::RequestRelocation relocation, bool measure,
+ int64_t loopTimeoutDuration);
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> compute(
const nn::OptionalTimePoint& deadline) const override;
@@ -60,6 +67,30 @@
const int64_t kLoopTimeoutDuration;
};
+// A reusable execution implementation that is backed by an actual AIDL IExecution object.
+class Execution final : public nn::IExecution, public std::enable_shared_from_this<Execution> {
+ struct PrivateConstructorTag {};
+
+ public:
+ static nn::GeneralResult<std::shared_ptr<const Execution>> create(
+ std::shared_ptr<aidl_hal::IExecution> execution,
+ hal::utils::RequestRelocation relocation);
+
+ Execution(PrivateConstructorTag tag, std::shared_ptr<aidl_hal::IExecution> execution,
+ hal::utils::RequestRelocation relocation);
+
+ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> compute(
+ const nn::OptionalTimePoint& deadline) const override;
+
+ nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> computeFenced(
+ const std::vector<nn::SyncFence>& waitFor, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+
+ private:
+ const std::shared_ptr<aidl_hal::IExecution> kExecution;
+ const hal::utils::RequestRelocation kRelocation;
+};
+
} // namespace aidl::android::hardware::neuralnetworks::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_EXECUTION_H
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h
index 3fb443c..cacdc26 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/HalInterfaces.h
@@ -61,6 +61,13 @@
#include <aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.h>
#include <aidl/android/hardware/neuralnetworks/Timing.h>
+#ifdef NN_AIDL_V4_OR_ABOVE
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionConfig.h>
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
+#include <aidl/android/hardware/neuralnetworks/PrepareModelConfig.h>
+#endif // NN_AIDL_V4_OR_ABOVE
+
namespace android::nn {
namespace aidl_hal = ::aidl::android::hardware::neuralnetworks;
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
index e66507a..9375c1d 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
@@ -53,6 +53,9 @@
const std::vector<ndk::ScopedFileDescriptor>& dataCache,
const std::vector<uint8_t>& token,
const std::shared_ptr<IPreparedModelCallback>& callback) override;
+ ndk::ScopedAStatus prepareModelWithConfig(
+ const Model& model, const PrepareModelConfig& config,
+ const std::shared_ptr<IPreparedModelCallback>& callback) override;
ndk::ScopedAStatus prepareModelFromCache(
int64_t deadline, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
const std::vector<ndk::ScopedFileDescriptor>& dataCache,
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
index 4035764..cb6a85b 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
@@ -40,26 +40,33 @@
struct PrivateConstructorTag {};
public:
+ // featureLevel is for testing purposes.
static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
- std::shared_ptr<aidl_hal::IPreparedModel> preparedModel);
+ std::shared_ptr<aidl_hal::IPreparedModel> preparedModel, nn::Version featureLevel);
PreparedModel(PrivateConstructorTag tag,
- std::shared_ptr<aidl_hal::IPreparedModel> preparedModel);
+ std::shared_ptr<aidl_hal::IPreparedModel> preparedModel,
+ nn::Version featureLevel);
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
@@ -67,6 +74,8 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeInternal(
const Request& request, bool measure, int64_t deadline, int64_t loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
const hal::utils::RequestRelocation& relocation) const;
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
@@ -74,10 +83,13 @@
const std::vector<ndk::ScopedFileDescriptor>& waitFor, bool measure,
int64_t deadline, int64_t loopTimeoutDuration,
int64_t timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
const hal::utils::RequestRelocation& relocation) const;
private:
const std::shared_ptr<aidl_hal::IPreparedModel> kPreparedModel;
+ const nn::Version kFeatureLevel;
};
} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
index a27487e..beca38b 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
@@ -38,6 +38,8 @@
return nn::kVersionFeatureLevel6;
case 3:
return nn::kVersionFeatureLevel7;
+ case 4:
+ return nn::kVersionFeatureLevel8;
default:
return std::nullopt;
}
diff --git a/neuralnetworks/aidl/utils/src/Burst.cpp b/neuralnetworks/aidl/utils/src/Burst.cpp
index fb00b26..6c7aa88 100644
--- a/neuralnetworks/aidl/utils/src/Burst.cpp
+++ b/neuralnetworks/aidl/utils/src/Burst.cpp
@@ -43,12 +43,16 @@
static nn::GeneralResult<std::shared_ptr<const BurstExecution>> create(
std::shared_ptr<const Burst> burst, Request request,
std::vector<int64_t> memoryIdentifierTokens, bool measure, int64_t loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
hal::utils::RequestRelocation relocation,
std::vector<Burst::OptionalCacheHold> cacheHolds);
BurstExecution(PrivateConstructorTag tag, std::shared_ptr<const Burst> burst, Request request,
std::vector<int64_t> memoryIdentifierTokens, bool measure,
- int64_t loopTimeoutDuration, hal::utils::RequestRelocation relocation,
+ int64_t loopTimeoutDuration, const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
+ hal::utils::RequestRelocation relocation,
std::vector<Burst::OptionalCacheHold> cacheHolds);
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> compute(
@@ -64,6 +68,8 @@
const std::vector<int64_t> kMemoryIdentifierTokens;
const bool kMeasure;
const int64_t kLoopTimeoutDuration;
+ const std::vector<nn::TokenValuePair> kHints;
+ const std::vector<nn::ExtensionNameAndPrefix> kExtensionNameToPrefix;
const hal::utils::RequestRelocation kRelocation;
const std::vector<Burst::OptionalCacheHold> kCacheHolds;
};
@@ -149,17 +155,20 @@
}
nn::GeneralResult<std::shared_ptr<const Burst>> Burst::create(
- std::shared_ptr<aidl_hal::IBurst> burst) {
+ std::shared_ptr<aidl_hal::IBurst> burst, nn::Version featureLevel) {
if (burst == nullptr) {
return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
<< "aidl_hal::utils::Burst::create must have non-null burst";
}
- return std::make_shared<const Burst>(PrivateConstructorTag{}, std::move(burst));
+ return std::make_shared<const Burst>(PrivateConstructorTag{}, std::move(burst), featureLevel);
}
-Burst::Burst(PrivateConstructorTag /*tag*/, std::shared_ptr<aidl_hal::IBurst> burst)
- : kBurst(std::move(burst)), kMemoryCache(std::make_shared<MemoryCache>(kBurst)) {
+Burst::Burst(PrivateConstructorTag /*tag*/, std::shared_ptr<aidl_hal::IBurst> burst,
+ nn::Version featureLevel)
+ : kBurst(std::move(burst)),
+ kMemoryCache(std::make_shared<MemoryCache>(kBurst)),
+ kFeatureLevel(featureLevel) {
CHECK(kBurst != nullptr);
}
@@ -170,8 +179,9 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
@@ -200,14 +210,14 @@
memoryIdentifierTokens.push_back(-1);
}
CHECK_EQ(requestInShared.pools.size(), memoryIdentifierTokens.size());
-
return executeInternal(aidlRequest, memoryIdentifierTokens, aidlMeasure, aidlDeadline,
- aidlLoopTimeoutDuration, relocation);
+ aidlLoopTimeoutDuration, hints, extensionNameToPrefix, relocation);
}
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::executeInternal(
const Request& request, const std::vector<int64_t>& memoryIdentifierTokens, bool measure,
- int64_t deadline, int64_t loopTimeoutDuration,
+ int64_t deadline, int64_t loopTimeoutDuration, const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
const hal::utils::RequestRelocation& relocation) const {
// Ensure that at most one execution is in flight at any given time.
const bool alreadyInFlight = mExecutionInFlight.test_and_set();
@@ -221,9 +231,21 @@
}
ExecutionResult executionResult;
- const auto ret = kBurst->executeSynchronously(request, memoryIdentifierTokens, measure,
- deadline, loopTimeoutDuration, &executionResult);
- HANDLE_ASTATUS(ret) << "execute failed";
+ if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+ auto aidlHints = NN_TRY(convert(hints));
+ auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+ const auto ret = kBurst->executeSynchronouslyWithConfig(
+ request, memoryIdentifierTokens,
+ {measure, loopTimeoutDuration, std::move(aidlHints),
+ std::move(aidlExtensionPrefix)},
+ deadline, &executionResult);
+ HANDLE_ASTATUS(ret) << "execute failed";
+ } else {
+ const auto ret =
+ kBurst->executeSynchronously(request, memoryIdentifierTokens, measure, deadline,
+ loopTimeoutDuration, &executionResult);
+ HANDLE_ASTATUS(ret) << "execute failed";
+ }
if (!executionResult.outputSufficientSize) {
auto canonicalOutputShapes =
nn::convert(executionResult.outputShapes).value_or(std::vector<nn::OutputShape>{});
@@ -241,7 +263,9 @@
nn::GeneralResult<nn::SharedExecution> Burst::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
@@ -272,12 +296,15 @@
return BurstExecution::create(shared_from_this(), std::move(aidlRequest),
std::move(memoryIdentifierTokens), aidlMeasure,
- aidlLoopTimeoutDuration, std::move(relocation), std::move(holds));
+ aidlLoopTimeoutDuration, hints, extensionNameToPrefix,
+ std::move(relocation), std::move(holds));
}
nn::GeneralResult<std::shared_ptr<const BurstExecution>> BurstExecution::create(
std::shared_ptr<const Burst> burst, Request request,
std::vector<int64_t> memoryIdentifierTokens, bool measure, int64_t loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
hal::utils::RequestRelocation relocation,
std::vector<Burst::OptionalCacheHold> cacheHolds) {
if (burst == nullptr) {
@@ -286,13 +313,15 @@
return std::make_shared<const BurstExecution>(
PrivateConstructorTag{}, std::move(burst), std::move(request),
- std::move(memoryIdentifierTokens), measure, loopTimeoutDuration, std::move(relocation),
- std::move(cacheHolds));
+ std::move(memoryIdentifierTokens), measure, loopTimeoutDuration, hints,
+ extensionNameToPrefix, std::move(relocation), std::move(cacheHolds));
}
BurstExecution::BurstExecution(PrivateConstructorTag /*tag*/, std::shared_ptr<const Burst> burst,
Request request, std::vector<int64_t> memoryIdentifierTokens,
bool measure, int64_t loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
hal::utils::RequestRelocation relocation,
std::vector<Burst::OptionalCacheHold> cacheHolds)
: kBurst(std::move(burst)),
@@ -300,6 +329,8 @@
kMemoryIdentifierTokens(std::move(memoryIdentifierTokens)),
kMeasure(measure),
kLoopTimeoutDuration(loopTimeoutDuration),
+ kHints(hints),
+ kExtensionNameToPrefix(extensionNameToPrefix),
kRelocation(std::move(relocation)),
kCacheHolds(std::move(cacheHolds)) {}
@@ -307,7 +338,8 @@
const nn::OptionalTimePoint& deadline) const {
const auto aidlDeadline = NN_TRY(convert(deadline));
return kBurst->executeInternal(kRequest, kMemoryIdentifierTokens, kMeasure, aidlDeadline,
- kLoopTimeoutDuration, kRelocation);
+ kLoopTimeoutDuration, kHints, kExtensionNameToPrefix,
+ kRelocation);
}
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
diff --git a/neuralnetworks/aidl/utils/src/Callbacks.cpp b/neuralnetworks/aidl/utils/src/Callbacks.cpp
index 8084970..554f3fa 100644
--- a/neuralnetworks/aidl/utils/src/Callbacks.cpp
+++ b/neuralnetworks/aidl/utils/src/Callbacks.cpp
@@ -38,16 +38,17 @@
// nn::kVersionFeatureLevel5. On failure, this function returns with the appropriate
// nn::GeneralError.
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
- ErrorStatus status, const std::shared_ptr<IPreparedModel>& preparedModel) {
+ ErrorStatus status, const std::shared_ptr<IPreparedModel>& preparedModel,
+ nn::Version featureLevel) {
HANDLE_STATUS_AIDL(status) << "model preparation failed with " << toString(status);
- return NN_TRY(PreparedModel::create(preparedModel));
+ return NN_TRY(PreparedModel::create(preparedModel, featureLevel));
}
} // namespace
ndk::ScopedAStatus PreparedModelCallback::notify(
ErrorStatus status, const std::shared_ptr<IPreparedModel>& preparedModel) {
- mData.put(prepareModelCallback(status, preparedModel));
+ mData.put(prepareModelCallback(status, preparedModel, kFeatureLevel));
return ndk::ScopedAStatus::ok();
}
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index 113d2da..eb28db7 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -302,9 +302,9 @@
};
}
-GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
+GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
const aidl_hal::ExtensionNameAndPrefix& extensionNameAndPrefix) {
- return Model::ExtensionNameAndPrefix{
+ return ExtensionNameAndPrefix{
.name = extensionNameAndPrefix.name,
.prefix = extensionNameAndPrefix.prefix,
};
@@ -506,6 +506,12 @@
return std::make_shared<const Handle>(std::move(duplicatedFd));
}
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<TokenValuePair> unvalidatedConvert(const aidl_hal::TokenValuePair& tokenValuePair) {
+ return TokenValuePair{.token = tokenValuePair.token, .value = tokenValuePair.value};
+}
+#endif // NN_AIDL_V4_OR_ABOVE
+
GeneralResult<Capabilities> convert(const aidl_hal::Capabilities& capabilities) {
return validatedConvert(capabilities);
}
@@ -562,6 +568,17 @@
GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories) {
return validatedConvert(memories);
}
+GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+ const std::vector<aidl_hal::ExtensionNameAndPrefix>& extensionNameAndPrefix) {
+ return unvalidatedConvert(extensionNameAndPrefix);
+}
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+GeneralResult<std::vector<TokenValuePair>> convert(
+ const std::vector<aidl_hal::TokenValuePair>& metaData) {
+ return validatedConvert(metaData);
+}
+#endif // NN_AIDL_V4_OR_ABOVE
GeneralResult<std::vector<OutputShape>> convert(
const std::vector<aidl_hal::OutputShape>& outputShapes) {
@@ -942,7 +959,7 @@
}
nn::GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
- const nn::Model::ExtensionNameAndPrefix& extensionNameToPrefix) {
+ const nn::ExtensionNameAndPrefix& extensionNameToPrefix) {
return ExtensionNameAndPrefix{
.name = extensionNameToPrefix.name,
.prefix = extensionNameToPrefix.prefix,
@@ -1055,6 +1072,11 @@
return Extension{.name = extension.name,
.operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes))};
}
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<TokenValuePair> unvalidatedConvert(const nn::TokenValuePair& tokenValuePair) {
+ return TokenValuePair{.token = tokenValuePair.token, .value = tokenValuePair.value};
+}
+#endif // NN_AIDL_V4_OR_ABOVE
nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken) {
return validatedConvert(cacheToken);
@@ -1134,6 +1156,17 @@
const std::vector<nn::SyncFence>& syncFences) {
return validatedConvert(syncFences);
}
+nn::GeneralResult<std::vector<ExtensionNameAndPrefix>> convert(
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) {
+ return unvalidatedConvert(extensionNameToPrefix);
+}
+
+#ifdef NN_AIDL_V4_OR_ABOVE
+nn::GeneralResult<std::vector<TokenValuePair>> convert(
+ const std::vector<nn::TokenValuePair>& metaData) {
+ return validatedConvert(metaData);
+}
+#endif // NN_AIDL_V4_OR_ABOVE
nn::GeneralResult<std::vector<Extension>> convert(const std::vector<nn::Extension>& extensions) {
return validatedConvert(extensions);
diff --git a/neuralnetworks/aidl/utils/src/Device.cpp b/neuralnetworks/aidl/utils/src/Device.cpp
index 5b7ec4e..f3f4fdb 100644
--- a/neuralnetworks/aidl/utils/src/Device.cpp
+++ b/neuralnetworks/aidl/utils/src/Device.cpp
@@ -215,7 +215,9 @@
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
// Ensure that model is ready for IPC.
std::optional<nn::Model> maybeModelInShared;
const nn::Model& modelInShared =
@@ -225,17 +227,28 @@
const auto aidlPreference = NN_TRY(convert(preference));
const auto aidlPriority = NN_TRY(convert(priority));
const auto aidlDeadline = NN_TRY(convert(deadline));
- const auto aidlModelCache = NN_TRY(convert(modelCache));
- const auto aidlDataCache = NN_TRY(convert(dataCache));
+ auto aidlModelCache = NN_TRY(convert(modelCache));
+ auto aidlDataCache = NN_TRY(convert(dataCache));
const auto aidlToken = NN_TRY(convert(token));
- const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>();
+ const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>(kFeatureLevel);
const auto scoped = kDeathHandler.protectCallback(cb.get());
+ if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+ auto aidlHints = NN_TRY(convert(hints));
+ auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+ const auto ret = kDevice->prepareModelWithConfig(
+ aidlModel,
+ {aidlPreference, aidlPriority, aidlDeadline, std::move(aidlModelCache),
+ std::move(aidlDataCache), aidlToken, std::move(aidlHints),
+ std::move(aidlExtensionPrefix)},
+ cb);
+ HANDLE_ASTATUS(ret) << "prepareModel failed";
+ return cb->get();
+ }
const auto ret = kDevice->prepareModel(aidlModel, aidlPreference, aidlPriority, aidlDeadline,
aidlModelCache, aidlDataCache, aidlToken, cb);
HANDLE_ASTATUS(ret) << "prepareModel failed";
-
return cb->get();
}
@@ -247,7 +260,7 @@
const auto aidlDataCache = NN_TRY(convert(dataCache));
const auto aidlToken = NN_TRY(convert(token));
- const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>();
+ const auto cb = ndk::SharedRefBase::make<PreparedModelCallback>(kFeatureLevel);
const auto scoped = kDeathHandler.protectCallback(cb.get());
const auto ret = kDevice->prepareModelFromCache(aidlDeadline, aidlModelCache, aidlDataCache,
diff --git a/neuralnetworks/aidl/utils/src/Execution.cpp b/neuralnetworks/aidl/utils/src/Execution.cpp
index 94edd90..2fd88af 100644
--- a/neuralnetworks/aidl/utils/src/Execution.cpp
+++ b/neuralnetworks/aidl/utils/src/Execution.cpp
@@ -35,44 +35,61 @@
namespace aidl::android::hardware::neuralnetworks::utils {
-nn::GeneralResult<std::shared_ptr<const Execution>> Execution::create(
- std::shared_ptr<const PreparedModel> preparedModel, Request request,
- hal::utils::RequestRelocation relocation, bool measure, int64_t loopTimeoutDuration) {
+nn::GeneralResult<std::shared_ptr<const ExecutionWithCachedRequest>>
+ExecutionWithCachedRequest::create(std::shared_ptr<const PreparedModel> preparedModel,
+ Request request, hal::utils::RequestRelocation relocation,
+ bool measure, int64_t loopTimeoutDuration) {
if (preparedModel == nullptr) {
- return NN_ERROR() << "aidl::utils::Execution::create must have non-null preparedModel";
+ return NN_ERROR() << "aidl::utils::ExecutionWithCachedRequest::create must have non-null "
+ "preparedModel";
}
- return std::make_shared<const Execution>(PrivateConstructorTag{}, std::move(preparedModel),
- std::move(request), std::move(relocation), measure,
- loopTimeoutDuration);
+ return std::make_shared<const ExecutionWithCachedRequest>(
+ PrivateConstructorTag{}, std::move(preparedModel), std::move(request),
+ std::move(relocation), measure, loopTimeoutDuration);
}
-Execution::Execution(PrivateConstructorTag /*tag*/,
- std::shared_ptr<const PreparedModel> preparedModel, Request request,
- hal::utils::RequestRelocation relocation, bool measure,
- int64_t loopTimeoutDuration)
+ExecutionWithCachedRequest::ExecutionWithCachedRequest(
+ PrivateConstructorTag /*tag*/, std::shared_ptr<const PreparedModel> preparedModel,
+ Request request, hal::utils::RequestRelocation relocation, bool measure,
+ int64_t loopTimeoutDuration)
: kPreparedModel(std::move(preparedModel)),
kRequest(std::move(request)),
kRelocation(std::move(relocation)),
kMeasure(measure),
kLoopTimeoutDuration(loopTimeoutDuration) {}
-nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
- const nn::OptionalTimePoint& deadline) const {
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+ExecutionWithCachedRequest::compute(const nn::OptionalTimePoint& deadline) const {
const auto aidlDeadline = NN_TRY(convert(deadline));
return kPreparedModel->executeInternal(kRequest, kMeasure, aidlDeadline, kLoopTimeoutDuration,
- kRelocation);
+ {}, {}, kRelocation);
}
-nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> Execution::computeFenced(
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+ExecutionWithCachedRequest::computeFenced(
const std::vector<nn::SyncFence>& waitFor, const nn::OptionalTimePoint& deadline,
const nn::OptionalDuration& timeoutDurationAfterFence) const {
const auto aidlWaitFor = NN_TRY(convert(waitFor));
const auto aidlDeadline = NN_TRY(convert(deadline));
const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
- return kPreparedModel->executeFencedInternal(kRequest, aidlWaitFor, kMeasure, aidlDeadline,
- kLoopTimeoutDuration,
- aidlTimeoutDurationAfterFence, kRelocation);
+ return kPreparedModel->executeFencedInternal(
+ kRequest, aidlWaitFor, kMeasure, aidlDeadline, kLoopTimeoutDuration,
+ aidlTimeoutDurationAfterFence, {}, {}, kRelocation);
}
+nn::GeneralResult<std::shared_ptr<const Execution>> Execution::create(
+ std::shared_ptr<aidl_hal::IExecution> execution, hal::utils::RequestRelocation relocation) {
+ if (execution == nullptr) {
+ return NN_ERROR() << "aidl::utils::Execution::create must have non-null execution";
+ }
+
+ return std::make_shared<const Execution>(PrivateConstructorTag{}, std::move(execution),
+ std::move(relocation));
+}
+
+Execution::Execution(PrivateConstructorTag /*tag*/, std::shared_ptr<aidl_hal::IExecution> execution,
+ hal::utils::RequestRelocation relocation)
+ : kExecution(std::move(execution)), kRelocation(std::move(relocation)) {}
+
} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/src/InvalidDevice.cpp b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
index c9d9955..33270ff 100644
--- a/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
+++ b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
@@ -167,6 +167,31 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus InvalidDevice::prepareModelWithConfig(
+ const Model& model, const PrepareModelConfig& config,
+ const std::shared_ptr<IPreparedModelCallback>& callback) {
+ if (!utils::valid(config.extensionNameToPrefix)) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, "Invalid extensionNameToPrefix");
+ }
+ for (const auto& hint : config.compilationHints) {
+ auto result = std::find_if(config.extensionNameToPrefix.begin(),
+ config.extensionNameToPrefix.end(),
+ [&hint](const ExtensionNameAndPrefix& extension) {
+ uint16_t prefix = static_cast<uint32_t>(hint.token) >>
+ IDevice::EXTENSION_TYPE_LOW_BITS_TYPE;
+ return prefix == extension.prefix;
+ });
+ if (result == config.extensionNameToPrefix.end()) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "Invalid token for compilation hints: " + std::to_string(hint.token));
+ }
+ }
+ return prepareModel(model, config.preference, config.priority, config.deadlineNs,
+ config.modelCache, config.dataCache, config.cacheToken, callback);
+}
+
ndk::ScopedAStatus InvalidDevice::prepareModelFromCache(
int64_t /*deadline*/, const std::vector<ndk::ScopedFileDescriptor>& /*modelCache*/,
const std::vector<ndk::ScopedFileDescriptor>& /*dataCache*/,
diff --git a/neuralnetworks/aidl/utils/src/PreparedModel.cpp b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
index f25c2c8..7e3a31c 100644
--- a/neuralnetworks/aidl/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
@@ -54,61 +54,16 @@
return std::make_pair(NN_TRY(nn::convert(timingLaunched)), NN_TRY(nn::convert(timingFenced)));
}
-} // namespace
-
-nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
- std::shared_ptr<aidl_hal::IPreparedModel> preparedModel) {
- if (preparedModel == nullptr) {
- return NN_ERROR()
- << "aidl_hal::utils::PreparedModel::create must have non-null preparedModel";
- }
-
- return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel));
-}
-
-PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/,
- std::shared_ptr<aidl_hal::IPreparedModel> preparedModel)
- : kPreparedModel(std::move(preparedModel)) {}
-
-nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
- const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const {
- // Ensure that request is ready for IPC.
- std::optional<nn::Request> maybeRequestInShared;
- hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
- &maybeRequestInShared, &relocation));
-
- const auto aidlRequest = NN_TRY(convert(requestInShared));
- const auto aidlMeasure = NN_TRY(convert(measure));
- const auto aidlDeadline = NN_TRY(convert(deadline));
- const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
- return executeInternal(aidlRequest, aidlMeasure, aidlDeadline, aidlLoopTimeoutDuration,
- relocation);
-}
-
-nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
-PreparedModel::executeInternal(const Request& request, bool measure, int64_t deadline,
- int64_t loopTimeoutDuration,
- const hal::utils::RequestRelocation& relocation) const {
- if (relocation.input) {
- relocation.input->flush();
- }
-
- ExecutionResult executionResult;
- const auto ret = kPreparedModel->executeSynchronously(request, measure, deadline,
- loopTimeoutDuration, &executionResult);
- HANDLE_ASTATUS(ret) << "executeSynchronously failed";
- if (!executionResult.outputSufficientSize) {
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> handleExecutionResult(
+ const ExecutionResult& result, const hal::utils::RequestRelocation& relocation) {
+ if (!result.outputSufficientSize) {
auto canonicalOutputShapes =
- nn::convert(executionResult.outputShapes).value_or(std::vector<nn::OutputShape>{});
+ nn::convert(result.outputShapes).value_or(std::vector<nn::OutputShape>{});
return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
<< "execution failed with " << nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
}
auto [outputShapes, timing] =
- NN_TRY(convertExecutionResults(executionResult.outputShapes, executionResult.timing));
+ NN_TRY(convertExecutionResults(result.outputShapes, result.timing));
if (relocation.output) {
relocation.output->flush();
@@ -117,44 +72,8 @@
}
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
- nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const {
- // Ensure that request is ready for IPC.
- std::optional<nn::Request> maybeRequestInShared;
- hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
- &maybeRequestInShared, &relocation));
-
- const auto aidlRequest = NN_TRY(convert(requestInShared));
- const auto aidlWaitFor = NN_TRY(convert(waitFor));
- const auto aidlMeasure = NN_TRY(convert(measure));
- const auto aidlDeadline = NN_TRY(convert(deadline));
- const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
- const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
- return executeFencedInternal(aidlRequest, aidlWaitFor, aidlMeasure, aidlDeadline,
- aidlLoopTimeoutDuration, aidlTimeoutDurationAfterFence,
- relocation);
-}
-
-nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-PreparedModel::executeFencedInternal(const Request& request,
- const std::vector<ndk::ScopedFileDescriptor>& waitFor,
- bool measure, int64_t deadline, int64_t loopTimeoutDuration,
- int64_t timeoutDurationAfterFence,
- const hal::utils::RequestRelocation& relocation) const {
- if (relocation.input) {
- relocation.input->flush();
- }
-
- FencedExecutionResult result;
- const auto ret =
- kPreparedModel->executeFenced(request, waitFor, measure, deadline, loopTimeoutDuration,
- timeoutDurationAfterFence, &result);
- HANDLE_ASTATUS(ret) << "executeFenced failed";
-
+handleFencedExecutionResult(const FencedExecutionResult& result,
+ const hal::utils::RequestRelocation& relocation) {
auto resultSyncFence = nn::SyncFence::createAsSignaled();
if (result.syncFence.get() != -1) {
resultSyncFence = nn::SyncFence::create(NN_TRY(nn::convert(result.syncFence))).value();
@@ -165,7 +84,7 @@
return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "callback is null";
}
- // If executeFenced required the request memory to be moved into shared memory, block here until
+ // If computeFenced required the request memory to be moved into shared memory, block here until
// the fenced execution has completed and flush the memory back.
if (relocation.output) {
const auto state = resultSyncFence.syncWait({});
@@ -189,9 +108,133 @@
return std::make_pair(std::move(resultSyncFence), std::move(resultCallback));
}
+} // namespace
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+ std::shared_ptr<aidl_hal::IPreparedModel> preparedModel, nn::Version featureLevel) {
+ if (preparedModel == nullptr) {
+ return NN_ERROR()
+ << "aidl_hal::utils::PreparedModel::create must have non-null preparedModel";
+ }
+
+ return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+ featureLevel);
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/,
+ std::shared_ptr<aidl_hal::IPreparedModel> preparedModel,
+ nn::Version featureLevel)
+ : kPreparedModel(std::move(preparedModel)), kFeatureLevel(featureLevel) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+ // Ensure that request is ready for IPC.
+ std::optional<nn::Request> maybeRequestInShared;
+ hal::utils::RequestRelocation relocation;
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+ &maybeRequestInShared, &relocation));
+
+ const auto aidlRequest = NN_TRY(convert(requestInShared));
+ const auto aidlMeasure = NN_TRY(convert(measure));
+ const auto aidlDeadline = NN_TRY(convert(deadline));
+ const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
+ return executeInternal(aidlRequest, aidlMeasure, aidlDeadline, aidlLoopTimeoutDuration, hints,
+ extensionNameToPrefix, relocation);
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeInternal(const Request& request, bool measure, int64_t deadline,
+ int64_t loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
+ const hal::utils::RequestRelocation& relocation) const {
+ if (relocation.input) {
+ relocation.input->flush();
+ }
+
+ ExecutionResult executionResult;
+ if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+ auto aidlHints = NN_TRY(convert(hints));
+ auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+ const auto ret = kPreparedModel->executeSynchronouslyWithConfig(
+ request,
+ {measure, loopTimeoutDuration, std::move(aidlHints),
+ std::move(aidlExtensionPrefix)},
+ deadline, &executionResult);
+ HANDLE_ASTATUS(ret) << "executeSynchronouslyWithConfig failed";
+ } else {
+ const auto ret = kPreparedModel->executeSynchronously(
+ request, measure, deadline, loopTimeoutDuration, &executionResult);
+ HANDLE_ASTATUS(ret) << "executeSynchronously failed";
+ }
+ return handleExecutionResult(executionResult, relocation);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+ // Ensure that request is ready for IPC.
+ std::optional<nn::Request> maybeRequestInShared;
+ hal::utils::RequestRelocation relocation;
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+ &maybeRequestInShared, &relocation));
+
+ const auto aidlRequest = NN_TRY(convert(requestInShared));
+ const auto aidlWaitFor = NN_TRY(convert(waitFor));
+ const auto aidlMeasure = NN_TRY(convert(measure));
+ const auto aidlDeadline = NN_TRY(convert(deadline));
+ const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
+ const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
+ return executeFencedInternal(aidlRequest, aidlWaitFor, aidlMeasure, aidlDeadline,
+ aidlLoopTimeoutDuration, aidlTimeoutDurationAfterFence, hints,
+ extensionNameToPrefix, relocation);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFencedInternal(
+ const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor, bool measure,
+ int64_t deadline, int64_t loopTimeoutDuration, int64_t timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix,
+ const hal::utils::RequestRelocation& relocation) const {
+ if (relocation.input) {
+ relocation.input->flush();
+ }
+
+ FencedExecutionResult result;
+ if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+ auto aidlHints = NN_TRY(convert(hints));
+ auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+ const auto ret = kPreparedModel->executeFencedWithConfig(
+ request, waitFor,
+ {measure, loopTimeoutDuration, std::move(aidlHints),
+ std::move(aidlExtensionPrefix)},
+ deadline, timeoutDurationAfterFence, &result);
+ HANDLE_ASTATUS(ret) << "executeFencedWithConfig failed";
+ } else {
+ const auto ret = kPreparedModel->executeFenced(request, waitFor, measure, deadline,
+ loopTimeoutDuration,
+ timeoutDurationAfterFence, &result);
+ HANDLE_ASTATUS(ret) << "executeFenced failed";
+ }
+ return handleFencedExecutionResult(result, relocation);
+}
+
nn::GeneralResult<nn::SharedExecution> PreparedModel::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
@@ -202,15 +245,31 @@
auto aidlRequest = NN_TRY(convert(requestInShared));
auto aidlMeasure = NN_TRY(convert(measure));
auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
- return Execution::create(shared_from_this(), std::move(aidlRequest), std::move(relocation),
- aidlMeasure, aidlLoopTimeoutDuration);
+
+ if (kFeatureLevel.level >= nn::Version::Level::FEATURE_LEVEL_8) {
+ std::shared_ptr<IExecution> execution;
+ auto aidlHints = NN_TRY(convert(hints));
+ auto aidlExtensionPrefix = NN_TRY(convert(extensionNameToPrefix));
+
+ const auto ret = kPreparedModel->createReusableExecution(
+ aidlRequest,
+ {aidlMeasure, aidlLoopTimeoutDuration, std::move(aidlHints),
+ std::move(aidlExtensionPrefix)},
+ &execution);
+ HANDLE_ASTATUS(ret) << "createReusableExecution failed";
+ return Execution::create(std::move(execution), std::move(relocation));
+ }
+
+ return ExecutionWithCachedRequest::create(shared_from_this(), std::move(aidlRequest),
+ std::move(relocation), aidlMeasure,
+ aidlLoopTimeoutDuration);
}
nn::GeneralResult<nn::SharedBurst> PreparedModel::configureExecutionBurst() const {
std::shared_ptr<IBurst> burst;
const auto ret = kPreparedModel->configureExecutionBurst(&burst);
HANDLE_ASTATUS(ret) << "configureExecutionBurst failed";
- return Burst::create(std::move(burst));
+ return Burst::create(std::move(burst), kFeatureLevel);
}
std::any PreparedModel::getUnderlyingResource() const {
@@ -218,4 +277,36 @@
return resource;
}
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
+ const nn::OptionalTimePoint& deadline) const {
+ const auto aidlDeadline = NN_TRY(convert(deadline));
+
+ if (kRelocation.input) {
+ kRelocation.input->flush();
+ }
+
+ ExecutionResult executionResult;
+ auto ret = kExecution->executeSynchronously(aidlDeadline, &executionResult);
+ HANDLE_ASTATUS(ret) << "executeSynchronously failed";
+ return handleExecutionResult(executionResult, kRelocation);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> Execution::computeFenced(
+ const std::vector<nn::SyncFence>& waitFor, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalDuration& timeoutDurationAfterFence) const {
+ const auto aidlWaitFor = NN_TRY(convert(waitFor));
+ const auto aidlDeadline = NN_TRY(convert(deadline));
+ const auto aidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
+
+ if (kRelocation.input) {
+ kRelocation.input->flush();
+ }
+
+ FencedExecutionResult result;
+ const auto ret = kExecution->executeFenced(aidlWaitFor, aidlDeadline,
+ aidlTimeoutDurationAfterFence, &result);
+ HANDLE_ASTATUS(ret) << "executeFenced failed";
+ return handleFencedExecutionResult(result, kRelocation);
+}
+
} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/DeviceTest.cpp b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
index 0366e7d..73727b3 100644
--- a/neuralnetworks/aidl/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
@@ -17,6 +17,7 @@
#include "MockBuffer.h"
#include "MockDevice.h"
#include "MockPreparedModel.h"
+#include "TestUtils.h"
#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
#include <android/binder_auto_utils.h>
@@ -60,7 +61,6 @@
.powerUsage = std::numeric_limits<float>::max()};
constexpr NumberOfCacheFiles kNumberOfCacheFiles = {.numModelCache = nn::kMaxNumberOfCacheFiles - 1,
.numDataCache = nn::kMaxNumberOfCacheFiles};
-
constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
std::shared_ptr<MockDevice> createMockDevice() {
@@ -123,6 +123,18 @@
};
}
+const std::vector<nn::TokenValuePair> kHints = {nn::TokenValuePair{.token = 0, .value = {1}}};
+const std::vector<nn::ExtensionNameAndPrefix> kExtensionNameToPrefix = {
+ nn::ExtensionNameAndPrefix{.name = "com.android.nn_test", .prefix = 1}};
+auto makePreparedModelWithConfigReturn(ErrorStatus launchStatus, ErrorStatus returnStatus,
+ const std::shared_ptr<MockPreparedModel>& preparedModel) {
+ return [launchStatus, returnStatus, preparedModel](
+ const Model& /*model*/, const PrepareModelConfig& /*config*/,
+ const std::shared_ptr<IPreparedModelCallback>& cb) -> ndk::ScopedAStatus {
+ return makePreparedModelReturnImpl(launchStatus, returnStatus, preparedModel, cb);
+ };
+}
+
auto makePreparedModelFromCacheReturn(ErrorStatus launchStatus, ErrorStatus returnStatus,
const std::shared_ptr<MockPreparedModel>& preparedModel) {
return [launchStatus, returnStatus, preparedModel](
@@ -146,26 +158,7 @@
return ndk::ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
};
-class DeviceTest : public ::testing::TestWithParam<nn::Version> {
- protected:
- const nn::Version kVersion = GetParam();
-};
-
-std::string printDeviceTest(const testing::TestParamInfo<nn::Version>& info) {
- const nn::Version version = info.param;
- CHECK(!version.runtimeOnlyFeatures);
- switch (version.level) {
- case nn::Version::Level::FEATURE_LEVEL_5:
- return "v1";
- case nn::Version::Level::FEATURE_LEVEL_6:
- return "v2";
- case nn::Version::Level::FEATURE_LEVEL_7:
- return "v3";
- default:
- LOG(FATAL) << "Invalid AIDL version: " << version;
- return "invalid";
- }
-}
+class DeviceTest : public VersionedAidlUtilsTestBase {};
} // namespace
@@ -578,6 +571,8 @@
}
TEST_P(DeviceTest, prepareModel) {
+ if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
// setup call
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -589,7 +584,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -598,6 +593,8 @@
}
TEST_P(DeviceTest, prepareModelLaunchError) {
+ if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
// setup call
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -608,7 +605,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -616,6 +613,8 @@
}
TEST_P(DeviceTest, prepareModelReturnError) {
+ if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
// setup call
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -626,7 +625,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -634,6 +633,8 @@
}
TEST_P(DeviceTest, prepareModelNullptrError) {
+ if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
// setup call
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -644,7 +645,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -652,6 +653,8 @@
}
TEST_P(DeviceTest, prepareModelTransportFailure) {
+ if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
// setup call
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -661,7 +664,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -669,6 +672,8 @@
}
TEST_P(DeviceTest, prepareModelDeadObject) {
+ if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
// setup call
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -678,7 +683,7 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -686,6 +691,8 @@
}
TEST_P(DeviceTest, prepareModelAsyncCrash) {
+ if (kVersion.level > nn::Version::Level::FEATURE_LEVEL_7) return;
+
// setup test
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
@@ -699,7 +706,157 @@
// run test
const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfig) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockDevice = createMockDevice();
+ const auto device = Device::create(kName, mockDevice, kVersion).value();
+ const auto mockPreparedModel = MockPreparedModel::create();
+ EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makePreparedModelWithConfigReturn(ErrorStatus::NONE, ErrorStatus::NONE,
+ mockPreparedModel)));
+
+ // run test
+ const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+ nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+ kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+ EXPECT_NE(result.value(), nullptr);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigLaunchError) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockDevice = createMockDevice();
+ const auto device = Device::create(kName, mockDevice, kVersion).value();
+ EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makePreparedModelWithConfigReturn(
+ ErrorStatus::GENERAL_FAILURE, ErrorStatus::GENERAL_FAILURE, nullptr)));
+
+ // run test
+ const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+ nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+ kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigReturnError) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockDevice = createMockDevice();
+ const auto device = Device::create(kName, mockDevice, kVersion).value();
+ EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makePreparedModelWithConfigReturn(
+ ErrorStatus::NONE, ErrorStatus::GENERAL_FAILURE, nullptr)));
+
+ // run test
+ const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+ nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+ kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigNullptrError) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockDevice = createMockDevice();
+ const auto device = Device::create(kName, mockDevice, kVersion).value();
+ EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makePreparedModelWithConfigReturn(ErrorStatus::NONE, ErrorStatus::NONE,
+ nullptr)));
+
+ // run test
+ const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+ nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+ kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigTransportFailure) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockDevice = createMockDevice();
+ const auto device = Device::create(kName, mockDevice, kVersion).value();
+ EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+ // run test
+ const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+ nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+ kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigDeadObject) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockDevice = createMockDevice();
+ const auto device = Device::create(kName, mockDevice, kVersion).value();
+ EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+ // run test
+ const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+ nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+ kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(DeviceTest, prepareModelWithConfigAsyncCrash) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockDevice = createMockDevice();
+ const auto device = Device::create(kName, mockDevice, kVersion).value();
+ const auto ret = [&device]() {
+ DeathMonitor::serviceDied(device->getDeathMonitor());
+ return ndk::ScopedAStatus::ok();
+ };
+ EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(ret));
+
+ // run test
+ const auto result = device->prepareModel(kSimpleModel, nn::ExecutionPreference::DEFAULT,
+ nn::Priority::DEFAULT, {}, {}, {}, {}, kHints,
+ kExtensionNameToPrefix);
// verify result
ASSERT_FALSE(result.has_value());
@@ -894,9 +1051,6 @@
EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
-INSTANTIATE_TEST_SUITE_P(TestDevice, DeviceTest,
- ::testing::Values(nn::kVersionFeatureLevel5, nn::kVersionFeatureLevel6,
- nn::kVersionFeatureLevel7),
- printDeviceTest);
+INSTANTIATE_VERSIONED_AIDL_UTILS_TEST(DeviceTest, kAllAidlVersions);
} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/ExecutionTest.cpp b/neuralnetworks/aidl/utils/test/ExecutionTest.cpp
new file mode 100644
index 0000000..8519290
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/ExecutionTest.cpp
@@ -0,0 +1,254 @@
+/*
+ * 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 "MockExecution.h"
+#include "MockFencedExecutionCallback.h"
+
+#include <aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <nnapi/IExecution.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/aidl/Execution.h>
+
+#include <functional>
+#include <memory>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+namespace {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::InvokeWithoutArgs;
+using ::testing::SetArgPointee;
+
+const std::shared_ptr<IExecution> kInvalidExecution;
+constexpr auto kNoTiming = Timing{.timeOnDeviceNs = -1, .timeInDriverNs = -1};
+
+constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
+
+constexpr auto makeGeneralFailure = [] {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+};
+constexpr auto makeGeneralTransportFailure = [] {
+ return ndk::ScopedAStatus::fromStatus(STATUS_NO_MEMORY);
+};
+constexpr auto makeDeadObjectFailure = [] {
+ return ndk::ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
+};
+
+auto makeFencedExecutionResult(const std::shared_ptr<MockFencedExecutionCallback>& callback) {
+ return [callback](const std::vector<ndk::ScopedFileDescriptor>& /*waitFor*/,
+ int64_t /*deadline*/, int64_t /*duration*/,
+ FencedExecutionResult* fencedExecutionResult) {
+ *fencedExecutionResult = FencedExecutionResult{.callback = callback,
+ .syncFence = ndk::ScopedFileDescriptor(-1)};
+ return ndk::ScopedAStatus::ok();
+ };
+}
+
+} // namespace
+
+TEST(ExecutionTest, invalidExecution) {
+ // run test
+ const auto result = Execution::create(kInvalidExecution, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeSync) {
+ // setup call
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ const auto mockExecutionResult = ExecutionResult{
+ .outputSufficientSize = true,
+ .outputShapes = {},
+ .timing = kNoTiming,
+ };
+ EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+ .Times(1)
+ .WillOnce(
+ DoAll(SetArgPointee<1>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
+
+ // run test
+ const auto result = execution->compute({});
+
+ // verify result
+ EXPECT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+}
+
+TEST(ExecutionTest, executeSyncError) {
+ // setup test
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+ .Times(1)
+ .WillOnce(Invoke(makeGeneralFailure));
+
+ // run test
+ const auto result = execution->compute({});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeSyncTransportFailure) {
+ // setup test
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+ // run test
+ const auto result = execution->compute({});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeSyncDeadObject) {
+ // setup test
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ EXPECT_CALL(*mockExecution, executeSynchronously(_, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+ // run test
+ const auto result = execution->compute({});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST(ExecutionTest, executeFenced) {
+ // setup call
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ const auto mockCallback = MockFencedExecutionCallback::create();
+ EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+ .Times(1)
+ .WillOnce(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+ SetArgPointee<2>(ErrorStatus::NONE), Invoke(makeStatusOk)));
+ EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
+
+ // run test
+ const auto result = execution->computeFenced({}, {}, {});
+
+ // verify result
+ ASSERT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+ const auto& [syncFence, callback] = result.value();
+ EXPECT_EQ(syncFence.syncWait({}), nn::SyncFence::FenceState::SIGNALED);
+ ASSERT_NE(callback, nullptr);
+
+ // get results from callback
+ const auto callbackResult = callback();
+ ASSERT_TRUE(callbackResult.has_value()) << "Failed with " << callbackResult.error().code << ": "
+ << callbackResult.error().message;
+}
+
+TEST(ExecutionTest, executeFencedCallbackError) {
+ // setup call
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ const auto mockCallback = MockFencedExecutionCallback::create();
+ EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+ .Times(1)
+ .WillOnce(Invoke(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+ SetArgPointee<2>(ErrorStatus::GENERAL_FAILURE),
+ Invoke(makeStatusOk))));
+ EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
+
+ // run test
+ const auto result = execution->computeFenced({}, {}, {});
+
+ // verify result
+ ASSERT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+ const auto& [syncFence, callback] = result.value();
+ EXPECT_NE(syncFence.syncWait({}), nn::SyncFence::FenceState::ACTIVE);
+ ASSERT_NE(callback, nullptr);
+
+ // verify callback failure
+ const auto callbackResult = callback();
+ ASSERT_FALSE(callbackResult.has_value());
+ EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeFencedError) {
+ // setup test
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
+
+ // run test
+ const auto result = execution->computeFenced({}, {}, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeFencedTransportFailure) {
+ // setup test
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+ // run test
+ const auto result = execution->computeFenced({}, {}, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(ExecutionTest, executeFencedDeadObject) {
+ // setup test
+ const auto mockExecution = MockExecution::create();
+ const auto execution = Execution::create(mockExecution, {}).value();
+ EXPECT_CALL(*mockExecution, executeFenced(_, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+ // run test
+ const auto result = execution->computeFenced({}, {}, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/MockBuffer.h b/neuralnetworks/aidl/utils/test/MockBuffer.h
index f77fa86..7a05a0f 100644
--- a/neuralnetworks/aidl/utils/test/MockBuffer.h
+++ b/neuralnetworks/aidl/utils/test/MockBuffer.h
@@ -21,7 +21,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
diff --git a/neuralnetworks/aidl/utils/test/MockBurst.h b/neuralnetworks/aidl/utils/test/MockBurst.h
index 5083bbd..609bd30 100644
--- a/neuralnetworks/aidl/utils/test/MockBurst.h
+++ b/neuralnetworks/aidl/utils/test/MockBurst.h
@@ -21,7 +21,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
@@ -32,6 +31,10 @@
bool measureTiming, int64_t deadline, int64_t loopTimeoutDuration,
ExecutionResult* executionResult),
(override));
+ MOCK_METHOD(ndk::ScopedAStatus, executeSynchronouslyWithConfig,
+ (const Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
+ const ExecutionConfig& config, int64_t deadline, ExecutionResult* executionResult),
+ (override));
MOCK_METHOD(ndk::ScopedAStatus, releaseMemoryResource, (int64_t memoryIdentifierToken),
(override));
};
diff --git a/neuralnetworks/aidl/utils/test/MockDevice.h b/neuralnetworks/aidl/utils/test/MockDevice.h
index 3a28d55..47b8346 100644
--- a/neuralnetworks/aidl/utils/test/MockDevice.h
+++ b/neuralnetworks/aidl/utils/test/MockDevice.h
@@ -50,6 +50,10 @@
const std::vector<uint8_t>& token,
const std::shared_ptr<IPreparedModelCallback>& callback),
(override));
+ MOCK_METHOD(ndk::ScopedAStatus, prepareModelWithConfig,
+ (const Model& model, const PrepareModelConfig& config,
+ const std::shared_ptr<IPreparedModelCallback>& callback),
+ (override));
MOCK_METHOD(ndk::ScopedAStatus, prepareModelFromCache,
(int64_t deadline, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
const std::vector<ndk::ScopedFileDescriptor>& dataCache,
diff --git a/neuralnetworks/aidl/utils/test/MockExecution.h b/neuralnetworks/aidl/utils/test/MockExecution.h
new file mode 100644
index 0000000..782e54f
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/MockExecution.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_EXECUTION_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_EXECUTION_H
+
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
+#include <android/binder_interface_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+class MockExecution final : public BnExecution {
+ public:
+ static std::shared_ptr<MockExecution> create();
+
+ MOCK_METHOD(ndk::ScopedAStatus, executeSynchronously,
+ (int64_t deadline, ExecutionResult* executionResult), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, executeFenced,
+ (const std::vector<ndk::ScopedFileDescriptor>& waitFor, int64_t deadline,
+ int64_t duration, FencedExecutionResult* fencedExecutionResult),
+ (override));
+};
+
+inline std::shared_ptr<MockExecution> MockExecution::create() {
+ return ndk::SharedRefBase::make<MockExecution>();
+}
+
+} // namespace aidl::android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_EXECUTION_H
diff --git a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
index 06f9ea2..29449bb 100644
--- a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
+++ b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
@@ -22,7 +22,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
diff --git a/neuralnetworks/aidl/utils/test/MockPreparedModel.h b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
index a4ae2b7..a5b3b66 100644
--- a/neuralnetworks/aidl/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
@@ -17,12 +17,11 @@
#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL_H
#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL_H
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
@@ -39,8 +38,21 @@
bool measureTiming, int64_t deadline, int64_t loopTimeoutDuration,
int64_t duration, FencedExecutionResult* fencedExecutionResult),
(override));
+ MOCK_METHOD(ndk::ScopedAStatus, executeSynchronouslyWithConfig,
+ (const Request& request, const ExecutionConfig& config, int64_t deadline,
+ ExecutionResult* executionResult),
+ (override));
+ MOCK_METHOD(ndk::ScopedAStatus, executeFencedWithConfig,
+ (const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+ const ExecutionConfig& config, int64_t deadline, int64_t duration,
+ FencedExecutionResult* fencedExecutionResult),
+ (override));
MOCK_METHOD(ndk::ScopedAStatus, configureExecutionBurst, (std::shared_ptr<IBurst> * burst),
(override));
+ MOCK_METHOD(ndk::ScopedAStatus, createReusableExecution,
+ (const Request& request, const ExecutionConfig& config,
+ std::shared_ptr<IExecution>* execution),
+ (override));
};
inline std::shared_ptr<MockPreparedModel> MockPreparedModel::create() {
diff --git a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
index 8bb5c90..bf6136d 100644
--- a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
@@ -15,8 +15,10 @@
*/
#include "MockBurst.h"
+#include "MockExecution.h"
#include "MockFencedExecutionCallback.h"
#include "MockPreparedModel.h"
+#include "TestUtils.h"
#include <aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.h>
#include <gmock/gmock.h>
@@ -66,21 +68,40 @@
};
}
+class PreparedModelTest : public VersionedAidlUtilsTestBase {};
+
+const std::vector<nn::TokenValuePair> kHints = {nn::TokenValuePair{.token = 0, .value = {1}}};
+const std::vector<nn::ExtensionNameAndPrefix> kExtensionNameToPrefix = {
+ nn::ExtensionNameAndPrefix{.name = "com.android.nn_test", .prefix = 1}};
+auto makeFencedExecutionWithConfigResult(
+ const std::shared_ptr<MockFencedExecutionCallback>& callback) {
+ return [callback](const Request& /*request*/,
+ const std::vector<ndk::ScopedFileDescriptor>& /*waitFor*/,
+ const ExecutionConfig& /*config*/, int64_t /*deadline*/, int64_t /*duration*/,
+ FencedExecutionResult* fencedExecutionResult) {
+ *fencedExecutionResult = FencedExecutionResult{.callback = callback,
+ .syncFence = ndk::ScopedFileDescriptor(-1)};
+ return ndk::ScopedAStatus::ok();
+ };
+}
+
} // namespace
-TEST(PreparedModelTest, invalidPreparedModel) {
+TEST_P(PreparedModelTest, invalidPreparedModel) {
// run test
- const auto result = PreparedModel::create(kInvalidPreparedModel);
+ const auto result = PreparedModel::create(kInvalidPreparedModel, kVersion);
// verify result
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, executeSync) {
+TEST_P(PreparedModelTest, executeSync) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup call
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
const auto mockExecutionResult = ExecutionResult{
.outputSufficientSize = true,
.outputShapes = {},
@@ -92,65 +113,73 @@
DoAll(SetArgPointee<4>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
EXPECT_TRUE(result.has_value())
<< "Failed with " << result.error().code << ": " << result.error().message;
}
-TEST(PreparedModelTest, executeSyncError) {
+TEST_P(PreparedModelTest, executeSyncError) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
.Times(1)
.WillOnce(Invoke(makeGeneralFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, executeSyncTransportFailure) {
+TEST_P(PreparedModelTest, executeSyncTransportFailure) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, executeSyncDeadObject) {
+TEST_P(PreparedModelTest, executeSyncDeadObject) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
-TEST(PreparedModelTest, executeFenced) {
+TEST_P(PreparedModelTest, executeFenced) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup call
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
const auto mockCallback = MockFencedExecutionCallback::create();
EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
.Times(1)
@@ -161,7 +190,7 @@
.WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -176,10 +205,12 @@
<< callbackResult.error().message;
}
-TEST(PreparedModelTest, executeFencedCallbackError) {
+TEST_P(PreparedModelTest, executeFencedCallbackError) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup call
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
const auto mockCallback = MockFencedExecutionCallback::create();
EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
.Times(1)
@@ -191,7 +222,7 @@
.WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -206,59 +237,67 @@
EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, executeFencedError) {
+TEST_P(PreparedModelTest, executeFencedError) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralFailure));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, executeFencedTransportFailure) {
+TEST_P(PreparedModelTest, executeFencedTransportFailure) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, executeFencedDeadObject) {
+TEST_P(PreparedModelTest, executeFencedDeadObject) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
-TEST(PreparedModelTest, reusableExecuteSync) {
+TEST_P(PreparedModelTest, reusableExecuteSync) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup call
const uint32_t kNumberOfComputations = 2;
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
const auto mockExecutionResult = ExecutionResult{
.outputSufficientSize = true,
.outputShapes = {},
@@ -270,7 +309,7 @@
DoAll(SetArgPointee<4>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -283,16 +322,18 @@
}
}
-TEST(PreparedModelTest, reusableExecuteSyncError) {
+TEST_P(PreparedModelTest, reusableExecuteSyncError) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
.Times(1)
.WillOnce(Invoke(makeGeneralFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -303,16 +344,18 @@
EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, reusableExecuteSyncTransportFailure) {
+TEST_P(PreparedModelTest, reusableExecuteSyncTransportFailure) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -323,16 +366,18 @@
EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, reusableExecuteSyncDeadObject) {
+TEST_P(PreparedModelTest, reusableExecuteSyncDeadObject) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -343,11 +388,13 @@
EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
-TEST(PreparedModelTest, reusableExecuteFenced) {
+TEST_P(PreparedModelTest, reusableExecuteFenced) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup call
const uint32_t kNumberOfComputations = 2;
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
const auto mockCallback = MockFencedExecutionCallback::create();
EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
.Times(kNumberOfComputations)
@@ -358,7 +405,7 @@
.WillRepeatedly(Invoke(makeFencedExecutionResult(mockCallback)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -379,10 +426,12 @@
}
}
-TEST(PreparedModelTest, reusableExecuteFencedCallbackError) {
+TEST_P(PreparedModelTest, reusableExecuteFencedCallbackError) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup call
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
const auto mockCallback = MockFencedExecutionCallback::create();
EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
.Times(1)
@@ -394,7 +443,7 @@
.WillOnce(Invoke(makeFencedExecutionResult(mockCallback)));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -413,16 +462,18 @@
EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, reusableExecuteFencedError) {
+TEST_P(PreparedModelTest, reusableExecuteFencedError) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -433,16 +484,18 @@
EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, reusableExecuteFencedTransportFailure) {
+TEST_P(PreparedModelTest, reusableExecuteFencedTransportFailure) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -453,16 +506,18 @@
EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, reusableExecuteFencedDeadObject) {
+TEST_P(PreparedModelTest, reusableExecuteFencedDeadObject) {
+ if (kVersion.level >= nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
// create execution
- const auto createResult = preparedModel->createReusableExecution({}, {}, {});
+ const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
ASSERT_TRUE(createResult.has_value())
<< "Failed with " << createResult.error().code << ": " << createResult.error().message;
ASSERT_NE(createResult.value(), nullptr);
@@ -473,14 +528,214 @@
EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
-TEST(PreparedModelTest, configureExecutionBurst) {
+TEST_P(PreparedModelTest, executeSyncWithConfig) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ const auto mockExecutionResult = ExecutionResult{
+ .outputSufficientSize = true,
+ .outputShapes = {},
+ .timing = kNoTiming,
+ };
+ EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+ .Times(1)
+ .WillOnce(
+ DoAll(SetArgPointee<3>(mockExecutionResult), InvokeWithoutArgs(makeStatusOk)));
+
+ // run test
+ const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ EXPECT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+}
+
+TEST_P(PreparedModelTest, executeSyncWithConfigError) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makeGeneralFailure));
+
+ // run test
+ const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeSyncWithConfigTransportFailure) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+ // run test
+ const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeSyncWithConfigDeadObject) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ EXPECT_CALL(*mockPreparedModel, executeSynchronouslyWithConfig(_, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+ // run test
+ const auto result = preparedModel->execute({}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfig) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ const auto mockCallback = MockFencedExecutionCallback::create();
+ EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+ .Times(1)
+ .WillOnce(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+ SetArgPointee<2>(ErrorStatus::NONE), Invoke(makeStatusOk)));
+ EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makeFencedExecutionWithConfigResult(mockCallback)));
+
+ // run test
+ const auto result =
+ preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+ const auto& [syncFence, callback] = result.value();
+ EXPECT_EQ(syncFence.syncWait({}), nn::SyncFence::FenceState::SIGNALED);
+ ASSERT_NE(callback, nullptr);
+
+ // get results from callback
+ const auto callbackResult = callback();
+ ASSERT_TRUE(callbackResult.has_value()) << "Failed with " << callbackResult.error().code << ": "
+ << callbackResult.error().message;
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigCallbackError) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup call
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ const auto mockCallback = MockFencedExecutionCallback::create();
+ EXPECT_CALL(*mockCallback, getExecutionInfo(_, _, _))
+ .Times(1)
+ .WillOnce(Invoke(DoAll(SetArgPointee<0>(kNoTiming), SetArgPointee<1>(kNoTiming),
+ SetArgPointee<2>(ErrorStatus::GENERAL_FAILURE),
+ Invoke(makeStatusOk))));
+ EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(Invoke(makeFencedExecutionWithConfigResult(mockCallback)));
+
+ // run test
+ const auto result =
+ preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+ const auto& [syncFence, callback] = result.value();
+ EXPECT_NE(syncFence.syncWait({}), nn::SyncFence::FenceState::ACTIVE);
+ ASSERT_NE(callback, nullptr);
+
+ // verify callback failure
+ const auto callbackResult = callback();
+ ASSERT_FALSE(callbackResult.has_value());
+ EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigError) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
+
+ // run test
+ const auto result =
+ preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigTransportFailure) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+ // run test
+ const auto result =
+ preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, executeFencedWithConfigDeadObject) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+ EXPECT_CALL(*mockPreparedModel, executeFencedWithConfig(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+ // run test
+ const auto result =
+ preparedModel->executeFenced({}, {}, {}, {}, {}, {}, kHints, kExtensionNameToPrefix);
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(PreparedModelTest, configureExecutionBurst) {
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
const auto mockBurst = ndk::SharedRefBase::make<MockBurst>();
EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
.Times(1)
.WillOnce(DoAll(SetArgPointee<0>(mockBurst), Invoke(makeStatusOk)));
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
// run test
const auto result = preparedModel->configureExecutionBurst();
@@ -491,13 +746,13 @@
EXPECT_NE(result.value(), nullptr);
}
-TEST(PreparedModelTest, configureExecutionBurstError) {
+TEST_P(PreparedModelTest, configureExecutionBurstError) {
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralFailure));
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
// run test
const auto result = preparedModel->configureExecutionBurst();
@@ -507,13 +762,13 @@
EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, configureExecutionBurstTransportFailure) {
+TEST_P(PreparedModelTest, configureExecutionBurstTransportFailure) {
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
// run test
const auto result = preparedModel->configureExecutionBurst();
@@ -523,13 +778,13 @@
EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
}
-TEST(PreparedModelTest, configureExecutionBurstDeadObject) {
+TEST_P(PreparedModelTest, configureExecutionBurstDeadObject) {
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
// run test
const auto result = preparedModel->configureExecutionBurst();
@@ -539,10 +794,84 @@
EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
-TEST(PreparedModelTest, getUnderlyingResource) {
+TEST_P(PreparedModelTest, createReusableExecution) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
// setup test
const auto mockPreparedModel = MockPreparedModel::create();
- const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+ const auto mockExecution = ndk::SharedRefBase::make<MockExecution>();
+ EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+ .Times(1)
+ .WillOnce(DoAll(SetArgPointee<2>(mockExecution), Invoke(makeStatusOk)));
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+ // run test
+ const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+ // verify result
+ ASSERT_TRUE(result.has_value())
+ << "Failed with " << result.error().code << ": " << result.error().message;
+ EXPECT_NE(result.value(), nullptr);
+}
+
+TEST_P(PreparedModelTest, createReusableExecutionError) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+ // run test
+ const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, createReusableExecutionTransportFailure) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+ // run test
+ const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(PreparedModelTest, createReusableExecutionDeadObject) {
+ if (kVersion.level < nn::Version::Level::FEATURE_LEVEL_8) return;
+
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
+
+ // run test
+ const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
+
+ // verify result
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
+
+TEST_P(PreparedModelTest, getUnderlyingResource) {
+ // setup test
+ const auto mockPreparedModel = MockPreparedModel::create();
+ const auto preparedModel = PreparedModel::create(mockPreparedModel, kVersion).value();
// run test
const auto resource = preparedModel->getUnderlyingResource();
@@ -554,4 +883,6 @@
EXPECT_EQ(maybeMock->get(), mockPreparedModel.get());
}
+INSTANTIATE_VERSIONED_AIDL_UTILS_TEST(PreparedModelTest, kAllAidlVersions);
+
} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/TestUtils.cpp b/neuralnetworks/aidl/utils/test/TestUtils.cpp
new file mode 100644
index 0000000..9abec88
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/TestUtils.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "TestUtils.h"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <string>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+std::string printTestVersion(const testing::TestParamInfo<nn::Version>& info) {
+ switch (info.param.level) {
+ case nn::Version::Level::FEATURE_LEVEL_5:
+ return "v1";
+ case nn::Version::Level::FEATURE_LEVEL_6:
+ return "v2";
+ case nn::Version::Level::FEATURE_LEVEL_7:
+ return "v3";
+ case nn::Version::Level::FEATURE_LEVEL_8:
+ return "v4";
+ default:
+ LOG(FATAL) << "Invalid AIDL version: " << info.param;
+ return "invalid";
+ }
+}
+
+} // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/test/TestUtils.h b/neuralnetworks/aidl/utils/test/TestUtils.h
new file mode 100644
index 0000000..23f734a
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/TestUtils.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_TEST_UTILS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_TEST_UTILS_H
+
+#include <gtest/gtest.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <string>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+class VersionedAidlUtilsTestBase : public ::testing::TestWithParam<nn::Version> {
+ protected:
+ const nn::Version kVersion = GetParam();
+};
+
+std::string printTestVersion(const testing::TestParamInfo<nn::Version>& info);
+
+inline const auto kAllAidlVersions =
+ ::testing::Values(nn::kVersionFeatureLevel5, nn::kVersionFeatureLevel6,
+ nn::kVersionFeatureLevel7, nn::kVersionFeatureLevel8);
+
+#define INSTANTIATE_VERSIONED_AIDL_UTILS_TEST(TestSuite, versions) \
+ INSTANTIATE_TEST_SUITE_P(Versioned, TestSuite, versions, printTestVersion)
+
+} // namespace aidl::android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_TEST_UTILS_H
diff --git a/neuralnetworks/aidl/vts/functional/Android.bp b/neuralnetworks/aidl/vts/functional/Android.bp
index 1ed15b8..356cdb0 100644
--- a/neuralnetworks/aidl/vts/functional/Android.bp
+++ b/neuralnetworks/aidl/vts/functional/Android.bp
@@ -30,6 +30,7 @@
"neuralnetworks_vts_functional_defaults",
"use_libaidlvintf_gtest_helper_static",
],
+ host_supported: true,
srcs: [
"BasicTests.cpp",
"Callbacks.cpp",
@@ -46,18 +47,11 @@
],
shared_libs: [
"libbinder_ndk",
- "libnativewindow",
- "libvndksupport",
],
static_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libaidlcommonsupport",
- "libgmock",
- "libhidlmemory",
"libneuralnetworks_common",
"libneuralnetworks_generated_test_harness",
- "libsync",
],
whole_static_libs: [
"neuralnetworks_generated_AIDL_V3_example",
@@ -73,6 +67,34 @@
],
test_suites: [
"general-tests",
- "vts",
],
+ target: {
+ android: {
+ shared_libs: [
+ "libnativewindow",
+ "libvndksupport",
+ ],
+ static_libs: [
+ "libsync",
+ ],
+ test_suites: [
+ "vts",
+ ],
+ test_config: "AndroidTestDevice.xml",
+ },
+ host: {
+ shared_libs: [
+ "libtextclassifier_hash",
+ ],
+ static_libs: [
+ "neuralnetworks_canonical_sample_driver",
+ "neuralnetworks_utils_hal_adapter_aidl",
+ ],
+ exclude_static_libs: [
+ "VtsHalHidlTestUtils",
+ "libaidlvintf_gtest_helper",
+ ],
+ test_config: "AndroidTestHost.xml",
+ },
+ },
}
diff --git a/neuralnetworks/aidl/vts/functional/AndroidTest.xml b/neuralnetworks/aidl/vts/functional/AndroidTestDevice.xml
similarity index 100%
rename from neuralnetworks/aidl/vts/functional/AndroidTest.xml
rename to neuralnetworks/aidl/vts/functional/AndroidTestDevice.xml
diff --git a/neuralnetworks/aidl/vts/functional/AndroidTestHost.xml b/neuralnetworks/aidl/vts/functional/AndroidTestHost.xml
new file mode 100644
index 0000000..7372a31
--- /dev/null
+++ b/neuralnetworks/aidl/vts/functional/AndroidTestHost.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalNeuralnetworksTargetTest.">
+ <test class="com.android.tradefed.testtype.HostGTest" >
+ <option name="module-name" value="VtsHalNeuralnetworksTargetTest" />
+ <option name="native-test-timeout" value="15m" />
+ </test>
+</configuration>
+
diff --git a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
index 77208aa..7451f7e 100644
--- a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
@@ -23,7 +23,6 @@
#include <fcntl.h>
#include <ftw.h>
#include <gtest/gtest.h>
-#include <hidlmemory/mapping.h>
#include <unistd.h>
#include <cstdio>
@@ -34,7 +33,6 @@
#include "Callbacks.h"
#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
#include "TestHarness.h"
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
@@ -229,7 +227,11 @@
// Create cache directory. The cache directory and a temporary cache file is always created
// to test the behavior of prepareModelFromCache, even when caching is not supported.
+#ifdef __ANDROID__
char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX";
+#else // __ANDROID__
+ char cacheDirTemp[] = "/tmp/TestCompilationCachingXXXXXX";
+#endif // __ANDROID__
char* cacheDir = mkdtemp(cacheDirTemp);
ASSERT_NE(cacheDir, nullptr);
mCacheDir = cacheDir;
diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
index f67fd34..40f6cd1 100644
--- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
@@ -20,7 +20,6 @@
#include <aidl/android/hardware/neuralnetworks/RequestMemoryPool.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
-#include <android/sync.h>
#include <gtest/gtest.h>
#include <algorithm>
@@ -30,7 +29,6 @@
#include <numeric>
#include <vector>
-#include <MemoryUtils.h>
#include <android/binder_status.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
@@ -43,6 +41,10 @@
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
+#ifdef __ANDROID__
+#include <android/sync.h>
+#endif // __ANDROID__
+
namespace aidl::android::hardware::neuralnetworks::vts::functional {
namespace nn = ::android::nn;
@@ -58,25 +60,66 @@
bool measureTiming;
OutputType outputType;
MemoryType memoryType;
+ bool reusable;
// `reportSkipping` indicates if a test should print an info message in case
// it is skipped. The field is set to true by default and is set to false in
// quantization coupling tests to suppress skipping a test
bool reportSkipping;
- TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType)
- : executor(executor),
- measureTiming(measureTiming),
- outputType(outputType),
- memoryType(memoryType),
- reportSkipping(true) {}
+ // `useConfig` indicates if a test should use execute*WithConfig functions for the execution.
+ bool useConfig;
TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType,
- bool reportSkipping)
+ bool reusable)
: executor(executor),
measureTiming(measureTiming),
outputType(outputType),
memoryType(memoryType),
- reportSkipping(reportSkipping) {}
+ reusable(reusable),
+ reportSkipping(true),
+ useConfig(false) {}
+ TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType,
+ bool reusable, bool reportSkipping)
+ : executor(executor),
+ measureTiming(measureTiming),
+ outputType(outputType),
+ memoryType(memoryType),
+ reusable(reusable),
+ reportSkipping(reportSkipping),
+ useConfig(false) {}
+ TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType,
+ bool reusable, bool reportSkipping, bool useConfig)
+ : executor(executor),
+ measureTiming(measureTiming),
+ outputType(outputType),
+ memoryType(memoryType),
+ reusable(reusable),
+ reportSkipping(reportSkipping),
+ useConfig(useConfig) {}
};
+std::string toString(OutputType type) {
+ switch (type) {
+ case OutputType::FULLY_SPECIFIED:
+ return "FULLY_SPECIFIED";
+ case OutputType::UNSPECIFIED:
+ return "UNSPECIFIED";
+ case OutputType::INSUFFICIENT:
+ return "INSUFFICIENT";
+ case OutputType::MISSED_DEADLINE:
+ return "MISSED_DEADLINE";
+ }
+}
+
+std::string toString(const TestConfig& config) {
+ std::stringstream ss;
+ ss << "TestConfig{.executor=" << toString(config.executor)
+ << ", .measureTiming=" << (config.measureTiming ? "true" : "false")
+ << ", .outputType=" << toString(config.outputType)
+ << ", .memoryType=" << toString(config.memoryType)
+ << ", .reusable=" << (config.reusable ? "true" : "false")
+ << ", .useConfig=" << (config.useConfig ? "true" : "false") << "}";
+ return ss.str();
+}
+
enum class IOType { INPUT, OUTPUT };
class DeviceMemoryAllocator {
@@ -240,10 +283,14 @@
} // namespace
void waitForSyncFence(int syncFd) {
- constexpr int kInfiniteTimeout = -1;
ASSERT_GT(syncFd, 0);
+#ifdef __ANDROID__
+ constexpr int kInfiniteTimeout = -1;
int r = sync_wait(syncFd, kInfiniteTimeout);
ASSERT_GE(r, 0);
+#else // __ANDROID__
+ LOG(FATAL) << "waitForSyncFence not supported on host";
+#endif // __ANDROID__
}
Model createModel(const TestModel& testModel) {
@@ -558,209 +605,266 @@
loopTimeoutDurationNs = 1 * kMillisecond;
}
- ErrorStatus executionStatus;
- std::vector<OutputShape> outputShapes;
- Timing timing = kNoTiming;
- switch (testConfig.executor) {
- case Executor::SYNC: {
- SCOPED_TRACE("synchronous");
+ std::shared_ptr<IExecution> execution;
+ if (testConfig.reusable) {
+ const auto ret = preparedModel->createReusableExecution(
+ request, {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}}, &execution);
+ ASSERT_TRUE(ret.isOk()) << static_cast<nn::ErrorStatus>(ret.getServiceSpecificError());
+ ASSERT_NE(nullptr, execution.get());
+ }
- ExecutionResult executionResult;
- // execute
- const auto ret = preparedModel->executeSynchronously(request, testConfig.measureTiming,
- kNoDeadline, loopTimeoutDurationNs,
- &executionResult);
- ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
- << ret.getDescription();
- if (ret.isOk()) {
- executionStatus = executionResult.outputSufficientSize
- ? ErrorStatus::NONE
- : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
- outputShapes = std::move(executionResult.outputShapes);
- timing = executionResult.timing;
- } else {
- executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
- }
- break;
- }
- case Executor::BURST: {
- SCOPED_TRACE("burst");
+ const auto executeAndCheckResults = [&preparedModel, &execution, &testConfig, &testModel,
+ &context, &request, loopTimeoutDurationNs, skipped]() {
+ ErrorStatus executionStatus;
+ std::vector<OutputShape> outputShapes;
+ Timing timing = kNoTiming;
+ switch (testConfig.executor) {
+ case Executor::SYNC: {
+ SCOPED_TRACE("synchronous");
- // create burst
- std::shared_ptr<IBurst> burst;
- auto ret = preparedModel->configureExecutionBurst(&burst);
- ASSERT_TRUE(ret.isOk()) << ret.getDescription();
- ASSERT_NE(nullptr, burst.get());
-
- // associate a unique slot with each memory pool
- int64_t currentSlot = 0;
- std::vector<int64_t> slots;
- slots.reserve(request.pools.size());
- for (const auto& pool : request.pools) {
- if (pool.getTag() == RequestMemoryPool::Tag::pool) {
- slots.push_back(currentSlot++);
+ ExecutionResult executionResult;
+ // execute
+ ::ndk::ScopedAStatus ret;
+ if (testConfig.reusable) {
+ ret = execution->executeSynchronously(kNoDeadline, &executionResult);
+ } else if (testConfig.useConfig) {
+ ret = preparedModel->executeSynchronouslyWithConfig(
+ request, {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}},
+ kNoDeadline, &executionResult);
} else {
- EXPECT_EQ(pool.getTag(), RequestMemoryPool::Tag::token);
- slots.push_back(-1);
+ ret = preparedModel->executeSynchronously(request, testConfig.measureTiming,
+ kNoDeadline, loopTimeoutDurationNs,
+ &executionResult);
}
+ ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
+ << ret.getDescription();
+ if (ret.isOk()) {
+ executionStatus = executionResult.outputSufficientSize
+ ? ErrorStatus::NONE
+ : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
+ outputShapes = std::move(executionResult.outputShapes);
+ timing = executionResult.timing;
+ } else {
+ executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
+ }
+ break;
}
+ case Executor::BURST: {
+ SCOPED_TRACE("burst");
- ExecutionResult executionResult;
- // execute
- ret = burst->executeSynchronously(request, slots, testConfig.measureTiming, kNoDeadline,
- loopTimeoutDurationNs, &executionResult);
- ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
- << ret.getDescription();
- if (ret.isOk()) {
- executionStatus = executionResult.outputSufficientSize
- ? ErrorStatus::NONE
- : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
- outputShapes = std::move(executionResult.outputShapes);
- timing = executionResult.timing;
- } else {
- executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
- }
-
- // Mark each slot as unused after the execution. This is unnecessary because the burst
- // is freed after this scope ends, but this is here to test the functionality.
- for (int64_t slot : slots) {
- ret = burst->releaseMemoryResource(slot);
+ // create burst
+ std::shared_ptr<IBurst> burst;
+ auto ret = preparedModel->configureExecutionBurst(&burst);
ASSERT_TRUE(ret.isOk()) << ret.getDescription();
- }
+ ASSERT_NE(nullptr, burst.get());
- break;
- }
- case Executor::FENCED: {
- SCOPED_TRACE("fenced");
- ErrorStatus result = ErrorStatus::NONE;
- FencedExecutionResult executionResult;
- auto ret = preparedModel->executeFenced(request, {}, testConfig.measureTiming,
- kNoDeadline, loopTimeoutDurationNs, kNoDuration,
- &executionResult);
- ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
- << ret.getDescription();
- if (!ret.isOk()) {
- result = static_cast<ErrorStatus>(ret.getServiceSpecificError());
- executionStatus = result;
- } else if (executionResult.syncFence.get() != -1) {
- std::vector<ndk::ScopedFileDescriptor> waitFor;
- auto dupFd = dup(executionResult.syncFence.get());
- ASSERT_NE(dupFd, -1);
- waitFor.emplace_back(dupFd);
- // If a sync fence is returned, try start another run waiting for the sync fence.
- ret = preparedModel->executeFenced(request, waitFor, testConfig.measureTiming,
- kNoDeadline, loopTimeoutDurationNs, kNoDuration,
- &executionResult);
- ASSERT_TRUE(ret.isOk());
- waitForSyncFence(executionResult.syncFence.get());
- }
- if (result == ErrorStatus::NONE) {
- ASSERT_NE(executionResult.callback, nullptr);
- Timing timingFenced;
- auto ret = executionResult.callback->getExecutionInfo(&timing, &timingFenced,
- &executionStatus);
- ASSERT_TRUE(ret.isOk());
- }
- break;
- }
- default: {
- FAIL() << "Unsupported execution mode for AIDL interface.";
- }
- }
-
- if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
- executionStatus == ErrorStatus::GENERAL_FAILURE) {
- if (skipped != nullptr) {
- *skipped = true;
- }
- if (!testConfig.reportSkipping) {
- return;
- }
- LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
- "execute model that it does not support.";
- std::cout << "[ ] Early termination of test because vendor service cannot "
- "execute model that it does not support."
- << std::endl;
- GTEST_SKIP();
- }
- if (!testConfig.measureTiming) {
- EXPECT_EQ(timing, kNoTiming);
- } else {
- if (timing.timeOnDeviceNs != -1 && timing.timeInDriverNs != -1) {
- EXPECT_LE(timing.timeOnDeviceNs, timing.timeInDriverNs);
- }
- }
-
- switch (testConfig.outputType) {
- case OutputType::FULLY_SPECIFIED:
- if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) {
- // Executor::FENCED does not support zero-sized output.
- ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
- return;
- }
- // If the model output operands are fully specified, outputShapes must be either
- // either empty, or have the same number of elements as the number of outputs.
- ASSERT_EQ(ErrorStatus::NONE, executionStatus);
- ASSERT_TRUE(outputShapes.size() == 0 ||
- outputShapes.size() == testModel.main.outputIndexes.size());
- break;
- case OutputType::UNSPECIFIED:
- if (testConfig.executor == Executor::FENCED) {
- // For Executor::FENCED, the output shape must be fully specified.
- ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
- return;
- }
- // If the model output operands are not fully specified, outputShapes must have
- // the same number of elements as the number of outputs.
- ASSERT_EQ(ErrorStatus::NONE, executionStatus);
- ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
- break;
- case OutputType::INSUFFICIENT:
- if (testConfig.executor == Executor::FENCED) {
- // For Executor::FENCED, the output shape must be fully specified.
- ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
- return;
- }
- ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
- ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
- // Check that all returned output dimensions are at least as fully specified as the
- // union of the information about the corresponding operand in the model and in the
- // request. In this test, all model outputs have known rank with all dimensions
- // unspecified, and no dimensional information is provided in the request.
- for (uint32_t i = 0; i < outputShapes.size(); i++) {
- ASSERT_EQ(outputShapes[i].isSufficient, i != kInsufficientOutputIndex);
- const auto& actual = outputShapes[i].dimensions;
- const auto& golden =
- testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
- ASSERT_EQ(actual.size(), golden.size());
- for (uint32_t j = 0; j < actual.size(); j++) {
- if (actual[j] == 0) continue;
- EXPECT_EQ(actual[j], golden[j]) << "index: " << j;
+ // associate a unique slot with each memory pool
+ int64_t currentSlot = 0;
+ std::vector<int64_t> slots;
+ slots.reserve(request.pools.size());
+ for (const auto& pool : request.pools) {
+ if (pool.getTag() == RequestMemoryPool::Tag::pool) {
+ slots.push_back(currentSlot++);
+ } else {
+ EXPECT_EQ(pool.getTag(), RequestMemoryPool::Tag::token);
+ slots.push_back(-1);
+ }
}
+
+ ExecutionResult executionResult;
+ // execute
+ if (testConfig.useConfig) {
+ ret = burst->executeSynchronouslyWithConfig(
+ request, slots,
+ {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}}, kNoDeadline,
+ &executionResult);
+ } else {
+ ret = burst->executeSynchronously(request, slots, testConfig.measureTiming,
+ kNoDeadline, loopTimeoutDurationNs,
+ &executionResult);
+ }
+ ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
+ << ret.getDescription();
+ if (ret.isOk()) {
+ executionStatus = executionResult.outputSufficientSize
+ ? ErrorStatus::NONE
+ : ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
+ outputShapes = std::move(executionResult.outputShapes);
+ timing = executionResult.timing;
+ } else {
+ executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
+ }
+
+ // Mark each slot as unused after the execution. This is unnecessary because the
+ // burst is freed after this scope ends, but this is here to test the functionality.
+ for (int64_t slot : slots) {
+ ret = burst->releaseMemoryResource(slot);
+ ASSERT_TRUE(ret.isOk()) << ret.getDescription();
+ }
+
+ break;
}
- return;
- case OutputType::MISSED_DEADLINE:
- ASSERT_TRUE(executionStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
- executionStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT)
- << "executionStatus = " << executionStatus;
- return;
+ case Executor::FENCED: {
+ SCOPED_TRACE("fenced");
+ ErrorStatus result = ErrorStatus::NONE;
+ FencedExecutionResult executionResult;
+ ::ndk::ScopedAStatus ret;
+ if (testConfig.reusable) {
+ ret = execution->executeFenced({}, kNoDeadline, kNoDuration, &executionResult);
+ } else if (testConfig.useConfig) {
+ ret = preparedModel->executeFencedWithConfig(
+ request, {}, {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}},
+ kNoDeadline, kNoDuration, &executionResult);
+ } else {
+ ret = preparedModel->executeFenced(request, {}, testConfig.measureTiming,
+ kNoDeadline, loopTimeoutDurationNs,
+ kNoDuration, &executionResult);
+ }
+ ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
+ << ret.getDescription();
+ if (!ret.isOk()) {
+ result = static_cast<ErrorStatus>(ret.getServiceSpecificError());
+ executionStatus = result;
+ } else if (executionResult.syncFence.get() != -1) {
+ std::vector<ndk::ScopedFileDescriptor> waitFor;
+ auto dupFd = dup(executionResult.syncFence.get());
+ ASSERT_NE(dupFd, -1);
+ waitFor.emplace_back(dupFd);
+ // If a sync fence is returned, try start another run waiting for the sync
+ // fence.
+ if (testConfig.reusable) {
+ ret = execution->executeFenced(waitFor, kNoDeadline, kNoDuration,
+ &executionResult);
+ } else if (testConfig.useConfig) {
+ ret = preparedModel->executeFencedWithConfig(
+ request, waitFor,
+ {testConfig.measureTiming, loopTimeoutDurationNs, {}, {}},
+ kNoDeadline, kNoDuration, &executionResult);
+ } else {
+ ret = preparedModel->executeFenced(
+ request, waitFor, testConfig.measureTiming, kNoDeadline,
+ loopTimeoutDurationNs, kNoDuration, &executionResult);
+ }
+ ASSERT_TRUE(ret.isOk());
+ waitForSyncFence(executionResult.syncFence.get());
+ }
+ if (result == ErrorStatus::NONE) {
+ ASSERT_NE(executionResult.callback, nullptr);
+ Timing timingFenced;
+ auto ret = executionResult.callback->getExecutionInfo(&timing, &timingFenced,
+ &executionStatus);
+ ASSERT_TRUE(ret.isOk());
+ }
+ break;
+ }
+ default: {
+ FAIL() << "Unsupported execution mode for AIDL interface.";
+ }
+ }
+
+ if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
+ executionStatus == ErrorStatus::GENERAL_FAILURE) {
+ if (skipped != nullptr) {
+ *skipped = true;
+ }
+ if (!testConfig.reportSkipping) {
+ return;
+ }
+ LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+ "execute model that it does not support.";
+ std::cout << "[ ] Early termination of test because vendor service cannot "
+ "execute model that it does not support."
+ << std::endl;
+ GTEST_SKIP();
+ }
+ if (!testConfig.measureTiming) {
+ EXPECT_EQ(timing, kNoTiming);
+ } else {
+ if (timing.timeOnDeviceNs != -1 && timing.timeInDriverNs != -1) {
+ EXPECT_LE(timing.timeOnDeviceNs, timing.timeInDriverNs);
+ }
+ }
+
+ switch (testConfig.outputType) {
+ case OutputType::FULLY_SPECIFIED:
+ if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) {
+ // Executor::FENCED does not support zero-sized output.
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+ return;
+ }
+ // If the model output operands are fully specified, outputShapes must be either
+ // either empty, or have the same number of elements as the number of outputs.
+ ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+ ASSERT_TRUE(outputShapes.size() == 0 ||
+ outputShapes.size() == testModel.main.outputIndexes.size());
+ break;
+ case OutputType::UNSPECIFIED:
+ if (testConfig.executor == Executor::FENCED) {
+ // For Executor::FENCED, the output shape must be fully specified.
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+ return;
+ }
+ // If the model output operands are not fully specified, outputShapes must have
+ // the same number of elements as the number of outputs.
+ ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+ ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
+ break;
+ case OutputType::INSUFFICIENT:
+ if (testConfig.executor == Executor::FENCED) {
+ // For Executor::FENCED, the output shape must be fully specified.
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+ return;
+ }
+ ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
+ ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
+ // Check that all returned output dimensions are at least as fully specified as the
+ // union of the information about the corresponding operand in the model and in the
+ // request. In this test, all model outputs have known rank with all dimensions
+ // unspecified, and no dimensional information is provided in the request.
+ for (uint32_t i = 0; i < outputShapes.size(); i++) {
+ ASSERT_EQ(outputShapes[i].isSufficient, i != kInsufficientOutputIndex);
+ const auto& actual = outputShapes[i].dimensions;
+ const auto& golden =
+ testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
+ ASSERT_EQ(actual.size(), golden.size());
+ for (uint32_t j = 0; j < actual.size(); j++) {
+ if (actual[j] == 0) continue;
+ EXPECT_EQ(actual[j], golden[j]) << "index: " << j;
+ }
+ }
+ return;
+ case OutputType::MISSED_DEADLINE:
+ ASSERT_TRUE(executionStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+ executionStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT)
+ << "executionStatus = " << executionStatus;
+ return;
+ }
+
+ // Go through all outputs, check returned output shapes.
+ for (uint32_t i = 0; i < outputShapes.size(); i++) {
+ EXPECT_TRUE(outputShapes[i].isSufficient);
+ const auto& expect =
+ testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
+ const auto unsignedActual = nn::toUnsigned(outputShapes[i].dimensions);
+ ASSERT_TRUE(unsignedActual.has_value());
+ const std::vector<uint32_t>& actual = unsignedActual.value();
+ EXPECT_EQ(expect, actual);
+ }
+
+ // Retrieve execution results.
+ const std::vector<TestBuffer> outputs = context.getOutputBuffers(testModel, request);
+
+ // We want "close-enough" results.
+ checkResults(testModel, outputs);
+ };
+
+ executeAndCheckResults();
+
+ // For reusable execution tests, run the execution twice.
+ if (testConfig.reusable) {
+ SCOPED_TRACE("Second execution");
+ executeAndCheckResults();
}
-
- // Go through all outputs, check returned output shapes.
- for (uint32_t i = 0; i < outputShapes.size(); i++) {
- EXPECT_TRUE(outputShapes[i].isSufficient);
- const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
- const auto unsignedActual = nn::toUnsigned(outputShapes[i].dimensions);
- ASSERT_TRUE(unsignedActual.has_value());
- const std::vector<uint32_t>& actual = unsignedActual.value();
- EXPECT_EQ(expect, actual);
- }
-
- // Retrieve execution results.
- const std::vector<TestBuffer> outputs = context.getOutputBuffers(testModel, request);
-
- // We want "close-enough" results.
- checkResults(testModel, outputs);
}
void EvaluatePreparedModel(const std::shared_ptr<IDevice>& device,
@@ -770,6 +874,15 @@
std::vector<bool> measureTimingList;
std::vector<Executor> executorList;
std::vector<MemoryType> memoryTypeList;
+ std::vector<bool> reusableList = {false};
+ std::vector<bool> useConfigList = {false};
+
+ int deviceVersion;
+ ASSERT_TRUE(device->getInterfaceVersion(&deviceVersion).isOk());
+ if (deviceVersion >= kMinAidlLevelForFL8) {
+ reusableList.push_back(true);
+ useConfigList.push_back(true);
+ }
switch (testKind) {
case TestKind::GENERAL: {
@@ -788,7 +901,11 @@
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {false};
executorList = {Executor::SYNC, Executor::BURST, Executor::FENCED};
+#ifdef __ANDROID__
memoryTypeList = {MemoryType::BLOB_AHWB, MemoryType::DEVICE};
+#else // __ANDROID__
+ memoryTypeList = {MemoryType::DEVICE}; // BLOB_AHWB is not supported on the host.
+#endif // __ANDROID__
} break;
case TestKind::FENCED_COMPUTE: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
@@ -812,8 +929,16 @@
for (const bool measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
for (const MemoryType memoryType : memoryTypeList) {
- const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
- EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+ for (const bool reusable : reusableList) {
+ for (const bool useConfig : useConfigList) {
+ if ((useConfig || executor == Executor::BURST) && reusable) continue;
+ const TestConfig testConfig(executor, measureTiming, outputType,
+ memoryType, reusable,
+ /*reportSkipping=*/true, useConfig);
+ SCOPED_TRACE(toString(testConfig));
+ EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+ }
+ }
}
}
}
@@ -833,7 +958,7 @@
for (const bool measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::ASHMEM,
- /*reportSkipping=*/false);
+ /*reusable=*/false, /*reportSkipping=*/false);
bool baseSkipped = false;
EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped);
bool coupledSkipped = false;
@@ -871,6 +996,13 @@
createPreparedModel(device, model, &preparedModel);
if (preparedModel == nullptr) return;
EvaluatePreparedModel(device, preparedModel, testModel, testKind);
+ int32_t deviceVersion;
+ ASSERT_TRUE(device->getInterfaceVersion(&deviceVersion).isOk());
+ if (deviceVersion >= kMinAidlLevelForFL8) {
+ createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ true,
+ /*useConfig*/ true);
+ EvaluatePreparedModel(device, preparedModel, testModel, testKind);
+ }
} break;
case TestKind::QUANTIZATION_COUPLING: {
ASSERT_TRUE(testModel.hasQuant8CoupledOperands());
diff --git a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
index cd5475c..f8341b1 100644
--- a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "neuralnetworks_aidl_hal_test"
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidl/android/hardware/neuralnetworks/IPreparedModel.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
@@ -33,7 +34,6 @@
#include "Callbacks.h"
#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
@@ -191,7 +191,7 @@
}
// A placeholder invalid IPreparedModel class for MemoryDomainAllocateTest.InvalidPreparedModel
-class InvalidPreparedModel : public BnPreparedModel {
+class InvalidPreparedModel final : public IPreparedModel {
public:
ndk::ScopedAStatus executeSynchronously(const Request&, bool, int64_t, int64_t,
ExecutionResult*) override {
@@ -204,10 +204,37 @@
return ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
}
+ ndk::ScopedAStatus executeSynchronouslyWithConfig(const Request&, const ExecutionConfig&,
+ int64_t, ExecutionResult*) override {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+ }
+ ndk::ScopedAStatus executeFencedWithConfig(const Request&,
+ const std::vector<ndk::ScopedFileDescriptor>&,
+ const ExecutionConfig&, int64_t, int64_t,
+ FencedExecutionResult*) override {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+ }
ndk::ScopedAStatus configureExecutionBurst(std::shared_ptr<IBurst>*) override {
return ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
}
+ ndk::ScopedAStatus createReusableExecution(const aidl_hal::Request&, const ExecutionConfig&,
+ std::shared_ptr<aidl_hal::IExecution>*) override {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+ }
+ ndk::ScopedAStatus getInterfaceVersion(int32_t* /*interfaceVersion*/) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+ }
+ ndk::ScopedAStatus getInterfaceHash(std::string* /*interfaceHash*/) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(ErrorStatus::GENERAL_FAILURE));
+ }
+ ndk::SpAIBinder asBinder() override { return ::ndk::SpAIBinder{}; }
+ bool isRemote() override { return true; }
};
template <typename... Args>
diff --git a/neuralnetworks/aidl/vts/functional/Utils.cpp b/neuralnetworks/aidl/vts/functional/Utils.cpp
index 325a436..1bc76f2 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.cpp
+++ b/neuralnetworks/aidl/vts/functional/Utils.cpp
@@ -21,18 +21,20 @@
#include <aidl/android/hardware/neuralnetworks/OperandType.h>
#include <android-base/logging.h>
#include <android/binder_status.h>
-#include <android/hardware_buffer.h>
#include <sys/mman.h>
#include <iostream>
#include <limits>
#include <numeric>
-#include <MemoryUtils.h>
#include <nnapi/SharedMemory.h>
#include <nnapi/hal/aidl/Conversions.h>
#include <nnapi/hal/aidl/Utils.h>
+#ifdef __ANDROID__
+#include <android/hardware_buffer.h>
+#endif // __ANDROID__
+
namespace aidl::android::hardware::neuralnetworks {
using test_helper::TestBuffer;
@@ -140,7 +142,8 @@
return ahwb->mIsValid ? std::move(ahwb) : nullptr;
}
-void TestBlobAHWB::initialize(uint32_t size) {
+void TestBlobAHWB::initialize([[maybe_unused]] uint32_t size) {
+#ifdef __ANDROID__
mIsValid = false;
ASSERT_GT(size, 0);
const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
@@ -164,6 +167,9 @@
mAidlMemory = utils::convert(mMemory).value();
mIsValid = true;
+#else // __ANDROID__
+ LOG(FATAL) << "TestBlobAHWB::initialize not supported on host";
+#endif // __ANDROID__
}
std::string gtestCompliantName(std::string name) {
@@ -177,6 +183,17 @@
return os << toString(errorStatus);
}
+std::string toString(MemoryType type) {
+ switch (type) {
+ case MemoryType::ASHMEM:
+ return "ASHMEM";
+ case MemoryType::BLOB_AHWB:
+ return "BLOB_AHWB";
+ case MemoryType::DEVICE:
+ return "DEVICE";
+ }
+}
+
Request ExecutionContext::createRequest(const TestModel& testModel, MemoryType memoryType) {
CHECK(memoryType == MemoryType::ASHMEM || memoryType == MemoryType::BLOB_AHWB);
diff --git a/neuralnetworks/aidl/vts/functional/Utils.h b/neuralnetworks/aidl/vts/functional/Utils.h
index ca81418..4e0a4aa 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.h
+++ b/neuralnetworks/aidl/vts/functional/Utils.h
@@ -18,7 +18,6 @@
#define ANDROID_HARDWARE_NEURALNETWORKS_AIDL_UTILS_H
#include <android-base/logging.h>
-#include <android/hardware_buffer.h>
#include <gtest/gtest.h>
#include <algorithm>
@@ -111,6 +110,8 @@
enum class MemoryType { ASHMEM, BLOB_AHWB, DEVICE };
+std::string toString(MemoryType type);
+
// Manages the lifetime of memory resources used in an execution.
class ExecutionContext {
DISALLOW_COPY_AND_ASSIGN(ExecutionContext);
diff --git a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
index fdc7eff..931ba25 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
@@ -77,6 +77,28 @@
ASSERT_EQ(nullptr, preparedModel.get());
}
+static void validatePrepareModelWithConfig(const std::shared_ptr<IDevice>& device,
+ const std::string& message, const Model& model,
+ ExecutionPreference preference, Priority priority) {
+ SCOPED_TRACE(message + " [prepareModelWithConfig]");
+
+ std::shared_ptr<PreparedModelCallback> preparedModelCallback =
+ ndk::SharedRefBase::make<PreparedModelCallback>();
+ const auto prepareLaunchStatus = device->prepareModelWithConfig(
+ model, {preference, priority, kNoDeadline, {}, {}, kEmptyCacheToken, {}, {}},
+ preparedModelCallback);
+ ASSERT_FALSE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(prepareLaunchStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+ ASSERT_EQ(static_cast<ErrorStatus>(prepareLaunchStatus.getServiceSpecificError()),
+ ErrorStatus::INVALID_ARGUMENT);
+
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
+ std::shared_ptr<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+ ASSERT_EQ(nullptr, preparedModel.get());
+}
+
static bool validExecutionPreference(ExecutionPreference preference) {
return preference == ExecutionPreference::LOW_POWER ||
preference == ExecutionPreference::FAST_SINGLE_ANSWER ||
@@ -103,6 +125,13 @@
}
validatePrepareModel(device, message, model, preference, priority);
+
+ int32_t aidlVersion;
+ ASSERT_TRUE(device->getInterfaceVersion(&aidlVersion).isOk());
+ if (aidlVersion >= kMinAidlLevelForFL8) {
+ // prepareModelWithConfig must satisfy all requirements enforced by prepareModel.
+ validatePrepareModelWithConfig(device, message, model, preference, priority);
+ }
}
static uint32_t addOperand(Model* model) {
diff --git a/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp b/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp
index 29e2471..d749841 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateRequest.cpp
@@ -36,6 +36,51 @@
///////////////////////// UTILITY FUNCTIONS /////////////////////////
+// Test request validation with reusable execution.
+static void validateReusableExecution(const std::shared_ptr<IPreparedModel>& preparedModel,
+ const std::string& message, const Request& request,
+ bool measure) {
+ // createReusableExecution
+ std::shared_ptr<IExecution> execution;
+ {
+ SCOPED_TRACE(message + " [createReusableExecution]");
+ const auto createStatus = preparedModel->createReusableExecution(
+ request, {measure, kOmittedTimeoutDuration, {}, {}}, &execution);
+ if (!createStatus.isOk()) {
+ ASSERT_EQ(createStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+ ASSERT_EQ(static_cast<ErrorStatus>(createStatus.getServiceSpecificError()),
+ ErrorStatus::INVALID_ARGUMENT);
+ ASSERT_EQ(nullptr, execution);
+ return;
+ } else {
+ ASSERT_NE(nullptr, execution);
+ }
+ }
+
+ // synchronous
+ {
+ SCOPED_TRACE(message + " [executeSynchronously]");
+ ExecutionResult executionResult;
+ const auto executeStatus = execution->executeSynchronously(kNoDeadline, &executionResult);
+ ASSERT_FALSE(executeStatus.isOk());
+ ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+ ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+ ErrorStatus::INVALID_ARGUMENT);
+ }
+
+ // fenced
+ {
+ SCOPED_TRACE(message + " [executeFenced]");
+ FencedExecutionResult executionResult;
+ const auto executeStatus =
+ execution->executeFenced({}, kNoDeadline, kNoDuration, &executionResult);
+ ASSERT_FALSE(executeStatus.isOk());
+ ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+ ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+ ErrorStatus::INVALID_ARGUMENT);
+ }
+}
+
// Primary validation function. This function will take a valid request, apply a
// mutation to it to invalidate the request, then pass it to interface calls
// that use the request.
@@ -101,6 +146,63 @@
ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
ErrorStatus::INVALID_ARGUMENT);
}
+
+ int32_t aidlVersion;
+ ASSERT_TRUE(preparedModel->getInterfaceVersion(&aidlVersion).isOk());
+ if (aidlVersion < kMinAidlLevelForFL8) {
+ return;
+ }
+
+ // validate reusable execution
+ validateReusableExecution(preparedModel, message, request, measure);
+
+ // synchronous with empty hints
+ {
+ SCOPED_TRACE(message + " [executeSynchronouslyWithConfig]");
+ ExecutionResult executionResult;
+ const auto executeStatus = preparedModel->executeSynchronouslyWithConfig(
+ request, {measure, kOmittedTimeoutDuration, {}, {}}, kNoDeadline, &executionResult);
+ ASSERT_FALSE(executeStatus.isOk());
+ ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+ ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+ ErrorStatus::INVALID_ARGUMENT);
+ }
+
+ // fenced with empty hints
+ {
+ SCOPED_TRACE(message + " [executeFencedWithConfig]");
+ FencedExecutionResult executionResult;
+ const auto executeStatus = preparedModel->executeFencedWithConfig(
+ request, {}, {false, kOmittedTimeoutDuration, {}, {}}, kNoDeadline, kNoDuration,
+ &executionResult);
+ ASSERT_FALSE(executeStatus.isOk());
+ ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+ ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+ ErrorStatus::INVALID_ARGUMENT);
+ }
+
+ // burst with empty hints
+ {
+ SCOPED_TRACE(message + " [burst executeSynchronouslyWithConfig]");
+
+ // create burst
+ std::shared_ptr<IBurst> burst;
+ auto ret = preparedModel->configureExecutionBurst(&burst);
+ ASSERT_TRUE(ret.isOk()) << ret.getDescription();
+ ASSERT_NE(nullptr, burst.get());
+
+ // use -1 for all memory identifier tokens
+ const std::vector<int64_t> slots(request.pools.size(), -1);
+
+ ExecutionResult executionResult;
+ const auto executeStatus = burst->executeSynchronouslyWithConfig(
+ request, slots, {measure, kOmittedTimeoutDuration, {}, {}}, kNoDeadline,
+ &executionResult);
+ ASSERT_FALSE(executeStatus.isOk());
+ ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
+ ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
+ ErrorStatus::INVALID_ARGUMENT);
+ }
}
std::shared_ptr<IBurst> createBurst(const std::shared_ptr<IPreparedModel>& preparedModel) {
diff --git a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
index c417356..51b4805 100644
--- a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "neuralnetworks_aidl_hal_test"
+
#include "VtsHalNeuralnetworks.h"
#include <android-base/logging.h>
@@ -28,20 +29,27 @@
#include <utility>
#include <TestHarness.h>
-#include <aidl/Vintf.h>
#include <nnapi/hal/aidl/Conversions.h>
#include "Callbacks.h"
#include "GeneratedTestHarness.h"
#include "Utils.h"
+#ifdef __ANDROID__
+#include <aidl/Vintf.h>
+#else // __ANDROID__
+#include <CanonicalDevice.h>
+#include <nnapi/hal/aidl/Adapter.h>
+#endif // __ANDROID__
+
namespace aidl::android::hardware::neuralnetworks::vts::functional {
using implementation::PreparedModelCallback;
// internal helper function
void createPreparedModel(const std::shared_ptr<IDevice>& device, const Model& model,
- std::shared_ptr<IPreparedModel>* preparedModel, bool reportSkipping) {
+ std::shared_ptr<IPreparedModel>* preparedModel, bool reportSkipping,
+ bool useConfig) {
ASSERT_NE(nullptr, preparedModel);
*preparedModel = nullptr;
@@ -56,11 +64,25 @@
// launch prepare model
const std::shared_ptr<PreparedModelCallback> preparedModelCallback =
ndk::SharedRefBase::make<PreparedModelCallback>();
- const auto prepareLaunchStatus =
- device->prepareModel(model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority,
- kNoDeadline, {}, {}, kEmptyCacheToken, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk()) << prepareLaunchStatus.getDescription();
-
+ if (useConfig) {
+ const auto prepareLaunchStatus =
+ device->prepareModelWithConfig(model,
+ {ExecutionPreference::FAST_SINGLE_ANSWER,
+ kDefaultPriority,
+ kNoDeadline,
+ {},
+ {},
+ kEmptyCacheToken,
+ {},
+ {}},
+ preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk()) << prepareLaunchStatus.getDescription();
+ } else {
+ const auto prepareLaunchStatus = device->prepareModel(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, kNoDeadline, {},
+ {}, kEmptyCacheToken, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk()) << prepareLaunchStatus.getDescription();
+ }
// retrieve prepared model
preparedModelCallback->wait();
const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
@@ -96,6 +118,7 @@
ASSERT_TRUE(deviceIsResponsive);
}
+#ifdef __ANDROID__
static NamedDevice makeNamedDevice(const std::string& name) {
ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
return {name, IDevice::fromBinder(binder)};
@@ -112,6 +135,14 @@
std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
return namedDevices;
}
+#else // __ANDROID__
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+ const std::string name = "nnapi-sample";
+ auto device = std::make_shared<const ::android::nn::sample::Device>(name);
+ auto aidlDevice = adapter::adapt(device);
+ return {{name, aidlDevice}};
+}
+#endif // __ANDROID__
const std::vector<NamedDevice>& getNamedDevices() {
const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
diff --git a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h
index 4312d3a..00d705c 100644
--- a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.h
@@ -30,6 +30,8 @@
using NamedDevice = Named<std::shared_ptr<IDevice>>;
using NeuralNetworksAidlTestParam = NamedDevice;
+constexpr int kMinAidlLevelForFL8 = 4;
+
class NeuralNetworksAidlTest : public testing::TestWithParam<NeuralNetworksAidlTestParam> {
protected:
void SetUp() override;
@@ -49,8 +51,8 @@
// Create an IPreparedModel object. If the model cannot be prepared,
// "preparedModel" will be nullptr instead.
void createPreparedModel(const std::shared_ptr<IDevice>& device, const Model& model,
- std::shared_ptr<IPreparedModel>* preparedModel,
- bool reportSkipping = true);
+ std::shared_ptr<IPreparedModel>* preparedModel, bool reportSkipping = true,
+ bool useConfig = false);
enum class Executor { SYNC, BURST, FENCED };
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Burst.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Burst.h
index f2687c4..8d42e2f 100644
--- a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Burst.h
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Burst.h
@@ -46,6 +46,11 @@
bool measureTiming, int64_t deadlineNs,
int64_t loopTimeoutDurationNs,
ExecutionResult* executionResult) override;
+ ndk::ScopedAStatus executeSynchronouslyWithConfig(
+ const Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
+ const ExecutionConfig& config, int64_t deadlineNs,
+ ExecutionResult* executionResult) override;
+
ndk::ScopedAStatus releaseMemoryResource(int64_t memoryIdentifierToken) override;
class ThreadSafeMemoryCache {
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Device.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Device.h
index aa29d63..c94f270 100644
--- a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Device.h
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Device.h
@@ -31,6 +31,7 @@
#include <aidl/android/hardware/neuralnetworks/IPreparedModelParcel.h>
#include <aidl/android/hardware/neuralnetworks/Model.h>
#include <aidl/android/hardware/neuralnetworks/NumberOfCacheFiles.h>
+#include <aidl/android/hardware/neuralnetworks/PrepareModelConfig.h>
#include <aidl/android/hardware/neuralnetworks/Priority.h>
#include <android/binder_auto_utils.h>
#include <nnapi/IDevice.h>
@@ -72,6 +73,9 @@
const std::vector<ndk::ScopedFileDescriptor>& dataCache,
const std::vector<uint8_t>& token,
const std::shared_ptr<IPreparedModelCallback>& callback) override;
+ ndk::ScopedAStatus prepareModelWithConfig(
+ const Model& model, const PrepareModelConfig& config,
+ const std::shared_ptr<IPreparedModelCallback>& callback) override;
protected:
const ::android::nn::SharedDevice kDevice;
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Execution.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Execution.h
new file mode 100644
index 0000000..6a9ac57
--- /dev/null
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Execution.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_EXECUTION_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_EXECUTION_H
+
+#include "nnapi/hal/aidl/Adapter.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnExecution.h>
+#include <aidl/android/hardware/neuralnetworks/ExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/FencedExecutionResult.h>
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
+#include <aidl/android/hardware/neuralnetworks/Request.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IExecution.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <vector>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::adapter {
+
+// Class that adapts nn::IExecution to BnExecution.
+class Execution : public BnExecution {
+ public:
+ explicit Execution(::android::nn::SharedExecution execution);
+
+ ndk::ScopedAStatus executeSynchronously(int64_t deadlineNs,
+ ExecutionResult* executionResult) override;
+ ndk::ScopedAStatus executeFenced(const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+ int64_t deadlineNs, int64_t durationNs,
+ FencedExecutionResult* fencedExecutionResult) override;
+
+ protected:
+ const ::android::nn::SharedExecution kExecution;
+};
+
+} // namespace aidl::android::hardware::neuralnetworks::adapter
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_ADAPTER_AIDL_EXECUTION_H
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/PreparedModel.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/PreparedModel.h
index 93e0427..d1359d6 100644
--- a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/PreparedModel.h
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/PreparedModel.h
@@ -23,6 +23,7 @@
#include <aidl/android/hardware/neuralnetworks/ExecutionResult.h>
#include <aidl/android/hardware/neuralnetworks/FencedExecutionResult.h>
#include <aidl/android/hardware/neuralnetworks/IBurst.h>
+#include <aidl/android/hardware/neuralnetworks/IExecution.h>
#include <aidl/android/hardware/neuralnetworks/Request.h>
#include <android/binder_auto_utils.h>
#include <nnapi/IPreparedModel.h>
@@ -50,6 +51,17 @@
int64_t loopTimeoutDurationNs, int64_t durationNs,
FencedExecutionResult* executionResult) override;
ndk::ScopedAStatus configureExecutionBurst(std::shared_ptr<IBurst>* burst) override;
+ ndk::ScopedAStatus createReusableExecution(const Request& request,
+ const ExecutionConfig& config,
+ std::shared_ptr<IExecution>* execution) override;
+ ndk::ScopedAStatus executeSynchronouslyWithConfig(const Request& request,
+ const ExecutionConfig& config,
+ int64_t deadlineNs,
+ ExecutionResult* executionResult) override;
+ ndk::ScopedAStatus executeFencedWithConfig(
+ const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+ const ExecutionConfig& config, int64_t deadlineNs, int64_t durationNs,
+ FencedExecutionResult* executionResult) override;
::android::nn::SharedPreparedModel getUnderlyingPreparedModel() const;
diff --git a/neuralnetworks/utils/adapter/aidl/src/Burst.cpp b/neuralnetworks/utils/adapter/aidl/src/Burst.cpp
index 4fabb20..a4a80fa 100644
--- a/neuralnetworks/utils/adapter/aidl/src/Burst.cpp
+++ b/neuralnetworks/utils/adapter/aidl/src/Burst.cpp
@@ -93,7 +93,8 @@
nn::ExecutionResult<ExecutionResult> executeSynchronously(
const nn::IBurst& burst, const Burst::ThreadSafeMemoryCache& cache, const Request& request,
const std::vector<int64_t>& memoryIdentifierTokens, bool measureTiming, int64_t deadlineNs,
- int64_t loopTimeoutDurationNs) {
+ int64_t loopTimeoutDurationNs, const std::vector<TokenValuePair>& hints,
+ const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
if (request.pools.size() != memoryIdentifierTokens.size()) {
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
<< "request.pools.size() != memoryIdentifierTokens.size()";
@@ -107,11 +108,13 @@
const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
+ auto nnHints = NN_TRY(convertInput(hints));
+ auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
const auto hold = ensureAllMemoriesAreCached(&nnRequest, memoryIdentifierTokens, burst, cache);
- const auto result =
- burst.execute(nnRequest, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration);
+ const auto result = burst.execute(nnRequest, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration,
+ nnHints, nnExtensionNameToPrefix);
if (!result.ok() && result.error().code == nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
const auto& [message, code, outputShapes] = result.error();
@@ -155,7 +158,24 @@
ExecutionResult* executionResult) {
auto result =
adapter::executeSynchronously(*kBurst, kMemoryCache, request, memoryIdentifierTokens,
- measureTiming, deadlineNs, loopTimeoutDurationNs);
+ measureTiming, deadlineNs, loopTimeoutDurationNs, {}, {});
+ if (!result.has_value()) {
+ auto [message, code, _] = std::move(result).error();
+ const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(aidlCode), message.c_str());
+ }
+ *executionResult = std::move(result).value();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Burst::executeSynchronouslyWithConfig(
+ const Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
+ const ExecutionConfig& config, int64_t deadlineNs, ExecutionResult* executionResult) {
+ auto result = adapter::executeSynchronously(
+ *kBurst, kMemoryCache, request, memoryIdentifierTokens, config.measureTiming,
+ deadlineNs, config.loopTimeoutDurationNs, config.executionHints,
+ config.extensionNameToPrefix);
if (!result.has_value()) {
auto [message, code, _] = std::move(result).error();
const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
diff --git a/neuralnetworks/utils/adapter/aidl/src/Device.cpp b/neuralnetworks/utils/adapter/aidl/src/Device.cpp
index 763be7f..84aaddb 100644
--- a/neuralnetworks/utils/adapter/aidl/src/Device.cpp
+++ b/neuralnetworks/utils/adapter/aidl/src/Device.cpp
@@ -148,13 +148,14 @@
}
}
-nn::GeneralResult<void> prepareModel(const nn::SharedDevice& device, const Executor& executor,
- const Model& model, ExecutionPreference preference,
- Priority priority, int64_t deadlineNs,
- const std::vector<ndk::ScopedFileDescriptor>& modelCache,
- const std::vector<ndk::ScopedFileDescriptor>& dataCache,
- const std::vector<uint8_t>& token,
- const std::shared_ptr<IPreparedModelCallback>& callback) {
+nn::GeneralResult<void> prepareModel(
+ const nn::SharedDevice& device, const Executor& executor, const Model& model,
+ ExecutionPreference preference, Priority priority, int64_t deadlineNs,
+ const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+ const std::vector<ndk::ScopedFileDescriptor>& dataCache, const std::vector<uint8_t>& token,
+ const std::vector<TokenValuePair>& hints,
+ const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix,
+ const std::shared_ptr<IPreparedModelCallback>& callback) {
if (callback.get() == nullptr) {
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
}
@@ -166,12 +167,16 @@
auto nnModelCache = NN_TRY(convertInput(modelCache));
auto nnDataCache = NN_TRY(convertInput(dataCache));
const auto nnToken = NN_TRY(convertCacheToken(token));
+ auto nnHints = NN_TRY(convertInput(hints));
+ auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
- nnToken, callback] {
- auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
- nnModelCache, nnDataCache, nnToken);
+ nnToken, nnHints = std::move(nnHints),
+ nnExtensionNameToPrefix = std::move(nnExtensionNameToPrefix), callback] {
+ auto result =
+ device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline, nnModelCache,
+ nnDataCache, nnToken, nnHints, nnExtensionNameToPrefix);
notify(callback.get(), std::move(result));
};
executor(std::move(task), nnDeadline);
@@ -273,8 +278,9 @@
const std::vector<ndk::ScopedFileDescriptor>& dataCache,
const std::vector<uint8_t>& token,
const std::shared_ptr<IPreparedModelCallback>& callback) {
- const auto result = adapter::prepareModel(kDevice, kExecutor, model, preference, priority,
- deadlineNs, modelCache, dataCache, token, callback);
+ const auto result =
+ adapter::prepareModel(kDevice, kExecutor, model, preference, priority, deadlineNs,
+ modelCache, dataCache, token, {}, {}, callback);
if (!result.has_value()) {
const auto& [message, code] = result.error();
const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
@@ -301,4 +307,21 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Device::prepareModelWithConfig(
+ const Model& model, const PrepareModelConfig& config,
+ const std::shared_ptr<IPreparedModelCallback>& callback) {
+ const auto result = adapter::prepareModel(
+ kDevice, kExecutor, model, config.preference, config.priority, config.deadlineNs,
+ config.modelCache, config.dataCache, config.cacheToken, config.compilationHints,
+ config.extensionNameToPrefix, callback);
+ if (!result.has_value()) {
+ const auto& [message, code] = result.error();
+ const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+ callback->notify(aidlCode, nullptr);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(aidlCode), message.c_str());
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/aidl/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/aidl/src/PreparedModel.cpp
index 71ed1a8..790558f 100644
--- a/neuralnetworks/utils/adapter/aidl/src/PreparedModel.cpp
+++ b/neuralnetworks/utils/adapter/aidl/src/PreparedModel.cpp
@@ -17,6 +17,7 @@
#include "PreparedModel.h"
#include "Burst.h"
+#include "Execution.h"
#include <aidl/android/hardware/neuralnetworks/BnFencedExecutionCallback.h>
#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
@@ -26,6 +27,7 @@
#include <aidl/android/hardware/neuralnetworks/Request.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
+#include <nnapi/IExecution.h>
#include <nnapi/IPreparedModel.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
@@ -116,17 +118,20 @@
return durationNs < 0 ? nn::OptionalTimePoint{} : nn::TimePoint(makeDuration(durationNs));
}
-nn::ExecutionResult<ExecutionResult> executeSynchronously(const nn::IPreparedModel& preparedModel,
- const Request& request,
- bool measureTiming, int64_t deadlineNs,
- int64_t loopTimeoutDurationNs) {
+nn::ExecutionResult<ExecutionResult> executeSynchronously(
+ const nn::IPreparedModel& preparedModel, const Request& request, bool measureTiming,
+ int64_t deadlineNs, int64_t loopTimeoutDurationNs, const std::vector<TokenValuePair>& hints,
+ const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
const auto nnRequest = NN_TRY(convertInput(request));
const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
+ auto nnHints = NN_TRY(convertInput(hints));
+ auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
const auto result =
- preparedModel.execute(nnRequest, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration);
+ preparedModel.execute(nnRequest, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration,
+ nnHints, nnExtensionNameToPrefix);
if (!result.ok() && result.error().code == nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
const auto& [message, code, outputShapes] = result.error();
@@ -145,16 +150,76 @@
nn::GeneralResult<FencedExecutionResult> executeFenced(
const nn::IPreparedModel& preparedModel, const Request& request,
const std::vector<ndk::ScopedFileDescriptor>& waitFor, bool measureTiming,
- int64_t deadlineNs, int64_t loopTimeoutDurationNs, int64_t durationNs) {
+ int64_t deadlineNs, int64_t loopTimeoutDurationNs, int64_t durationNs,
+ const std::vector<TokenValuePair>& hints,
+ const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
const auto nnRequest = NN_TRY(convertInput(request));
const auto nnWaitFor = NN_TRY(convertSyncFences(waitFor));
const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
const auto nnDuration = NN_TRY(makeOptionalDuration(durationNs));
+ auto nnHints = NN_TRY(convertInput(hints));
+ auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
auto [syncFence, executeFencedInfoCallback] = NN_TRY(preparedModel.executeFenced(
- nnRequest, nnWaitFor, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration, nnDuration));
+ nnRequest, nnWaitFor, nnMeasureTiming, nnDeadline, nnLoopTimeoutDuration, nnDuration,
+ nnHints, nnExtensionNameToPrefix));
+
+ ndk::ScopedFileDescriptor fileDescriptor;
+ if (syncFence.hasFd()) {
+ auto uniqueFd = NN_TRY(nn::dupFd(syncFence.getFd()));
+ fileDescriptor = ndk::ScopedFileDescriptor(uniqueFd.release());
+ }
+
+ return FencedExecutionResult{.callback = ndk::SharedRefBase::make<FencedExecutionCallback>(
+ std::move(executeFencedInfoCallback)),
+ .syncFence = std::move(fileDescriptor)};
+}
+
+nn::GeneralResult<nn::SharedExecution> createReusableExecution(
+ const nn::IPreparedModel& preparedModel, const Request& request, bool measureTiming,
+ int64_t loopTimeoutDurationNs, const std::vector<TokenValuePair>& hints,
+ const std::vector<ExtensionNameAndPrefix>& extensionNameToPrefix) {
+ const auto nnRequest = NN_TRY(convertInput(request));
+ const auto nnMeasureTiming = measureTiming ? nn::MeasureTiming::YES : nn::MeasureTiming::NO;
+ const auto nnLoopTimeoutDuration = NN_TRY(makeOptionalDuration(loopTimeoutDurationNs));
+ auto nnHints = NN_TRY(convertInput(hints));
+ auto nnExtensionNameToPrefix = NN_TRY(convertInput(extensionNameToPrefix));
+
+ return preparedModel.createReusableExecution(nnRequest, nnMeasureTiming, nnLoopTimeoutDuration,
+ nnHints, nnExtensionNameToPrefix);
+}
+
+nn::ExecutionResult<ExecutionResult> executeSynchronously(const nn::IExecution& execution,
+ int64_t deadlineNs) {
+ const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+
+ const auto result = execution.compute(nnDeadline);
+
+ if (!result.ok() && result.error().code == nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+ const auto& [message, code, outputShapes] = result.error();
+ LOG(ERROR) << "executeSynchronously failed with " << code << ": " << message;
+ return ExecutionResult{.outputSufficientSize = false,
+ .outputShapes = utils::convert(outputShapes).value(),
+ .timing = {.timeInDriverNs = -1, .timeOnDeviceNs = -1}};
+ }
+
+ const auto& [outputShapes, timing] = NN_TRY(result);
+ return ExecutionResult{.outputSufficientSize = true,
+ .outputShapes = utils::convert(outputShapes).value(),
+ .timing = utils::convert(timing).value()};
+}
+
+nn::GeneralResult<FencedExecutionResult> executeFenced(
+ const nn::IExecution& execution, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+ int64_t deadlineNs, int64_t durationNs) {
+ const auto nnWaitFor = NN_TRY(convertSyncFences(waitFor));
+ const auto nnDeadline = NN_TRY(makeOptionalTimePoint(deadlineNs));
+ const auto nnDuration = NN_TRY(makeOptionalDuration(durationNs));
+
+ auto [syncFence, executeFencedInfoCallback] =
+ NN_TRY(execution.computeFenced(nnWaitFor, nnDeadline, nnDuration));
ndk::ScopedFileDescriptor fileDescriptor;
if (syncFence.hasFd()) {
@@ -179,7 +244,7 @@
int64_t loopTimeoutDurationNs,
ExecutionResult* executionResult) {
auto result = adapter::executeSynchronously(*kPreparedModel, request, measureTiming, deadlineNs,
- loopTimeoutDurationNs);
+ loopTimeoutDurationNs, {}, {});
if (!result.has_value()) {
const auto& [message, code, _] = result.error();
const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
@@ -195,7 +260,41 @@
bool measureTiming, int64_t deadlineNs, int64_t loopTimeoutDurationNs, int64_t durationNs,
FencedExecutionResult* executionResult) {
auto result = adapter::executeFenced(*kPreparedModel, request, waitFor, measureTiming,
- deadlineNs, loopTimeoutDurationNs, durationNs);
+ deadlineNs, loopTimeoutDurationNs, durationNs, {}, {});
+ if (!result.has_value()) {
+ const auto& [message, code] = result.error();
+ const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(aidlCode), message.c_str());
+ }
+ *executionResult = std::move(result).value();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PreparedModel::executeSynchronouslyWithConfig(const Request& request,
+ const ExecutionConfig& config,
+ int64_t deadlineNs,
+ ExecutionResult* executionResult) {
+ auto result = adapter::executeSynchronously(
+ *kPreparedModel, request, config.measureTiming, deadlineNs,
+ config.loopTimeoutDurationNs, config.executionHints, config.extensionNameToPrefix);
+ if (!result.has_value()) {
+ const auto& [message, code, _] = result.error();
+ const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(aidlCode), message.c_str());
+ }
+ *executionResult = std::move(result).value();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PreparedModel::executeFencedWithConfig(
+ const Request& request, const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+ const ExecutionConfig& config, int64_t deadlineNs, int64_t durationNs,
+ FencedExecutionResult* executionResult) {
+ auto result = adapter::executeFenced(*kPreparedModel, request, waitFor, config.measureTiming,
+ deadlineNs, config.loopTimeoutDurationNs, durationNs,
+ config.executionHints, config.extensionNameToPrefix);
if (!result.has_value()) {
const auto& [message, code] = result.error();
const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
@@ -222,4 +321,51 @@
return kPreparedModel;
}
+ndk::ScopedAStatus PreparedModel::createReusableExecution(const Request& request,
+ const ExecutionConfig& config,
+ std::shared_ptr<IExecution>* execution) {
+ auto result = adapter::createReusableExecution(
+ *kPreparedModel, request, config.measureTiming, config.loopTimeoutDurationNs,
+ config.executionHints, config.extensionNameToPrefix);
+ if (!result.has_value()) {
+ const auto& [message, code] = result.error();
+ const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(aidlCode), message.c_str());
+ }
+ *execution = ndk::SharedRefBase::make<Execution>(std::move(result).value());
+ return ndk::ScopedAStatus::ok();
+}
+
+Execution::Execution(nn::SharedExecution execution) : kExecution(std::move(execution)) {
+ CHECK(kExecution != nullptr);
+}
+
+ndk::ScopedAStatus Execution::executeSynchronously(int64_t deadlineNs,
+ ExecutionResult* executionResult) {
+ auto result = adapter::executeSynchronously(*kExecution, deadlineNs);
+ if (!result.has_value()) {
+ const auto& [message, code, _] = result.error();
+ const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(aidlCode), message.c_str());
+ }
+ *executionResult = std::move(result).value();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Execution::executeFenced(const std::vector<ndk::ScopedFileDescriptor>& waitFor,
+ int64_t deadlineNs, int64_t durationNs,
+ FencedExecutionResult* executionResult) {
+ auto result = adapter::executeFenced(*kExecution, waitFor, deadlineNs, durationNs);
+ if (!result.has_value()) {
+ const auto& [message, code] = result.error();
+ const auto aidlCode = utils::convert(code).value_or(ErrorStatus::GENERAL_FAILURE);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(aidlCode), message.c_str());
+ }
+ *executionResult = std::move(result).value();
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/hidl/Android.bp b/neuralnetworks/utils/adapter/hidl/Android.bp
index d073106..6875daa 100644
--- a/neuralnetworks/utils/adapter/hidl/Android.bp
+++ b/neuralnetworks/utils/adapter/hidl/Android.bp
@@ -30,17 +30,16 @@
local_include_dirs: ["include/nnapi/hal"],
export_include_dirs: ["include"],
static_libs: [
- "neuralnetworks_types",
- "neuralnetworks_utils_hal_1_0",
- "neuralnetworks_utils_hal_1_1",
- "neuralnetworks_utils_hal_1_2",
- "neuralnetworks_utils_hal_1_3",
- ],
- shared_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"android.hardware.neuralnetworks@1.3",
"libfmq",
+ "neuralnetworks_types",
+ "neuralnetworks_utils_hal_1_0",
+ "neuralnetworks_utils_hal_1_1",
+ "neuralnetworks_utils_hal_1_2",
+ "neuralnetworks_utils_hal_1_3",
+ "neuralnetworks_utils_hal_common",
],
}
diff --git a/neuralnetworks/utils/adapter/hidl/src/Burst.cpp b/neuralnetworks/utils/adapter/hidl/src/Burst.cpp
index 8b2e1dd..e3b165b 100644
--- a/neuralnetworks/utils/adapter/hidl/src/Burst.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/Burst.cpp
@@ -250,7 +250,7 @@
nn::MeasureTiming canonicalMeasure = NN_TRY(nn::convert(measure));
const auto [outputShapes, timing] =
- NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure, {}, {}));
+ NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure, {}, {}, {}, {}));
return std::make_pair(NN_TRY(V1_2::utils::convert(outputShapes)),
NN_TRY(V1_2::utils::convert(timing)));
diff --git a/neuralnetworks/utils/adapter/hidl/src/Device.cpp b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
index 4993a80..0f44638 100644
--- a/neuralnetworks/utils/adapter/hidl/src/Device.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
@@ -135,7 +135,7 @@
Task task = [device, nnModel = std::move(nnModel), executor, callback] {
auto result = device->prepareModel(nnModel, nn::ExecutionPreference::DEFAULT,
- nn::Priority::DEFAULT, {}, {}, {}, {});
+ nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
notify(callback.get(), std::move(result), executor);
};
executor(std::move(task), {});
@@ -155,8 +155,8 @@
const auto nnPreference = NN_TRY(convertInput(preference));
Task task = [device, nnModel = std::move(nnModel), nnPreference, executor, callback] {
- auto result =
- device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {}, {});
+ auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {},
+ {}, {}, {});
notify(callback.get(), std::move(result), executor);
};
executor(std::move(task), {});
@@ -185,7 +185,7 @@
nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
nnToken, executor, callback] {
auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {},
- nnModelCache, nnDataCache, nnToken);
+ nnModelCache, nnDataCache, nnToken, {}, {});
notify(callback.get(), std::move(result), executor);
};
executor(std::move(task), {});
@@ -215,7 +215,7 @@
nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
nnToken, executor, callback] {
auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
- nnModelCache, nnDataCache, nnToken);
+ nnModelCache, nnDataCache, nnToken, {}, {});
notify(callback.get(), std::move(result), executor);
};
executor(std::move(task), nnDeadline);
diff --git a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
index 71060d5..c6055a6 100644
--- a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
@@ -159,7 +159,7 @@
}
Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
- auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {});
+ auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
notify(callback.get(), std::move(result));
};
executor(std::move(task), {});
@@ -185,7 +185,7 @@
}
Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
- auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {});
+ auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
notify(callback.get(), std::move(result));
};
executor(std::move(task), {});
@@ -216,8 +216,8 @@
Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
nnLoopTimeoutDuration, callback] {
- auto result =
- preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration);
+ auto result = preparedModel->execute(nnRequest, nnMeasure, nnDeadline,
+ nnLoopTimeoutDuration, {}, {});
notify(callback.get(), std::move(result));
};
executor(std::move(task), nnDeadline);
@@ -232,7 +232,7 @@
const auto nnMeasure = NN_TRY(convertInput(measure));
const auto [outputShapes, timing] =
- NN_TRY(preparedModel->execute(nnRequest, nnMeasure, {}, {}));
+ NN_TRY(preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {}));
auto hidlOutputShapes = NN_TRY(V1_2::utils::convert(outputShapes));
const auto hidlTiming = NN_TRY(V1_2::utils::convert(timing));
@@ -248,8 +248,8 @@
const auto nnDeadline = NN_TRY(convertInput(deadline));
const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
- const auto [outputShapes, timing] =
- NN_TRY(preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration));
+ const auto [outputShapes, timing] = NN_TRY(preparedModel->execute(
+ nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration, {}, {}));
auto hidlOutputShapes = NN_TRY(V1_3::utils::convert(outputShapes));
const auto hidlTiming = NN_TRY(V1_3::utils::convert(timing));
@@ -293,8 +293,9 @@
const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
const auto nnDuration = NN_TRY(convertInput(duration));
- auto [syncFence, executeFencedCallback] = NN_TRY(preparedModel->executeFenced(
- nnRequest, nnWaitFor, nnMeasure, nnDeadline, nnLoopTimeoutDuration, nnDuration));
+ auto [syncFence, executeFencedCallback] =
+ NN_TRY(preparedModel->executeFenced(nnRequest, nnWaitFor, nnMeasure, nnDeadline,
+ nnLoopTimeoutDuration, nnDuration, {}, {}));
auto hidlSyncFence = NN_TRY(V1_3::utils::convert(syncFence.getSharedHandle()));
auto hidlExecuteFencedCallback = sp<FencedExecutionCallback>::make(executeFencedCallback);
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
index 39927a3..bfba24f 100644
--- a/neuralnetworks/utils/common/Android.bp
+++ b/neuralnetworks/utils/common/Android.bp
@@ -39,20 +39,12 @@
srcs: ["test/*.cpp"],
static_libs: [
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
- "libfmq",
- "libhidlbase",
- "libhidlmemory",
- "liblog",
- "libutils",
],
target: {
android: {
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
index e86edda..1f1245f 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
@@ -33,12 +33,15 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
};
} // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
index 5e62b9a..9582873 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
@@ -52,8 +52,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache,
- const nn::CacheToken& token) const override;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
index de30aae..3f1f290 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
@@ -31,18 +31,23 @@
public:
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
index fde2486..129431f 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
@@ -48,18 +48,23 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
private:
bool isValidInternal() const EXCLUDES(mMutex);
nn::GeneralResult<nn::SharedExecution> createReusableExecutionInternal(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const;
const Factory kMakeBurst;
mutable std::mutex mMutex;
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
index 84ae799..267d634 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
@@ -65,8 +65,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache,
- const nn::CacheToken& token) const override;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
@@ -83,7 +84,9 @@
nn::GeneralResult<nn::SharedPreparedModel> prepareModelInternal(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const;
nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCacheInternal(
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
index 86533ed..bbfc220 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
@@ -49,18 +49,23 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const override;
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedExecution> createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const override;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const override;
nn::GeneralResult<nn::SharedBurst> configureExecutionBurst() const override;
@@ -70,7 +75,9 @@
bool isValidInternal() const EXCLUDES(mMutex);
nn::GeneralResult<nn::SharedExecution> createReusableExecutionInternal(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const;
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& metaData,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const;
nn::GeneralResult<nn::SharedBurst> configureExecutionBurstInternal() const;
const Factory kMakePreparedModel;
diff --git a/neuralnetworks/utils/common/src/InvalidBurst.cpp b/neuralnetworks/utils/common/src/InvalidBurst.cpp
index 0191533..3fdfb5c 100644
--- a/neuralnetworks/utils/common/src/InvalidBurst.cpp
+++ b/neuralnetworks/utils/common/src/InvalidBurst.cpp
@@ -34,13 +34,17 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> InvalidBurst::execute(
const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
const nn::OptionalTimePoint& /*deadline*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR() << "InvalidBurst";
}
nn::GeneralResult<nn::SharedExecution> InvalidBurst::createReusableExecution(
const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR() << "InvalidBurst";
}
diff --git a/neuralnetworks/utils/common/src/InvalidDevice.cpp b/neuralnetworks/utils/common/src/InvalidDevice.cpp
index 535ccb4..c8cc287 100644
--- a/neuralnetworks/utils/common/src/InvalidDevice.cpp
+++ b/neuralnetworks/utils/common/src/InvalidDevice.cpp
@@ -84,7 +84,9 @@
const nn::Model& /*model*/, nn::ExecutionPreference /*preference*/,
nn::Priority /*priority*/, nn::OptionalTimePoint /*deadline*/,
const std::vector<nn::SharedHandle>& /*modelCache*/,
- const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+ const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR() << "InvalidDevice";
}
diff --git a/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp b/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
index 8195462..f6f978d 100644
--- a/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
+++ b/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
@@ -27,9 +27,12 @@
namespace android::hardware::neuralnetworks::utils {
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
-InvalidPreparedModel::execute(const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
- const nn::OptionalTimePoint& /*deadline*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+InvalidPreparedModel::execute(
+ const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
+ const nn::OptionalTimePoint& /*deadline*/,
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR() << "InvalidPreparedModel";
}
@@ -38,13 +41,17 @@
const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
const nn::OptionalDuration& /*loopTimeoutDuration*/,
- const nn::OptionalDuration& /*timeoutDurationAfterFence*/) const {
+ const nn::OptionalDuration& /*timeoutDurationAfterFence*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR() << "InvalidPreparedModel";
}
nn::GeneralResult<nn::SharedExecution> InvalidPreparedModel::createReusableExecution(
const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
- const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
+ const nn::OptionalDuration& /*loopTimeoutDuration*/,
+ const std::vector<nn::TokenValuePair>& /*hints*/,
+ const std::vector<nn::ExtensionNameAndPrefix>& /*extensionNameToPrefix*/) const {
return NN_ERROR() << "InvalidPreparedModel";
}
diff --git a/neuralnetworks/utils/common/src/ResilientBurst.cpp b/neuralnetworks/utils/common/src/ResilientBurst.cpp
index 79cbe39..bf7a8ea 100644
--- a/neuralnetworks/utils/common/src/ResilientBurst.cpp
+++ b/neuralnetworks/utils/common/src/ResilientBurst.cpp
@@ -105,37 +105,49 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> ResilientBurst::execute(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const {
- const auto fn = [&request, measure, deadline, loopTimeoutDuration](const nn::IBurst& burst) {
- return burst.execute(request, measure, deadline, loopTimeoutDuration);
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+ const auto fn = [&request, measure, deadline, loopTimeoutDuration, &hints,
+ &extensionNameToPrefix](const nn::IBurst& burst) {
+ return burst.execute(request, measure, deadline, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
};
return protect(*this, fn);
}
nn::GeneralResult<nn::SharedExecution> ResilientBurst::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
#if 0
auto self = shared_from_this();
- ResilientExecution::Factory makeExecution =
- [burst = std::move(self), request, measure, loopTimeoutDuration] {
- return burst->createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+ ResilientExecution::Factory makeExecution = [burst = std::move(self), request, measure,
+ loopTimeoutDuration, &hints,
+ &extensionNameToPrefix] {
+ return burst->createReusableExecutionInternal(request, measure, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
};
return ResilientExecution::create(std::move(makeExecution));
#else
- return createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+ return createReusableExecutionInternal(request, measure, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
#endif
}
nn::GeneralResult<nn::SharedExecution> ResilientBurst::createReusableExecutionInternal(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
if (!isValidInternal()) {
return std::make_shared<const InvalidExecution>();
}
- const auto fn = [&request, measure, &loopTimeoutDuration](const nn::IBurst& burst) {
- return burst.createReusableExecution(request, measure, loopTimeoutDuration);
+ const auto fn = [&request, measure, &loopTimeoutDuration, &hints,
+ &extensionNameToPrefix](const nn::IBurst& burst) {
+ return burst.createReusableExecution(request, measure, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
};
return protect(*this, fn);
}
diff --git a/neuralnetworks/utils/common/src/ResilientDevice.cpp b/neuralnetworks/utils/common/src/ResilientDevice.cpp
index 2023c9a..a5c2640 100644
--- a/neuralnetworks/utils/common/src/ResilientDevice.cpp
+++ b/neuralnetworks/utils/common/src/ResilientDevice.cpp
@@ -179,19 +179,21 @@
nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModel(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
#if 0
auto self = shared_from_this();
ResilientPreparedModel::Factory makePreparedModel = [device = std::move(self), model,
preference, priority, deadline, modelCache,
- dataCache, token] {
+ dataCache, token, hints, extensionNameToPrefix] {
return device->prepareModelInternal(model, preference, priority, deadline, modelCache,
- dataCache, token);
+ dataCache, token, hints, extensionNameToPrefix);
};
return ResilientPreparedModel::create(std::move(makePreparedModel));
#else
- return prepareModelInternal(model, preference, priority, deadline, modelCache, dataCache,
- token);
+ return prepareModelInternal(model, preference, priority, deadline, modelCache, dataCache, token,
+ hints, extensionNameToPrefix);
#endif
}
@@ -234,14 +236,16 @@
nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelInternal(
const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
- const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+ const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
if (!isValidInternal()) {
return std::make_shared<const InvalidPreparedModel>();
}
- const auto fn = [&model, preference, priority, &deadline, &modelCache, &dataCache,
- &token](const nn::IDevice& device) {
+ const auto fn = [&model, preference, priority, &deadline, &modelCache, &dataCache, &token,
+ &hints, &extensionNameToPrefix](const nn::IDevice& device) {
return device.prepareModel(model, preference, priority, deadline, modelCache, dataCache,
- token);
+ token, hints, extensionNameToPrefix);
};
return protect(*this, fn, /*blocking=*/false);
}
diff --git a/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
index 1ae19bc..b5843c0 100644
--- a/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
+++ b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
@@ -104,43 +104,53 @@
}
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
-ResilientPreparedModel::execute(const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration) const {
- const auto fn = [&request, measure, &deadline,
- &loopTimeoutDuration](const nn::IPreparedModel& preparedModel) {
- return preparedModel.execute(request, measure, deadline, loopTimeoutDuration);
+ResilientPreparedModel::execute(
+ const nn::Request& request, nn::MeasureTiming measure,
+ const nn::OptionalTimePoint& deadline, const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
+ const auto fn = [&request, measure, &deadline, &loopTimeoutDuration, &hints,
+ &extensionNameToPrefix](const nn::IPreparedModel& preparedModel) {
+ return preparedModel.execute(request, measure, deadline, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
};
return protect(*this, fn);
}
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
-ResilientPreparedModel::executeFenced(const nn::Request& request,
- const std::vector<nn::SyncFence>& waitFor,
- nn::MeasureTiming measure,
- const nn::OptionalTimePoint& deadline,
- const nn::OptionalDuration& loopTimeoutDuration,
- const nn::OptionalDuration& timeoutDurationAfterFence) const {
+ResilientPreparedModel::executeFenced(
+ const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+ nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const nn::OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
const auto fn = [&request, &waitFor, measure, &deadline, &loopTimeoutDuration,
- &timeoutDurationAfterFence](const nn::IPreparedModel& preparedModel) {
+ &timeoutDurationAfterFence, &hints,
+ &extensionNameToPrefix](const nn::IPreparedModel& preparedModel) {
return preparedModel.executeFenced(request, waitFor, measure, deadline, loopTimeoutDuration,
- timeoutDurationAfterFence);
+ timeoutDurationAfterFence, hints, extensionNameToPrefix);
};
return protect(*this, fn);
}
nn::GeneralResult<nn::SharedExecution> ResilientPreparedModel::createReusableExecution(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
#if 0
auto self = shared_from_this();
- ResilientExecution::Factory makeExecution =
- [preparedModel = std::move(self), request, measure, loopTimeoutDuration] {
- return preparedModel->createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+ ResilientExecution::Factory makeExecution = [preparedModel = std::move(self), request, measure,
+ loopTimeoutDuration, hints,
+ extensionNameToPrefix] {
+ return preparedModel->createReusableExecutionInternal(request, measure, loopTimeoutDuration,
+ hints, extensionNameToPrefix);
};
return ResilientExecution::create(std::move(makeExecution));
#else
- return createReusableExecutionInternal(request, measure, loopTimeoutDuration);
+ return createReusableExecutionInternal(request, measure, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
#endif
}
@@ -159,13 +169,16 @@
nn::GeneralResult<nn::SharedExecution> ResilientPreparedModel::createReusableExecutionInternal(
const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration) const {
+ const nn::OptionalDuration& loopTimeoutDuration,
+ const std::vector<nn::TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const {
if (!isValidInternal()) {
return std::make_shared<const InvalidExecution>();
}
- const auto fn = [&request, measure,
- &loopTimeoutDuration](const nn::IPreparedModel& preparedModel) {
- return preparedModel.createReusableExecution(request, measure, loopTimeoutDuration);
+ const auto fn = [&request, measure, &loopTimeoutDuration, &hints,
+ &extensionNameToPrefix](const nn::IPreparedModel& preparedModel) {
+ return preparedModel.createReusableExecution(request, measure, loopTimeoutDuration, hints,
+ extensionNameToPrefix);
};
return protect(*this, fn);
}
diff --git a/neuralnetworks/utils/common/test/MockDevice.h b/neuralnetworks/utils/common/test/MockDevice.h
index a9428bc..a0fc5c3 100644
--- a/neuralnetworks/utils/common/test/MockDevice.h
+++ b/neuralnetworks/utils/common/test/MockDevice.h
@@ -39,7 +39,9 @@
MOCK_METHOD(GeneralResult<SharedPreparedModel>, prepareModel,
(const Model& model, ExecutionPreference preference, Priority priority,
OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache,
- const std::vector<SharedHandle>& dataCache, const CacheToken& token),
+ const std::vector<SharedHandle>& dataCache, const CacheToken& token,
+ const std::vector<TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
(const, override));
MOCK_METHOD(GeneralResult<SharedPreparedModel>, prepareModelFromCache,
(OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache,
diff --git a/neuralnetworks/utils/common/test/MockPreparedModel.h b/neuralnetworks/utils/common/test/MockPreparedModel.h
index c8ce006..b8613b2 100644
--- a/neuralnetworks/utils/common/test/MockPreparedModel.h
+++ b/neuralnetworks/utils/common/test/MockPreparedModel.h
@@ -27,17 +27,23 @@
public:
MOCK_METHOD((ExecutionResult<std::pair<std::vector<OutputShape>, Timing>>), execute,
(const Request& request, MeasureTiming measure, const OptionalTimePoint& deadline,
- const OptionalDuration& loopTimeoutDuration),
+ const OptionalDuration& loopTimeoutDuration,
+ const std::vector<TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
(const, override));
MOCK_METHOD((GeneralResult<std::pair<SyncFence, ExecuteFencedInfoCallback>>), executeFenced,
(const Request& request, const std::vector<SyncFence>& waitFor,
MeasureTiming measure, const OptionalTimePoint& deadline,
const OptionalDuration& loopTimeoutDuration,
- const OptionalDuration& timeoutDurationAfterFence),
+ const OptionalDuration& timeoutDurationAfterFence,
+ const std::vector<TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
(const, override));
MOCK_METHOD((GeneralResult<SharedExecution>), createReusableExecution,
- (const nn::Request& request, nn::MeasureTiming measure,
- const nn::OptionalDuration& loopTimeoutDuration),
+ (const Request& request, MeasureTiming measure,
+ const OptionalDuration& loopTimeoutDuration,
+ const std::vector<TokenValuePair>& hints,
+ const std::vector<nn::ExtensionNameAndPrefix>& extensionNameToPrefix),
(const, override));
MOCK_METHOD(GeneralResult<SharedBurst>, configureExecutionBurst, (), (const, override));
MOCK_METHOD(std::any, getUnderlyingResource, (), (const, override));
diff --git a/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp b/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp
index 0488b63..d9b8505 100644
--- a/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp
+++ b/neuralnetworks/utils/common/test/ResilientDeviceTest.cpp
@@ -309,12 +309,12 @@
// setup call
const auto [mockDevice, mockDeviceFactory, device] = setup();
const auto mockPreparedModel = std::make_shared<const nn::MockPreparedModel>();
- EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+ EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(mockPreparedModel));
// run test
- const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+ const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -324,12 +324,12 @@
TEST(ResilientDeviceTest, prepareModelError) {
// setup call
const auto [mockDevice, mockDeviceFactory, device] = setup();
- EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+ EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(kReturnGeneralFailure);
// run test
- const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+ const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -339,13 +339,13 @@
TEST(ResilientDeviceTest, prepareModelDeadObjectFailedRecovery) {
// setup call
const auto [mockDevice, mockDeviceFactory, device] = setup();
- EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+ EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(kReturnDeadObject);
EXPECT_CALL(*mockDeviceFactory, Call(false)).Times(1).WillOnce(kReturnGeneralFailure);
// run test
- const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+ const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -355,18 +355,18 @@
TEST(ResilientDeviceTest, prepareModelDeadObjectSuccessfulRecovery) {
// setup call
const auto [mockDevice, mockDeviceFactory, device] = setup();
- EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _))
+ EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(kReturnDeadObject);
const auto recoveredMockDevice = createConfiguredMockDevice();
const auto mockPreparedModel = std::make_shared<const nn::MockPreparedModel>();
- EXPECT_CALL(*recoveredMockDevice, prepareModel(_, _, _, _, _, _, _))
+ EXPECT_CALL(*recoveredMockDevice, prepareModel(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(mockPreparedModel));
EXPECT_CALL(*mockDeviceFactory, Call(false)).Times(1).WillOnce(Return(recoveredMockDevice));
// run test
- const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+ const auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -679,7 +679,7 @@
device->recover(mockDevice.get(), /*blocking=*/false);
// run test
- auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {});
+ auto result = device->prepareModel({}, {}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
diff --git a/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp b/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp
index d396ca8..276bfba 100644
--- a/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp
+++ b/neuralnetworks/utils/common/test/ResilientPreparedModelTest.cpp
@@ -104,12 +104,12 @@
TEST(ResilientPreparedModelTest, execute) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _))
+ EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _))
.Times(1)
.WillOnce(Return(kNoExecutionError));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -119,10 +119,12 @@
TEST(ResilientPreparedModelTest, executeError) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _)).Times(1).WillOnce(kReturnGeneralFailure);
+ EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(kReturnGeneralFailure);
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -132,12 +134,12 @@
TEST(ResilientPreparedModelTest, executeDeadObjectFailedRecovery) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
+ EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
constexpr auto ret = [] { return nn::error(nn::ErrorStatus::GENERAL_FAILURE); };
EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(ret);
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -147,9 +149,9 @@
TEST(ResilientPreparedModelTest, executeDeadObjectSuccessfulRecovery) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
+ EXPECT_CALL(*mockPreparedModel, execute(_, _, _, _, _, _)).Times(1).WillOnce(kReturnDeadObject);
const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
- EXPECT_CALL(*recoveredMockPreparedModel, execute(_, _, _, _))
+ EXPECT_CALL(*recoveredMockPreparedModel, execute(_, _, _, _, _, _))
.Times(1)
.WillOnce(Return(kNoExecutionError));
EXPECT_CALL(*mockPreparedModelFactory, Call())
@@ -157,7 +159,7 @@
.WillOnce(Return(recoveredMockPreparedModel));
// run test
- const auto result = preparedModel->execute({}, {}, {}, {});
+ const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -167,12 +169,12 @@
TEST(ResilientPreparedModelTest, executeFenced) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+ EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(kNoFencedExecutionError));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -182,12 +184,12 @@
TEST(ResilientPreparedModelTest, executeFencedError) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+ EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(kReturnGeneralFailure);
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -197,13 +199,13 @@
TEST(ResilientPreparedModelTest, executeFencedDeadObjectFailedRecovery) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+ EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(kReturnDeadObject);
EXPECT_CALL(*mockPreparedModelFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure);
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -213,11 +215,11 @@
TEST(ResilientPreparedModelTest, executeFencedDeadObjectSuccessfulRecovery) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _))
+ EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(kReturnDeadObject);
const auto recoveredMockPreparedModel = createConfiguredMockPreparedModel();
- EXPECT_CALL(*recoveredMockPreparedModel, executeFenced(_, _, _, _, _, _))
+ EXPECT_CALL(*recoveredMockPreparedModel, executeFenced(_, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(kNoFencedExecutionError));
EXPECT_CALL(*mockPreparedModelFactory, Call())
@@ -225,7 +227,7 @@
.WillOnce(Return(recoveredMockPreparedModel));
// run test
- const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
+ const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -235,12 +237,12 @@
TEST(ResilientPreparedModelTest, createReusableExecution) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+ EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _, _, _))
.Times(1)
.WillOnce(Return(kNoCreateReusableExecutionError));
// run test
- const auto result = preparedModel->createReusableExecution({}, {}, {});
+ const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -250,12 +252,12 @@
TEST(ResilientPreparedModelTest, createReusableExecutionError) {
// setup call
const auto [mockPreparedModel, mockPreparedModelFactory, preparedModel] = setup();
- EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _))
+ EXPECT_CALL(*mockPreparedModel, createReusableExecution(_, _, _, _, _))
.Times(1)
.WillOnce(kReturnGeneralFailure);
// run test
- const auto result = preparedModel->createReusableExecution({}, {}, {});
+ const auto result = preparedModel->createReusableExecution({}, {}, {}, {}, {});
// verify result
ASSERT_FALSE(result.has_value());
diff --git a/neuralnetworks/utils/service/Android.bp b/neuralnetworks/utils/service/Android.bp
index c3272ae..452078b 100644
--- a/neuralnetworks/utils/service/Android.bp
+++ b/neuralnetworks/utils/service/Android.bp
@@ -33,6 +33,10 @@
local_include_dirs: ["include/nnapi/hal"],
export_include_dirs: ["include"],
static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
+ "android.hardware.neuralnetworks@1.3",
"neuralnetworks_types",
"neuralnetworks_utils_hal_1_0",
"neuralnetworks_utils_hal_1_1",
@@ -40,10 +44,4 @@
"neuralnetworks_utils_hal_1_3",
"neuralnetworks_utils_hal_common",
],
- shared_libs: [
- "android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- "android.hardware.neuralnetworks@1.2",
- "android.hardware.neuralnetworks@1.3",
- ],
}
diff --git a/nfc/OWNERS b/nfc/OWNERS
new file mode 100644
index 0000000..7867204
--- /dev/null
+++ b/nfc/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 48448
+alisher@google.com
+georgekgchang@google.com
+jackcwyu@google.com
+
+
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
new file mode 100644
index 0000000..d390c7e
--- /dev/null
+++ b/nfc/aidl/Android.bp
@@ -0,0 +1,34 @@
+// 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.nfc",
+ vendor_available: true,
+ srcs: ["android/hardware/nfc/*.aidl"],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ enabled: false,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
similarity index 79%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
index 7ef08d2..7a0ae54 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
@@ -31,9 +31,17 @@
// 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.gnss.visibility_control;
+package android.hardware.nfc;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface INfc {
+ void open(in android.hardware.nfc.INfcClientCallback clientCallback);
+ void close(in android.hardware.nfc.NfcCloseType type);
+ void coreInitialized();
+ void factoryReset();
+ android.hardware.nfc.NfcConfig getConfig();
+ void powerCycle();
+ void preDiscover();
+ int write(in byte[] data);
+ void setEnableVerboseLogging(in boolean enable);
+ boolean isVerboseLoggingEnabled();
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfcClientCallback.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfcClientCallback.aidl
index 7ef08d2..8150e81 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfcClientCallback.aidl
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
+package android.hardware.nfc;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+interface INfcClientCallback {
+ void sendData(in byte[] data);
+ void sendEvent(in android.hardware.nfc.NfcEvent event, in android.hardware.nfc.NfcStatus status);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcCloseType.aidl
similarity index 85%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcCloseType.aidl
index 7ef08d2..7d44d48 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcCloseType.aidl
@@ -31,9 +31,9 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.nfc;
+@Backing(type="int") @VintfStability
+enum NfcCloseType {
+ DISABLE = 0,
+ HOST_SWITCHED_OFF = 1,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
similarity index 74%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
index 7ef08d2..92e0a9a 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcConfig.aidl
@@ -31,9 +31,22 @@
// 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.gnss.visibility_control;
+package android.hardware.nfc;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable NfcConfig {
+ boolean nfaPollBailOutMode;
+ android.hardware.nfc.PresenceCheckAlgorithm presenceCheckAlgorithm;
+ android.hardware.nfc.ProtocolDiscoveryConfig nfaProprietaryCfg;
+ byte defaultOffHostRoute;
+ byte defaultOffHostRouteFelica;
+ byte defaultSystemCodeRoute;
+ byte defaultSystemCodePowerState;
+ byte defaultRoute;
+ byte offHostESEPipeId;
+ byte offHostSIMPipeId;
+ int maxIsoDepTransceiveLength;
+ byte[] hostAllowlist;
+ byte[] offHostRouteUicc;
+ byte[] offHostRouteEse;
+ byte defaultIsoDepRoute;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
similarity index 85%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
index 7ef08d2..dda258e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
@@ -31,9 +31,13 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.nfc;
+@Backing(type="int") @VintfStability
+enum NfcEvent {
+ OPEN_CPLT = 0,
+ CLOSE_CPLT = 1,
+ POST_INIT_CPLT = 2,
+ PRE_DISCOVER_CPLT = 3,
+ HCI_NETWORK_RESET = 4,
+ ERROR = 5,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcStatus.aidl
similarity index 85%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcStatus.aidl
index 7ef08d2..2632480 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcStatus.aidl
@@ -31,9 +31,12 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.nfc;
+@Backing(type="int") @VintfStability
+enum NfcStatus {
+ OK = 0,
+ FAILED = 1,
+ ERR_TRANSPORT = 2,
+ ERR_CMD_TIMEOUT = 3,
+ REFUSED = 4,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/PresenceCheckAlgorithm.aidl
similarity index 85%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/PresenceCheckAlgorithm.aidl
index 7ef08d2..9a9be21 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/PresenceCheckAlgorithm.aidl
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.nfc;
+@Backing(type="byte") @VintfStability
+enum PresenceCheckAlgorithm {
+ DEFAULT = 0,
+ I_BLOCK = 1,
+ ISO_DEP_NAK = 2,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
similarity index 84%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
index 7ef08d2..021dfe2 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
@@ -31,9 +31,16 @@
// 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.gnss.visibility_control;
+package android.hardware.nfc;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+parcelable ProtocolDiscoveryConfig {
+ byte protocol18092Active;
+ byte protocolBPrime;
+ byte protocolDual;
+ byte protocol15693;
+ byte protocolKovio;
+ byte protocolMifare;
+ byte discoveryPollKovio;
+ byte discoveryPollBPrime;
+ byte discoveryListenBPrime;
}
diff --git a/nfc/aidl/android/hardware/nfc/INfc.aidl b/nfc/aidl/android/hardware/nfc/INfc.aidl
new file mode 100644
index 0000000..662f8d4
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/INfc.aidl
@@ -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 android.hardware.nfc;
+
+import android.hardware.nfc.INfcClientCallback;
+import android.hardware.nfc.NfcCloseType;
+import android.hardware.nfc.NfcConfig;
+import android.hardware.nfc.NfcStatus;
+
+@VintfStability
+interface INfc {
+ /**
+ * Opens the NFC controller device and performs initialization.
+ * This may include patch download and other vendor-specific initialization.
+ *
+ * If open completes successfully, the controller must be ready to perform NCI
+ * initialization - ie accept CORE_RESET and subsequent commands through the write()
+ * call.
+ *
+ * Returns ok() if initialization starts successfully.
+ * If open() returns ok(), the NCI stack must wait for a NfcEvent.OPEN_CPLT
+ * callback before continuing.
+ * If a NfcEvent.OPEN_CPLT callback received with status NfcStatus::OK, the controller
+ * must be ready to perform NCI initialization - ie accept CORE_RESET and subsequent
+ * commands through the write() call.
+ */
+ void open(in INfcClientCallback clientCallback);
+
+ /**
+ * Close the NFC HAL and setup NFC controller close type.
+ * Associated resources such as clientCallback must be released.
+ * The clientCallback reference from open() must be invalid after close().
+ * If close() returns ok(), the NCI stack must wait for a NfcEvent.CLOSE_CPLT
+ * callback before continuing.
+ * Returns an error if close may be called more than once.
+ * Calls to any other method which expect a callback after this must return
+ * a service-specific error NfcStatus::FAILED.
+ * HAL close automatically if the client drops the reference to the HAL or
+ * crashes.
+ */
+ void close(in NfcCloseType type);
+
+ /**
+ * coreInitialized() is called after the CORE_INIT_RSP is received from the
+ * NFCC. At this time, the HAL can do any chip-specific configuration.
+ *
+ * If coreInitialized() returns ok(), the NCI stack must wait for a
+ * NfcEvent.POST_INIT_CPLT before continuing.
+ * If coreInitialized() returns an error, the NCI stack must continue immediately.
+ *
+ * coreInitialized() must be called after open() registers the clientCallback
+ * or return a service-specific error NfcStatus::FAILED directly.
+ *
+ */
+ void coreInitialized();
+
+ /**
+ * Clears the NFC chip.
+ *
+ * Must be called during factory reset and/or before the first time the HAL is
+ * initialized after a factory reset.
+ */
+ void factoryReset();
+
+ /**
+ * Fetches vendor specific configurations.
+ * @return NfcConfig indicates support for certain features and
+ * populates the vendor specific configs.
+ */
+ NfcConfig getConfig();
+
+ /**
+ * Restart controller by power cyle;
+ * It's similar to open but just reset the controller without initialize all the
+ * resources.
+ *
+ * If powerCycle() returns ok(), the NCI stack must wait for a NfcEvent.OPEN_CPLT
+ * before continuing.
+ *
+ * powerCycle() must be called after open() registers the clientCallback
+ * or return a service-specific error NfcStatus::FAILED directly.
+ */
+ void powerCycle();
+
+ /**
+ * preDiscover is called every time before starting RF discovery.
+ * It is a good place to do vendor-specific configuration that must be
+ * performed every time RF discovery is about to be started.
+ *
+ * If preDiscover() returns ok(), the NCI stack must wait for a
+ * NfcEvent.PREDISCOVER_CPLT before continuing.
+ *
+ * preDiscover() must be called after open() registers the clientCallback
+ * or return a service-specific error NfcStatus::FAILED directly.
+ *
+ * If preDiscover() reports an error, the NCI stack must start RF discovery immediately.
+ */
+ void preDiscover();
+
+ /**
+ * Performs an NCI write.
+ *
+ * This method may queue writes and return immediately. The only
+ * requirement is that the writes are executed in order.
+ *
+ * @param data
+ * Data packet to transmit NCI Commands and Data Messages over write.
+ * Detailed format is defined in NFC Controller Interface (NCI) Technical Specification.
+ * https://nfc-forum.org/our-work/specification-releases/
+ *
+ * @return number of bytes written to the NFCC.
+ */
+ int write(in byte[] data);
+
+ /**
+ * Set the logging flag for NFC HAL to enable it's verbose logging.
+ * If verbose logging is not supported, the call must not have any effect on logging verbosity.
+ * However, isVerboseLoggingEnabled() must still return the value set by the last call to
+ * setEnableVerboseLogging().
+ * @param enable for setting the verbose logging flag to HAL
+ */
+ void setEnableVerboseLogging(in boolean enable);
+
+ /**
+ * Get the verbose logging flag value from NFC HAL.
+ * @return true if verbose logging flag value is enabled, false if disabled.
+ */
+ boolean isVerboseLoggingEnabled();
+}
diff --git a/nfc/aidl/android/hardware/nfc/INfcClientCallback.aidl b/nfc/aidl/android/hardware/nfc/INfcClientCallback.aidl
new file mode 100644
index 0000000..43d4f5c
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/INfcClientCallback.aidl
@@ -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.
+ */
+
+package android.hardware.nfc;
+
+import android.hardware.nfc.NfcEvent;
+import android.hardware.nfc.NfcStatus;
+
+@VintfStability
+interface INfcClientCallback {
+ /**
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass incomming response data to the stack.
+ *
+ * @param data
+ * Data packet to transmit NCI Responses, Notifications, and Data
+ * Messages over sendData.
+ * Detailed format is defined in NFC Controller Interface (NCI) Technical Specification.
+ * https://nfc-forum.org/our-work/specification-releases/
+ */
+ void sendData(in byte[] data);
+
+ /**
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass events back to the stack.
+ */
+ void sendEvent(in NfcEvent event, in NfcStatus status);
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcCloseType.aidl b/nfc/aidl/android/hardware/nfc/NfcCloseType.aidl
new file mode 100644
index 0000000..5160532
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcCloseType.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.nfc;
+
+/**
+ * Different closing types for NFC HAL.
+ */
+@VintfStability
+@Backing(type="int")
+enum NfcCloseType {
+ /**
+ * Close the NFC controller and free NFC HAL resources.
+ */
+ DISABLE = 0,
+
+ /**
+ * Switch the NFC controller operation mode and free NFC HAL resources.
+ * Enable NFC functionality for off host card emulation usecases in
+ * device(host) power off(switched off) state, if the device
+ * supports power off use cases. If the device doesn't support power
+ * off use cases, this call should be same as DISABLE.
+ */
+ HOST_SWITCHED_OFF = 1,
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcConfig.aidl b/nfc/aidl/android/hardware/nfc/NfcConfig.aidl
new file mode 100644
index 0000000..1b4fcfb
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcConfig.aidl
@@ -0,0 +1,89 @@
+/*
+ * 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.nfc;
+
+import android.hardware.nfc.PresenceCheckAlgorithm;
+import android.hardware.nfc.ProtocolDiscoveryConfig;
+
+/**
+ * Define Nfc related configurations based on:
+ * NFC Controller Interface (NCI) Technical Specification
+ * https://nfc-forum.org/our-work/specification-releases/
+ */
+@VintfStability
+parcelable NfcConfig {
+ /**
+ * If true, NFCC is using bail out mode for either Type A or Type B poll
+ * based on: Nfc-Forum Activity Technical Specification
+ * https://nfc-forum.org/our-work/specification-releases/
+ */
+ boolean nfaPollBailOutMode;
+ PresenceCheckAlgorithm presenceCheckAlgorithm;
+ ProtocolDiscoveryConfig nfaProprietaryCfg;
+ /**
+ * Default off-host route. 0x00 if there aren't any. Refer to NCI spec.
+ */
+ byte defaultOffHostRoute;
+ /**
+ * Default off-host route for Felica. 0x00 if there aren't any. Refer to
+ * NCI spec.
+ */
+ byte defaultOffHostRouteFelica;
+ /**
+ * Default system code route. 0x00 if there aren't any. Refer NCI spec.
+ */
+ byte defaultSystemCodeRoute;
+ /**
+ * Default power state for system code route. 0x00 if there aren't any.
+ * Refer to NCI spec.
+ */
+ byte defaultSystemCodePowerState;
+ /**
+ * Default route for all remaining protocols and technology which haven't
+ * been configured.
+ * Device Host(0x00) is the default. Refer to NCI spec.
+ *
+ */
+ byte defaultRoute;
+ /**
+ * Pipe ID for eSE. 0x00 if there aren't any.
+ */
+ byte offHostESEPipeId;
+ /**
+ * Pipe ID for UICC. 0x00 if there aren't any.
+ */
+ byte offHostSIMPipeId;
+ /**
+ * Extended APDU length for ISO_DEP. If not supported default length is 261
+ */
+ int maxIsoDepTransceiveLength;
+ /**
+ * list of allowed host ids, as per ETSI TS 102 622
+ * https://www.etsi.org/
+ */
+ byte[] hostAllowlist;
+ /**
+ * NFCEE ID for offhost UICC & eSE secure element.
+ * 0x00 if there aren't any. Refer to NCI spec.
+ */
+ byte[] offHostRouteUicc;
+ byte[] offHostRouteEse;
+ /**
+ * Default IsoDep route. 0x00 if there aren't any. Refer to NCI spec.
+ */
+ byte defaultIsoDepRoute;
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcEvent.aidl b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
new file mode 100644
index 0000000..a78b1cd
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.nfc;
+
+/**
+ * Nfc event to notify nfc status change.
+ */
+@VintfStability
+@Backing(type="int")
+enum NfcEvent {
+ /**
+ * Open complete event to notify upper layer when NFC HAL and NFCC
+ * initialization complete.
+ */
+ OPEN_CPLT = 0,
+ /**
+ * Close complete event to notify upper layer when HAL close is done.
+ */
+ CLOSE_CPLT = 1,
+ /**
+ * Post init complete event to notify upper layer when post init operations
+ * are done.
+ */
+ POST_INIT_CPLT = 2,
+ /**
+ * Pre-discover complete event to notify upper layer when pre-discover
+ * operations are done.
+ */
+ PRE_DISCOVER_CPLT = 3,
+ /**
+ * HCI network reset event to notify upplayer when HCI network needs to
+ * be re-initialized in case of an error.
+ */
+ HCI_NETWORK_RESET = 4,
+ /**
+ * Error event to notify upper layer when there's an unknown error.
+ */
+ ERROR = 5,
+}
diff --git a/nfc/aidl/android/hardware/nfc/NfcStatus.aidl b/nfc/aidl/android/hardware/nfc/NfcStatus.aidl
new file mode 100644
index 0000000..a38d370
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/NfcStatus.aidl
@@ -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 android.hardware.nfc;
+
+/**
+ * Used to specify the status of the NfcEvent
+ */
+@VintfStability
+@Backing(type="int")
+enum NfcStatus {
+ /**
+ * Default status when NfcEvent with status OK.
+ */
+ OK = 0,
+ /**
+ * Generic error.
+ */
+ FAILED = 1,
+ /**
+ * Transport error.
+ */
+ ERR_TRANSPORT = 2,
+ /**
+ * Command timeout error.
+ */
+ ERR_CMD_TIMEOUT = 3,
+ /**
+ * Refused error when command is rejected.
+ */
+ REFUSED = 4,
+}
diff --git a/nfc/aidl/android/hardware/nfc/PresenceCheckAlgorithm.aidl b/nfc/aidl/android/hardware/nfc/PresenceCheckAlgorithm.aidl
new file mode 100644
index 0000000..20e7bff
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/PresenceCheckAlgorithm.aidl
@@ -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.nfc;
+
+/*
+ * Presence Check Algorithm as defined in ISO/IEC 14443-4:
+ * https://www.iso.org/standard/73599.html
+ */
+@VintfStability
+@Backing(type="byte")
+enum PresenceCheckAlgorithm {
+ /**
+ * Let the stack select an algorithm
+ */
+ DEFAULT = 0,
+ /**
+ * ISO-DEP protocol's empty I-block
+ */
+ I_BLOCK = 1,
+ /**
+ * Type - 4 tag protocol iso-dep nak presence check command is sent waiting for
+ * response and notification.
+ */
+ ISO_DEP_NAK = 2,
+}
diff --git a/nfc/aidl/android/hardware/nfc/ProtocolDiscoveryConfig.aidl b/nfc/aidl/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
new file mode 100644
index 0000000..f8e3228
--- /dev/null
+++ b/nfc/aidl/android/hardware/nfc/ProtocolDiscoveryConfig.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.nfc;
+
+/**
+ * Vendor Specific Proprietary Protocol & Discovery Configuration.
+ * Set to 0xFF if not supported.
+ * discovery* fields map to "RF Technology and Mode" in NCI Spec
+ * protocol* fields map to "RF protocols" in NCI Spec
+ */
+@VintfStability
+parcelable ProtocolDiscoveryConfig {
+ byte protocol18092Active;
+ byte protocolBPrime;
+ byte protocolDual;
+ byte protocol15693;
+ byte protocolKovio;
+ byte protocolMifare;
+ byte discoveryPollKovio;
+ byte discoveryPollBPrime;
+ byte discoveryListenBPrime;
+}
diff --git a/nfc/aidl/default/Android.bp b/nfc/aidl/default/Android.bp
new file mode 100644
index 0000000..907d23d
--- /dev/null
+++ b/nfc/aidl/default/Android.bp
@@ -0,0 +1,23 @@
+cc_binary {
+ name: "android.hardware.nfc-service.example",
+ relative_install_path: "hw",
+ init_rc: ["nfc-service-example.rc"],
+ vintf_fragments: ["nfc-service-example.xml"],
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ "libbinder_ndk",
+ "android.hardware.nfc-V1-ndk",
+ ],
+ srcs: [
+ "main.cpp",
+ "Nfc.cpp",
+ "Vendor_hal_api.cpp",
+ ],
+}
diff --git a/nfc/aidl/default/Nfc.cpp b/nfc/aidl/default/Nfc.cpp
new file mode 100644
index 0000000..a31ac5e
--- /dev/null
+++ b/nfc/aidl/default/Nfc.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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 "Nfc.h"
+
+#include <android-base/logging.h>
+
+#include "Vendor_hal_api.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace nfc {
+
+std::shared_ptr<INfcClientCallback> Nfc::mCallback = nullptr;
+AIBinder_DeathRecipient* clientDeathRecipient = nullptr;
+
+void OnDeath(void* cookie) {
+ if (Nfc::mCallback != nullptr && !AIBinder_isAlive(Nfc::mCallback->asBinder().get())) {
+ LOG(INFO) << __func__ << " Nfc service has died";
+ Nfc* nfc = static_cast<Nfc*>(cookie);
+ nfc->close(NfcCloseType::DISABLE);
+ }
+}
+
+::ndk::ScopedAStatus Nfc::open(const std::shared_ptr<INfcClientCallback>& clientCallback) {
+ LOG(INFO) << "open";
+ if (clientCallback == nullptr) {
+ LOG(INFO) << "Nfc::open null callback";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+ } else {
+ Nfc::mCallback = clientCallback;
+
+ clientDeathRecipient = AIBinder_DeathRecipient_new(OnDeath);
+ auto linkRet = AIBinder_linkToDeath(clientCallback->asBinder().get(), clientDeathRecipient,
+ this /* cookie */);
+ if (linkRet != STATUS_OK) {
+ LOG(ERROR) << __func__ << ": linkToDeath failed: " << linkRet;
+ // Just ignore the error.
+ }
+
+ int ret = Vendor_hal_open(eventCallback, dataCallback);
+ return ret == 0 ? ndk::ScopedAStatus::ok()
+ : ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+ return ndk::ScopedAStatus::ok();
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::close(NfcCloseType type) {
+ LOG(INFO) << "close";
+ if (Nfc::mCallback == nullptr) {
+ LOG(ERROR) << __func__ << "mCallback null";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+ }
+ int ret = 0;
+ if (type == NfcCloseType::HOST_SWITCHED_OFF) {
+ ret = Vendor_hal_close_off();
+ } else {
+ ret = Vendor_hal_close();
+ }
+ Nfc::mCallback = nullptr;
+ AIBinder_DeathRecipient_delete(clientDeathRecipient);
+ clientDeathRecipient = nullptr;
+ return ret == 0 ? ndk::ScopedAStatus::ok()
+ : ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+}
+
+::ndk::ScopedAStatus Nfc::coreInitialized() {
+ LOG(INFO) << "coreInitialized";
+ if (Nfc::mCallback == nullptr) {
+ LOG(ERROR) << __func__ << "mCallback null";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+ }
+ int ret = Vendor_hal_core_initialized();
+
+ return ret == 0 ? ndk::ScopedAStatus::ok()
+ : ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+}
+
+::ndk::ScopedAStatus Nfc::factoryReset() {
+ LOG(INFO) << "factoryReset";
+ Vendor_hal_factoryReset();
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::getConfig(NfcConfig* _aidl_return) {
+ LOG(INFO) << "getConfig";
+ NfcConfig nfcVendorConfig;
+ Vendor_hal_getConfig(nfcVendorConfig);
+
+ *_aidl_return = nfcVendorConfig;
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::powerCycle() {
+ LOG(INFO) << "powerCycle";
+ if (Nfc::mCallback == nullptr) {
+ LOG(ERROR) << __func__ << "mCallback null";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+ }
+ return Vendor_hal_power_cycle() ? ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED))
+ : ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::preDiscover() {
+ LOG(INFO) << "preDiscover";
+ if (Nfc::mCallback == nullptr) {
+ LOG(ERROR) << __func__ << "mCallback null";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+ }
+ return Vendor_hal_pre_discover() ? ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED))
+ : ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::write(const std::vector<uint8_t>& data, int32_t* _aidl_return) {
+ LOG(INFO) << "write";
+ if (Nfc::mCallback == nullptr) {
+ LOG(ERROR) << __func__ << "mCallback null";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(NfcStatus::FAILED));
+ }
+ *_aidl_return = Vendor_hal_write(data.size(), &data[0]);
+ return ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus Nfc::setEnableVerboseLogging(bool enable) {
+ LOG(INFO) << "setVerboseLogging";
+ Vendor_hal_setVerboseLogging(enable);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::isVerboseLoggingEnabled(bool* _aidl_return) {
+ *_aidl_return = Vendor_hal_getVerboseLogging();
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace nfc
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/nfc/aidl/default/Nfc.h b/nfc/aidl/default/Nfc.h
new file mode 100644
index 0000000..1b14534
--- /dev/null
+++ b/nfc/aidl/default/Nfc.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <aidl/android/hardware/nfc/BnNfc.h>
+#include <aidl/android/hardware/nfc/INfcClientCallback.h>
+#include <android-base/logging.h>
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace nfc {
+
+using ::aidl::android::hardware::nfc::NfcCloseType;
+using ::aidl::android::hardware::nfc::NfcConfig;
+using ::aidl::android::hardware::nfc::NfcStatus;
+
+// Default implementation that reports no support NFC.
+struct Nfc : public BnNfc {
+ public:
+ Nfc() = default;
+
+ ::ndk::ScopedAStatus open(const std::shared_ptr<INfcClientCallback>& clientCallback) override;
+ ::ndk::ScopedAStatus close(NfcCloseType type) override;
+ ::ndk::ScopedAStatus coreInitialized() override;
+ ::ndk::ScopedAStatus factoryReset() override;
+ ::ndk::ScopedAStatus getConfig(NfcConfig* _aidl_return) override;
+ ::ndk::ScopedAStatus powerCycle() override;
+ ::ndk::ScopedAStatus preDiscover() override;
+ ::ndk::ScopedAStatus write(const std::vector<uint8_t>& data, int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus setEnableVerboseLogging(bool enable) override;
+ ::ndk::ScopedAStatus isVerboseLoggingEnabled(bool* _aidl_return) override;
+
+ static void eventCallback(uint8_t event, uint8_t status) {
+ if (mCallback != nullptr) {
+ auto ret = mCallback->sendEvent((NfcEvent)event, (NfcStatus)status);
+ if (!ret.isOk()) {
+ LOG(ERROR) << "Failed to send event!";
+ }
+ }
+ }
+
+ static void dataCallback(uint16_t data_len, uint8_t* p_data) {
+ std::vector<uint8_t> data(p_data, p_data + data_len);
+ if (mCallback != nullptr) {
+ auto ret = mCallback->sendData(data);
+ if (!ret.isOk()) {
+ LOG(ERROR) << "Failed to send data!";
+ }
+ }
+ }
+
+ static std::shared_ptr<INfcClientCallback> mCallback;
+};
+
+} // namespace nfc
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/nfc/aidl/default/Vendor_hal_api.cpp b/nfc/aidl/default/Vendor_hal_api.cpp
new file mode 100644
index 0000000..66a2ebc
--- /dev/null
+++ b/nfc/aidl/default/Vendor_hal_api.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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/properties.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include "Vendor_hal_api.h"
+
+bool logging = false;
+
+int Vendor_hal_open(nfc_stack_callback_t* p_cback, nfc_stack_data_callback_t* p_data_cback) {
+ (void)p_cback;
+ (void)p_data_cback;
+ // nothing to open in this example
+ return -1;
+}
+
+int Vendor_hal_write(uint16_t data_len, const uint8_t* p_data) {
+ (void)data_len;
+ (void)p_data;
+ return -1;
+}
+
+int Vendor_hal_core_initialized() {
+ return -1;
+}
+
+int Vendor_hal_pre_discover() {
+ return -1;
+}
+
+int Vendor_hal_close() {
+ return -1;
+}
+
+int Vendor_hal_close_off() {
+ return -1;
+}
+
+int Vendor_hal_power_cycle() {
+ return -1;
+}
+
+void Vendor_hal_factoryReset() {}
+
+void Vendor_hal_getConfig(NfcConfig& config) {
+ (void)config;
+}
+
+void Vendor_hal_setVerboseLogging(bool enable) {
+ logging = enable;
+}
+
+bool Vendor_hal_getVerboseLogging() {
+ return logging;
+}
diff --git a/nfc/aidl/default/Vendor_hal_api.h b/nfc/aidl/default/Vendor_hal_api.h
new file mode 100644
index 0000000..595c2dd
--- /dev/null
+++ b/nfc/aidl/default/Vendor_hal_api.h
@@ -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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/nfc/INfc.h>
+#include <aidl/android/hardware/nfc/NfcConfig.h>
+#include <aidl/android/hardware/nfc/NfcEvent.h>
+#include <aidl/android/hardware/nfc/NfcStatus.h>
+#include <aidl/android/hardware/nfc/PresenceCheckAlgorithm.h>
+#include <aidl/android/hardware/nfc/ProtocolDiscoveryConfig.h>
+#include "hardware_nfc.h"
+
+using aidl::android::hardware::nfc::NfcConfig;
+using aidl::android::hardware::nfc::NfcEvent;
+using aidl::android::hardware::nfc::NfcStatus;
+using aidl::android::hardware::nfc::PresenceCheckAlgorithm;
+using aidl::android::hardware::nfc::ProtocolDiscoveryConfig;
+
+int Vendor_hal_open(nfc_stack_callback_t* p_cback, nfc_stack_data_callback_t* p_data_cback);
+int Vendor_hal_write(uint16_t data_len, const uint8_t* p_data);
+
+int Vendor_hal_core_initialized();
+
+int Vendor_hal_pre_discover();
+
+int Vendor_hal_close();
+
+int Vendor_hal_close_off();
+
+int Vendor_hal_power_cycle();
+
+void Vendor_hal_factoryReset();
+
+void Vendor_hal_getConfig(NfcConfig& config);
+
+void Vendor_hal_setVerboseLogging(bool enable);
+
+bool Vendor_hal_getVerboseLogging();
diff --git a/nfc/aidl/default/hardware_nfc.h b/nfc/aidl/default/hardware_nfc.h
new file mode 100644
index 0000000..0f856c5
--- /dev/null
+++ b/nfc/aidl/default/hardware_nfc.h
@@ -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.
+ */
+#pragma once
+
+typedef uint8_t nfc_event_t;
+typedef uint8_t nfc_status_t;
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass events back to the stack.
+ */
+typedef void(nfc_stack_callback_t)(nfc_event_t event, nfc_status_t event_status);
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass incomming data to the stack.
+ */
+typedef void(nfc_stack_data_callback_t)(uint16_t data_len, uint8_t* p_data);
diff --git a/nfc/aidl/default/main.cpp b/nfc/aidl/default/main.cpp
new file mode 100644
index 0000000..0cc51e7
--- /dev/null
+++ b/nfc/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "Nfc.h"
+using ::aidl::android::hardware::nfc::Nfc;
+
+int main() {
+ LOG(INFO) << "NFC HAL starting up";
+ if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+ LOG(INFO) << "failed to set thread pool max thread count";
+ return 1;
+ }
+ std::shared_ptr<Nfc> nfc_service = ndk::SharedRefBase::make<Nfc>();
+
+ const std::string instance = std::string() + Nfc::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(nfc_service->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+ ABinderProcess_joinThreadPool();
+ return 0;
+}
diff --git a/nfc/aidl/default/nfc-service-example.rc b/nfc/aidl/default/nfc-service-example.rc
new file mode 100644
index 0000000..7d7052e
--- /dev/null
+++ b/nfc/aidl/default/nfc-service-example.rc
@@ -0,0 +1,4 @@
+service nfc_hal_service /vendor/bin/hw/android.hardware.nfc-service.st
+ class hal
+ user nfc
+ group nfc
diff --git a/nfc/aidl/default/nfc-service-example.xml b/nfc/aidl/default/nfc-service-example.xml
new file mode 100644
index 0000000..70fed20
--- /dev/null
+++ b/nfc/aidl/default/nfc-service-example.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.nfc</name>
+ <fqname>INfc/default</fqname>
+ </hal>
+</manifest>
diff --git a/nfc/aidl/vts/functional/Android.bp b/nfc/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..99eecd0
--- /dev/null
+++ b/nfc/aidl/vts/functional/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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: "VtsAidlHalNfcTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsAidlHalNfcTargetTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.nfc-V1-ndk",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
new file mode 100644
index 0000000..977b25c
--- /dev/null
+++ b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
@@ -0,0 +1,458 @@
+/*
+ * 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 "nfc_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/nfc/BnNfc.h>
+#include <aidl/android/hardware/nfc/BnNfcClientCallback.h>
+#include <aidl/android/hardware/nfc/INfc.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_enums.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <chrono>
+#include <future>
+
+using aidl::android::hardware::nfc::INfc;
+using aidl::android::hardware::nfc::INfcClientCallback;
+using aidl::android::hardware::nfc::NfcCloseType;
+using aidl::android::hardware::nfc::NfcConfig;
+using aidl::android::hardware::nfc::NfcEvent;
+using aidl::android::hardware::nfc::NfcStatus;
+using aidl::android::hardware::nfc::PresenceCheckAlgorithm;
+
+using android::getAidlHalInstanceNames;
+using android::PrintInstanceNameToString;
+using android::base::StringPrintf;
+using ndk::enum_range;
+using ndk::ScopedAStatus;
+using ndk::SharedRefBase;
+using ndk::SpAIBinder;
+
+constexpr static int kCallbackTimeoutMs = 10000;
+
+// 261 bytes is the default and minimum transceive length
+constexpr unsigned int MIN_ISO_DEP_TRANSCEIVE_LENGTH = 261;
+
+// Range of valid off host route ids
+constexpr uint8_t MIN_OFFHOST_ROUTE_ID = 0x01;
+constexpr uint8_t MAX_OFFHOST_ROUTE_ID = 0xFE;
+
+class NfcClientCallback : public aidl::android::hardware::nfc::BnNfcClientCallback {
+ public:
+ NfcClientCallback(const std::function<void(NfcEvent, NfcStatus)>& on_hal_event_cb,
+ const std::function<void(const std::vector<uint8_t>&)>& on_nci_data_cb)
+ : on_nci_data_cb_(on_nci_data_cb), on_hal_event_cb_(on_hal_event_cb) {}
+ virtual ~NfcClientCallback() = default;
+
+ ::ndk::ScopedAStatus sendEvent(NfcEvent event, NfcStatus event_status) override {
+ on_hal_event_cb_(event, event_status);
+ return ::ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus sendData(const std::vector<uint8_t>& data) override {
+ on_nci_data_cb_(data);
+ return ::ndk::ScopedAStatus::ok();
+ };
+
+ private:
+ std::function<void(const std::vector<uint8_t>&)> on_nci_data_cb_;
+ std::function<void(NfcEvent, NfcStatus)> on_hal_event_cb_;
+};
+
+class NfcAidl : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+ infc_ = INfc::fromBinder(binder);
+ ASSERT_NE(infc_, nullptr);
+ }
+ std::shared_ptr<INfc> infc_;
+};
+
+/*
+ * OpenAndCloseForDisable:
+ * Makes an open call, waits for NfcEvent::OPEN_CPLT
+ * Immediately calls close(NfcCloseType::DISABLE) and
+ * waits for NfcEvent::CLOSE_CPLT
+ *
+ */
+TEST_P(NfcAidl, OpenAndCloseForDisable) {
+ std::promise<void> open_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ LOG(INFO) << StringPrintf("%s,%d ", __func__, event);
+ if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close DISABLE";
+ EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+ LOG(INFO) << "wait for close";
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * OpenAndCloseForHostSwitchedOff:
+ * Makes an open call, waits for NfcEvent::OPEN_CPLT
+ * Immediately calls close(NfcCloseType::HOST_SWITCHED_OFF) and
+ * waits for NfcEvent::CLOSE_CPLT
+ *
+ */
+TEST_P(NfcAidl, OpenAndCloseForHostSwitchedOff) {
+ std::promise<void> open_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close HOST_SWITCHED_OFF";
+ EXPECT_TRUE(infc_->close(NfcCloseType::HOST_SWITCHED_OFF).isOk());
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * OpenAfterOpen:
+ * Calls open() multiple times
+ * Checks status
+ */
+TEST_P(NfcAidl, OpenAfterOpen) {
+ int open_count = 0;
+ std::promise<void> open_cb_promise;
+ std::promise<void> open2_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto open2_cb_future = open2_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &open2_cb_promise, &open_count](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) {
+ open_count == 0 ? open_cb_promise.set_value() : open2_cb_promise.set_value();
+ open_count++;
+ }
+ },
+ [](auto) {});
+
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Open again and wait for OPEN_CPLT
+ LOG(INFO) << "open again";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open2_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * CloseAfterClose:
+ * Calls close() multiple times
+ * Checks status
+ */
+TEST_P(NfcAidl, CloseAfterClose) {
+ std::promise<void> open_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close";
+ EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+ // Close again should fail.
+ LOG(INFO) << "close again";
+ EXPECT_TRUE(!(infc_->close(NfcCloseType::DISABLE).isOk()));
+}
+
+/*
+ * PowerCycleAfterOpen:
+ * Calls powerCycle() after open
+ * Waits for NfcEvent.OPEN_CPLT
+ * Checks status
+ */
+TEST_P(NfcAidl, PowerCycleAfterOpen) {
+ int open_cplt_count = 0;
+ std::promise<void> open_cb_promise;
+ std::promise<void> power_cycle_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto power_cycle_cb_future = power_cycle_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise, &power_cycle_cb_promise, &open_cplt_count](
+ auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) {
+ if (open_cplt_count == 0) {
+ open_cplt_count++;
+ open_cb_promise.set_value();
+ } else {
+ power_cycle_cb_promise.set_value();
+ }
+ }
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // PowerCycle and wait for OPEN_CPLT
+ LOG(INFO) << "PowerCycle";
+ EXPECT_TRUE(infc_->powerCycle().isOk());
+ EXPECT_EQ(power_cycle_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close";
+ EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * PowerCycleAfterClose:
+ * Calls powerCycle() after close
+ * PowerCycle should fail immediately
+ */
+TEST_P(NfcAidl, PowerCycleAfterClose) {
+ std::promise<void> open_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close";
+ EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // PowerCycle should fail
+ LOG(INFO) << "PowerCycle";
+ EXPECT_TRUE(!(infc_->powerCycle().isOk()));
+}
+
+/*
+ * CoreInitializedAfterOpen:
+ * Calls coreInitialized() after open
+ * Waits for NfcEvent.POST_INIT_CPLT
+ */
+TEST_P(NfcAidl, CoreInitializedAfterOpen) {
+ std::promise<void> open_cb_promise;
+ std::promise<void> core_init_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto core_init_cb_future = core_init_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise, &core_init_cb_promise](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+ if (event == NfcEvent::POST_INIT_CPLT) core_init_cb_promise.set_value();
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // CoreInitialized and wait for POST_INIT_CPLT
+ LOG(INFO) << "coreInitialized";
+ EXPECT_TRUE(infc_->coreInitialized().isOk());
+ EXPECT_EQ(core_init_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close";
+ EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+}
+
+/*
+ * CoreInitializedAfterClose:
+ * Calls coreInitialized() after close
+ * coreInitialized() should fail immediately
+ */
+TEST_P(NfcAidl, CoreInitializedAfterClose) {
+ std::promise<void> open_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close";
+ EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // coreInitialized should fail
+ LOG(INFO) << "CoreInitialized";
+ EXPECT_TRUE(!(infc_->coreInitialized().isOk()));
+}
+
+/*
+ * PreDiscoverAfterClose:
+ * Call preDiscover() after close
+ * preDiscover() should fail immediately
+ */
+TEST_P(NfcAidl, PreDiscoverAfterClose) {
+ std::promise<void> open_cb_promise;
+ std::promise<void> close_cb_promise;
+ auto open_cb_future = open_cb_promise.get_future();
+ auto close_cb_future = close_cb_promise.get_future();
+ std::shared_ptr<INfcClientCallback> mCallback = ::ndk::SharedRefBase::make<NfcClientCallback>(
+ [&open_cb_promise, &close_cb_promise](auto event, auto status) {
+ EXPECT_EQ(status, NfcStatus::OK);
+ if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value();
+ if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value();
+ },
+ [](auto) {});
+ std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+ // Open and wait for OPEN_CPLT
+ LOG(INFO) << "open";
+ EXPECT_TRUE(infc_->open(mCallback).isOk());
+ EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // Close and wait for CLOSE_CPLT
+ LOG(INFO) << "close";
+ EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk());
+ EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready);
+
+ // preDiscover should fail
+ LOG(INFO) << "preDiscover";
+ EXPECT_TRUE(!(infc_->preDiscover().isOk()));
+}
+
+/*
+ * checkGetConfigValues:
+ * Calls getConfig()
+ * checks if fields in NfcConfig are populated correctly
+ */
+TEST_P(NfcAidl, CheckGetConfigValues) {
+ NfcConfig configValue;
+ EXPECT_TRUE(infc_->getConfig(&configValue).isOk());
+ EXPECT_GE(configValue.maxIsoDepTransceiveLength, MIN_ISO_DEP_TRANSCEIVE_LENGTH);
+ LOG(INFO) << StringPrintf("configValue.maxIsoDepTransceiveLength = %x",
+ configValue.maxIsoDepTransceiveLength);
+ for (auto uicc : configValue.offHostRouteUicc) {
+ LOG(INFO) << StringPrintf("offHostRouteUicc = %x", uicc);
+ EXPECT_GE(uicc, MIN_OFFHOST_ROUTE_ID);
+ EXPECT_LE(uicc, MAX_OFFHOST_ROUTE_ID);
+ }
+ for (auto ese : configValue.offHostRouteEse) {
+ LOG(INFO) << StringPrintf("offHostRouteEse = %x", ese);
+ EXPECT_GE(ese, MIN_OFFHOST_ROUTE_ID);
+ EXPECT_LE(ese, MAX_OFFHOST_ROUTE_ID);
+ }
+ if (configValue.defaultIsoDepRoute != 0) {
+ EXPECT_GE((uint8_t)configValue.defaultIsoDepRoute, MIN_OFFHOST_ROUTE_ID);
+ EXPECT_LE((uint8_t)configValue.defaultIsoDepRoute, MAX_OFFHOST_ROUTE_ID);
+ }
+}
+
+/*
+ * CheckisVerboseLoggingEnabledAfterSetEnableVerboseLogging:
+ * Calls setEnableVerboseLogging()
+ * checks the return value of isVerboseLoggingEnabled
+ */
+TEST_P(NfcAidl, CheckisVerboseLoggingEnabledAfterSetEnableVerboseLogging) {
+ bool enabled = false;
+ EXPECT_TRUE(infc_->setEnableVerboseLogging(true).isOk());
+ EXPECT_TRUE(infc_->isVerboseLoggingEnabled(&enabled).isOk());
+ EXPECT_TRUE(enabled);
+ EXPECT_TRUE(infc_->setEnableVerboseLogging(false).isOk());
+ EXPECT_TRUE(infc_->isVerboseLoggingEnabled(&enabled).isOk());
+ EXPECT_TRUE(!enabled);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NfcAidl);
+INSTANTIATE_TEST_SUITE_P(Nfc, NfcAidl,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(INfc::descriptor)),
+ ::android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_startThreadPool();
+ std::system("/system/bin/svc nfc disable"); /* Turn off NFC */
+ sleep(5);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ std::system("/system/bin/svc nfc enable"); /* Turn on NFC */
+ sleep(5);
+ return status;
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
index ba444a7..f38426b 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
@@ -49,5 +49,6 @@
CAMERA_STREAMING_LOW = 12,
CAMERA_STREAMING_MID = 13,
CAMERA_STREAMING_HIGH = 14,
- GAME_LOADING = 15,
+ GAME = 15,
+ GAME_LOADING = 16,
}
diff --git a/power/aidl/android/hardware/power/Mode.aidl b/power/aidl/android/hardware/power/Mode.aidl
index 2ebace1..cc4b130 100644
--- a/power/aidl/android/hardware/power/Mode.aidl
+++ b/power/aidl/android/hardware/power/Mode.aidl
@@ -164,6 +164,11 @@
CAMERA_STREAMING_HIGH,
/**
+ * This mode indicates that user is playing a game.
+ */
+ GAME,
+
+ /**
* This mode indicates that the user is waiting for loading in a game.
*/
GAME_LOADING,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
index 6982d40..980b042 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
@@ -47,4 +47,7 @@
EMERGENCY = 512,
MCX = 1024,
XCAP = 2048,
+ VSIM = 4096,
+ BIP = 8192,
+ ENTERPRISE = 16384,
}
diff --git a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
index e780d8e..ae103fc 100644
--- a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
@@ -73,4 +73,16 @@
* APN type for XCAP
*/
XCAP = 1 << 11,
+ /**
+ * APN type for VSIM.
+ */
+ VSIM = 1 << 12,
+ /**
+ * APN type for BIP.
+ */
+ BIP = 1 << 13,
+ /**
+ * APN type for ENTERPRISE
+ */
+ ENTERPRISE = 1 << 14
}
diff --git a/security/dice/aidl/Android.bp b/security/dice/aidl/Android.bp
index af9dd33..01bc91e 100644
--- a/security/dice/aidl/Android.bp
+++ b/security/dice/aidl/Android.bp
@@ -41,6 +41,10 @@
},
rust: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ ],
},
},
// versions: ["1"],
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/BccHandover.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/BccHandover.aidl
index ab50c36..8baca94 100644
--- a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/BccHandover.aidl
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/BccHandover.aidl
@@ -35,7 +35,7 @@
/* @hide */
@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
parcelable BccHandover {
- byte[] cdiAttest;
- byte[] cdiSeal;
+ byte[32] cdiAttest;
+ byte[32] cdiSeal;
android.hardware.security.dice.Bcc bcc;
}
diff --git a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/InputValues.aidl b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/InputValues.aidl
index 79583fb..e43c429 100644
--- a/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/InputValues.aidl
+++ b/security/dice/aidl/aidl_api/android.hardware.security.dice/current/android/hardware/security/dice/InputValues.aidl
@@ -35,10 +35,10 @@
/* @hide */
@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
parcelable InputValues {
- byte[] codeHash;
+ byte[64] codeHash;
android.hardware.security.dice.Config config;
- byte[] authorityHash;
+ byte[64] authorityHash;
@nullable byte[] authorityDescriptor;
android.hardware.security.dice.Mode mode = android.hardware.security.dice.Mode.NOT_INITIALIZED;
- byte[] hidden;
+ byte[64] hidden;
}
diff --git a/security/dice/aidl/android/hardware/security/dice/BccHandover.aidl b/security/dice/aidl/android/hardware/security/dice/BccHandover.aidl
index d522cef..6ca862c 100644
--- a/security/dice/aidl/android/hardware/security/dice/BccHandover.aidl
+++ b/security/dice/aidl/android/hardware/security/dice/BccHandover.aidl
@@ -27,13 +27,13 @@
@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
parcelable BccHandover {
/**
- * CDI_attest. Must a exactly 32 bytes of data.
+ * CDI_attest. Must be exactly 32 bytes of data.
*/
- byte[] cdiAttest;
+ byte[32] cdiAttest;
/**
- * CDI_seal. Must a exactly 32 bytes of data.
+ * CDI_seal. Must be exactly 32 bytes of data.
*/
- byte[] cdiSeal;
+ byte[32] cdiSeal;
/**
* CBOR encoded BCC.
*
diff --git a/security/dice/aidl/android/hardware/security/dice/InputValues.aidl b/security/dice/aidl/android/hardware/security/dice/InputValues.aidl
index e44ef22..711d523 100644
--- a/security/dice/aidl/android/hardware/security/dice/InputValues.aidl
+++ b/security/dice/aidl/android/hardware/security/dice/InputValues.aidl
@@ -34,7 +34,7 @@
/**
* The target code hash. Must be exactly 64 bytes.
*/
- byte[] codeHash;
+ byte[64] codeHash;
/**
* The configuration data.
*/
@@ -42,7 +42,7 @@
/**
* The authority hash. Must be exactly 64 bytes. Must be all zero if unused.
*/
- byte[] authorityHash;
+ byte[64] authorityHash;
/**
* Optional free form authorityDescriptor.
*/
@@ -54,5 +54,5 @@
/**
* Optional hidden values. Must be exactly 64 bytes. Must be all zero if unused.
*/
- byte[] hidden;
+ byte[64] hidden;
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 9846ee9..4b63799 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -96,7 +96,9 @@
* - TRUSTED_ENVRIONMENT IKeyMintDevices must support curve 25519 for Purpose::SIGN (Ed25519,
* as specified in RFC 8032), Purpose::ATTEST_KEY (Ed25519) or for KeyPurpose::AGREE_KEY
* (X25519, as specified in RFC 7748). However, a key must have exactly one of these
- * purpose values; the same key cannot be used for multiple purposes.
+ * purpose values; the same key cannot be used for multiple purposes. Signing operations
+ * (Purpose::SIGN) have a message size limit of 16 KiB; operations on messages longer than
+ * this limit must fail with ErrorCode::INVALID_INPUT_LENGTH.
* STRONGBOX IKeyMintDevices do not support curve 25519.
*
* o AES
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 374f2da..146a527 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -25,6 +25,7 @@
#include <cppbor_parse.h>
#include <cutils/properties.h>
#include <gmock/gmock.h>
+#include <openssl/evp.h>
#include <openssl/mem.h>
#include <remote_prov/remote_prov_utils.h>
@@ -206,6 +207,21 @@
return boot_patch_level(key_characteristics_);
}
+bool KeyMintAidlTestBase::Curve25519Supported() {
+ // Strongbox never supports curve 25519.
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ return false;
+ }
+
+ // Curve 25519 was included in version 2 of the KeyMint interface.
+ int32_t version = 0;
+ auto status = keymint_->getInterfaceVersion(&version);
+ if (!status.isOk()) {
+ ADD_FAILURE() << "Failed to determine interface version";
+ }
+ return version >= 2;
+}
+
ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
if (result.isOk()) return ErrorCode::OK;
@@ -543,7 +559,12 @@
std::vector<uint8_t> o_put;
result = op_->update(vector<uint8_t>(input.begin(), input.end()), {}, {}, &o_put);
- if (result.isOk()) output->append(o_put.begin(), o_put.end());
+ if (result.isOk()) {
+ output->append(o_put.begin(), o_put.end());
+ } else {
+ // Failure always terminates the operation.
+ op_ = {};
+ }
return GetReturnErrorCode(result);
}
@@ -740,6 +761,19 @@
if (digest == Digest::NONE) {
switch (EVP_PKEY_id(pub_key.get())) {
+ case EVP_PKEY_ED25519: {
+ ASSERT_EQ(64, signature.size());
+ uint8_t pub_keydata[32];
+ size_t pub_len = sizeof(pub_keydata);
+ ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(pub_key.get(), pub_keydata, &pub_len));
+ ASSERT_EQ(sizeof(pub_keydata), pub_len);
+ ASSERT_EQ(1, ED25519_verify(reinterpret_cast<const uint8_t*>(message.data()),
+ message.size(),
+ reinterpret_cast<const uint8_t*>(signature.data()),
+ pub_keydata));
+ break;
+ }
+
case EVP_PKEY_EC: {
vector<uint8_t> data((EVP_PKEY_bits(pub_key.get()) + 7) / 8);
size_t data_size = std::min(data.size(), message.size());
@@ -1166,16 +1200,31 @@
vector<EcCurve> KeyMintAidlTestBase::ValidCurves() {
if (securityLevel_ == SecurityLevel::STRONGBOX) {
return {EcCurve::P_256};
+ } else if (Curve25519Supported()) {
+ return {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521,
+ EcCurve::CURVE_25519};
} else {
- return {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+ return {
+ EcCurve::P_224,
+ EcCurve::P_256,
+ EcCurve::P_384,
+ EcCurve::P_521,
+ };
}
}
vector<EcCurve> KeyMintAidlTestBase::InvalidCurves() {
if (SecLevel() == SecurityLevel::STRONGBOX) {
- return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521};
+ // Curve 25519 is not supported, either because:
+ // - KeyMint v1: it's an unknown enum value
+ // - KeyMint v2+: it's not supported by StrongBox.
+ return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521, EcCurve::CURVE_25519};
} else {
- return {};
+ if (Curve25519Supported()) {
+ return {};
+ } else {
+ return {EcCurve::CURVE_25519};
+ }
}
}
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 61f9d4d..27cb99c 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -80,6 +80,8 @@
uint32_t boot_patch_level(const vector<KeyCharacteristics>& key_characteristics);
uint32_t boot_patch_level();
+ bool Curve25519Supported();
+
ErrorCode GetReturnErrorCode(const Status& result);
ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 340010f..7357ac7 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -22,6 +22,7 @@
#include <algorithm>
#include <iostream>
+#include <openssl/curve25519.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
@@ -69,6 +70,9 @@
namespace {
+// Maximum supported Ed25519 message size.
+const size_t MAX_ED25519_MSG_SIZE = 16 * 1024;
+
// Whether to check that BOOT_PATCHLEVEL is populated.
bool check_boot_pl = true;
@@ -415,6 +419,126 @@
// } end SEQUENCE (PrivateKeyInfo)
);
+/**
+ * Ed25519 key pair generated as follows:
+ * ```
+ * % openssl req -x509 -newkey ED25519 -days 700 -nodes \
+ * -keyout ed25519_priv.key -out ed25519.pem * -subj "/CN=fake.ed25519.com"
+ * Generating a ED25519 private key writing new private key to
+ * 'ed25519_priv.key'
+ * -----
+ * % cat ed25519_priv.key
+ * -----BEGIN PRIVATE KEY-----
+ * MC4CAQAwBQYDK2VwBCIEIKl3A5quNywcj1P+0XI9SBalFPIvO52NxceMLRH6dVmR
+ * -----END PRIVATE KEY-----
+ * % der2ascii -pem -i ed25519_priv.key
+ * SEQUENCE {
+ * INTEGER { 0 }
+ * SEQUENCE {
+ * # ed25519
+ * OBJECT_IDENTIFIER { 1.3.101.112 }
+ * }
+ * OCTET_STRING {
+ * OCTET_STRING { `a977039aae372c1c8f53fed1723d4816a514f22f3b9d8dc5c78c2d11fa755991` }
+ * }
+ * }
+ * % cat ed25519.pem
+ * -----BEGIN CERTIFICATE-----
+ * MIIBSjCB/aADAgECAhR0Jron3eKcdgqyecv/eEfGWAzn8DAFBgMrZXAwGzEZMBcG
+ * A1UEAwwQZmFrZS5lZDI1NTE5LmNvbTAeFw0yMTEwMjAwODI3NDJaFw0yMzA5MjAw
+ * ODI3NDJaMBsxGTAXBgNVBAMMEGZha2UuZWQyNTUxOS5jb20wKjAFBgMrZXADIQDv
+ * uwHz+3TaQ69D2digxlz0fFfsZg0rPqgQae3jBPRWkaNTMFEwHQYDVR0OBBYEFN9O
+ * od30SY4JTs66ZR403UPya+iXMB8GA1UdIwQYMBaAFN9Ood30SY4JTs66ZR403UPy
+ * a+iXMA8GA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAKjVrYQjuE/gEL2j/ABpDbFjV
+ * Ilg5tJ6MN/P3psAv3Cs7f0X1lFqdlt15nJ/6aj2cmGCwNRXt5wcyYDKNu+v2Dw==
+ * -----END CERTIFICATE-----
+ * % openssl x509 -in ed25519.pem -text -noout
+ * Certificate:
+ * Data:
+ * Version: 3 (0x2)
+ * Serial Number:
+ * 74:26:ba:27:dd:e2:9c:76:0a:b2:79:cb:ff:78:47:c6:58:0c:e7:f0
+ * Signature Algorithm: ED25519
+ * Issuer: CN = fake.ed25519.com
+ * Validity
+ * Not Before: Oct 20 08:27:42 2021 GMT
+ * Not After : Sep 20 08:27:42 2023 GMT
+ * Subject: CN = fake.ed25519.com
+ * Subject Public Key Info:
+ * Public Key Algorithm: ED25519
+ * ED25519 Public-Key:
+ * pub:
+ * ef:bb:01:f3:fb:74:da:43:af:43:d9:d8:a0:c6:5c:
+ * f4:7c:57:ec:66:0d:2b:3e:a8:10:69:ed:e3:04:f4:
+ * 56:91
+ * X509v3 extensions:
+ * X509v3 Subject Key Identifier:
+ * DF:4E:A1:DD:F4:49:8E:09:4E:CE:BA:65:1E:34:DD:43:F2:6B:E8:97
+ * X509v3 Authority Key Identifier:
+ * keyid:DF:4E:A1:DD:F4:49:8E:09:4E:CE:BA:65:1E:34:DD:43:F2:6B:E8:97
+ *
+ * X509v3 Basic Constraints: critical
+ * CA:TRUE
+ * Signature Algorithm: ED25519
+ * 2a:35:6b:61:08:ee:13:f8:04:2f:68:ff:00:1a:43:6c:58:d5:
+ * 22:58:39:b4:9e:8c:37:f3:f7:a6:c0:2f:dc:2b:3b:7f:45:f5:
+ * 94:5a:9d:96:dd:79:9c:9f:fa:6a:3d:9c:98:60:b0:35:15:ed:
+ * e7:07:32:60:32:8d:bb:eb:f6:0f
+ * ```
+ */
+string ed25519_key = hex2str("a977039aae372c1c8f53fed1723d4816a514f22f3b9d8dc5c78c2d11fa755991");
+string ed25519_pkcs8_key = hex2str(
+ // RFC 5208 s5
+ "302e" // SEQUENCE length 0x2e (PrivateKeyInfo) {
+ "0201" // INTEGER length 1 (Version)
+ "00" // version 0
+ "3005" // SEQUENCE length 05 (AlgorithmIdentifier) {
+ "0603" // OBJECT IDENTIFIER length 3 (algorithm)
+ "2b6570" // 1.3.101.112 (id-Ed125519 RFC 8410 s3)
+ // } end SEQUENCE (AlgorithmIdentifier)
+ "0422" // OCTET STRING length 0x22 (PrivateKey)
+ "0420" // OCTET STRING length 0x20 (RFC 8410 s7)
+ "a977039aae372c1c8f53fed1723d4816a514f22f3b9d8dc5c78c2d11fa755991"
+ // } end SEQUENCE (PrivateKeyInfo)
+);
+string ed25519_pubkey = hex2str("efbb01f3fb74da43af43d9d8a0c65cf47c57ec660d2b3ea81069ede304f45691");
+
+/**
+ * X25519 key pair generated as follows:
+ * ```
+ * % openssl genpkey -algorithm X25519 > x25519_priv.key
+ * % cat x25519_priv.key
+ * -----BEGIN PRIVATE KEY-----
+ * MC4CAQAwBQYDK2VuBCIEIGgPwF3NLwQx/Sfwr2nfJvXitwlDNh3Skzh+TISN/y1C
+ * -----END PRIVATE KEY-----
+ * % der2ascii -pem -i x25519_priv.key
+ * SEQUENCE {
+ * INTEGER { 0 }
+ * SEQUENCE {
+ * # x25519
+ * OBJECT_IDENTIFIER { 1.3.101.110 }
+ * }
+ * OCTET_STRING {
+ * OCTET_STRING { `680fc05dcd2f0431fd27f0af69df26f5e2b70943361dd293387e4c848dff2d42` }
+ * }
+ * }
+ * ```
+ */
+
+string x25519_key = hex2str("680fc05dcd2f0431fd27f0af69df26f5e2b70943361dd293387e4c848dff2d42");
+string x25519_pkcs8_key = hex2str(
+ // RFC 5208 s5
+ "302e" // SEQUENCE length 0x2e (PrivateKeyInfo) {
+ "0201" // INTEGER length 1 (Version)
+ "00" // version 0
+ "3005" // SEQUENCE length 05 (AlgorithmIdentifier) {
+ "0603" // OBJECT IDENTIFIER length 3 (algorithm)
+ "2b656e" // 1.3.101.110 (id-X125519 RFC 8410 s3)
+ "0422" // OCTET STRING length 0x22 (PrivateKey)
+ "0420" // OCTET STRING length 0x20 (RFC 8410 s7)
+ "680fc05dcd2f0431fd27f0af69df26f5e2b70943361dd293387e4c848dff2d42");
+string x25519_pubkey = hex2str("be46925a857f17831d6d454b9d3d36a4a30166edf80eb82b684661c3e258f768");
+
struct RSA_Delete {
void operator()(RSA* p) { RSA_free(p); }
};
@@ -1374,7 +1498,7 @@
/*
* NewKeyGenerationTest.Ecdsa
*
- * Verifies that keymint can generate all required EC key sizes, and that the resulting keys
+ * Verifies that keymint can generate all required EC curves, and that the resulting keys
* have correct characteristics.
*/
TEST_P(NewKeyGenerationTest, Ecdsa) {
@@ -1400,6 +1524,65 @@
}
/*
+ * NewKeyGenerationTest.EcdsaCurve25519
+ *
+ * Verifies that keymint can generate a curve25519 key, and that the resulting key
+ * has correct characteristics.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaCurve25519) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ EcCurve curve = EcCurve::CURVE_25519;
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ErrorCode result = GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics);
+ ASSERT_EQ(result, ErrorCode::OK);
+ ASSERT_GT(key_blob.size(), 0U);
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
+
+ CheckedDeleteKey(&key_blob);
+}
+
+/*
+ * NewKeyGenerationTest.EcCurve25519MultiPurposeFail
+ *
+ * Verifies that KeyMint rejects an attempt to generate a curve 25519 key for both
+ * SIGN and AGREE_KEY.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaCurve25519MultiPurposeFail) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ EcCurve curve = EcCurve::CURVE_25519;
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ErrorCode result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics);
+ ASSERT_EQ(result, ErrorCode::INCOMPATIBLE_PURPOSE);
+}
+
+/*
* NewKeyGenerationTest.EcdsaAttestation
*
* Verifies that for all Ecdsa key sizes, if challenge and app id is provided,
@@ -1453,6 +1636,62 @@
}
/*
+ * NewKeyGenerationTest.EcdsaAttestationCurve25519
+ *
+ * Verifies that for a curve 25519 key, if challenge and app id is provided,
+ * an attestation will be generated.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationCurve25519) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ EcCurve curve = EcCurve::CURVE_25519;
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ auto subject = "cert subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 0xFFFFFFFFFFFFFFFF;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ErrorCode result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics);
+ ASSERT_EQ(ErrorCode::OK, result);
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+ EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, //
+ sw_enforced, hw_enforced, SecLevel(),
+ cert_chain_[0].encodedCertificate));
+
+ CheckedDeleteKey(&key_blob);
+}
+
+/*
* NewKeyGenerationTest.EcdsaAttestationTags
*
* Verifies that creation of an attested ECDSA key includes various tags in the
@@ -1984,20 +2223,22 @@
}
/*
- * NewKeyGenerationTest.EcdsaInvalidSize
+ * NewKeyGenerationTest.EcdsaInvalidCurve
*
- * Verifies that specifying an invalid key size for EC key generation returns
+ * Verifies that specifying an invalid curve for EC key generation returns
* UNSUPPORTED_KEY_SIZE.
*/
-TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
+TEST_P(NewKeyGenerationTest, EcdsaInvalidCurve) {
for (auto curve : InvalidCurves()) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
- ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(curve)
- .Digest(Digest::NONE)
- .SetDefaultValidity(),
- &key_blob, &key_characteristics));
+ auto result = GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics);
+ ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
+ result == ErrorCode::UNSUPPORTED_EC_CURVE);
}
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
@@ -2808,15 +3049,19 @@
/*
* SigningOperationsTest.EcdsaAllDigestsAndCurves
*
- * Verifies ECDSA signature/verification for all digests and curves.
+ * Verifies ECDSA signature/verification for all digests and required curves.
*/
TEST_P(SigningOperationsTest, EcdsaAllDigestsAndCurves) {
- auto digests = ValidDigests(true /* withNone */, false /* withMD5 */);
string message = "1234567890";
string corrupt_message = "2234567890";
for (auto curve : ValidCurves()) {
SCOPED_TRACE(testing::Message() << "Curve::" << curve);
+ // Ed25519 only allows Digest::NONE.
+ auto digests = (curve == EcCurve::CURVE_25519)
+ ? std::vector<Digest>(1, Digest::NONE)
+ : ValidDigests(true /* withNone */, false /* withMD5 */);
+
ErrorCode error = GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(curve)
@@ -2841,25 +3086,141 @@
/*
* SigningOperationsTest.EcdsaAllCurves
*
- * Verifies that ECDSA operations succeed with all possible curves.
+ * Verifies that ECDSA operations succeed with all required curves.
*/
TEST_P(SigningOperationsTest, EcdsaAllCurves) {
for (auto curve : ValidCurves()) {
+ Digest digest = (curve == EcCurve::CURVE_25519 ? Digest::NONE : Digest::SHA_2_256);
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
ErrorCode error = GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(curve)
- .Digest(Digest::SHA_2_256)
+ .Digest(digest)
.SetDefaultValidity());
EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
if (error != ErrorCode::OK) continue;
string message(1024, 'a');
- SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+ SignMessage(message, AuthorizationSetBuilder().Digest(digest));
CheckedDeleteKey();
}
}
/*
+ * SigningOperationsTest.EcdsaCurve25519
+ *
+ * Verifies that ECDSA operations succeed with curve25519.
+ */
+TEST_P(SigningOperationsTest, EcdsaCurve25519) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ EcCurve curve = EcCurve::CURVE_25519;
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity());
+ ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+
+ string message(1024, 'a');
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE));
+ CheckedDeleteKey();
+}
+
+/*
+ * SigningOperationsTest.EcdsaCurve25519MaxSize
+ *
+ * Verifies that EDDSA operations with curve25519 under the maximum message size succeed.
+ */
+TEST_P(SigningOperationsTest, EcdsaCurve25519MaxSize) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ EcCurve curve = EcCurve::CURVE_25519;
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity());
+ ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+
+ auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+
+ for (size_t msg_size : {MAX_ED25519_MSG_SIZE - 1, MAX_ED25519_MSG_SIZE}) {
+ SCOPED_TRACE(testing::Message() << "-msg-size=" << msg_size);
+ string message(msg_size, 'a');
+
+ // Attempt to sign via Begin+Finish.
+ AuthorizationSet out_params;
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+ EXPECT_TRUE(out_params.empty());
+ string signature;
+ auto result = Finish(message, &signature);
+ EXPECT_EQ(result, ErrorCode::OK);
+ LocalVerifyMessage(message, signature, params);
+
+ // Attempt to sign via Begin+Update+Finish
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+ EXPECT_TRUE(out_params.empty());
+ string output;
+ result = Update(message, &output);
+ EXPECT_EQ(result, ErrorCode::OK);
+ EXPECT_EQ(output.size(), 0);
+ string signature2;
+ EXPECT_EQ(ErrorCode::OK, Finish({}, &signature2));
+ LocalVerifyMessage(message, signature2, params);
+ }
+
+ CheckedDeleteKey();
+}
+
+/*
+ * SigningOperationsTest.EcdsaCurve25519MaxSizeFail
+ *
+ * Verifies that EDDSA operations with curve25519 fail when message size is too large.
+ */
+TEST_P(SigningOperationsTest, EcdsaCurve25519MaxSizeFail) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ EcCurve curve = EcCurve::CURVE_25519;
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity());
+ ASSERT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+
+ auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+
+ for (size_t msg_size : {MAX_ED25519_MSG_SIZE + 1, MAX_ED25519_MSG_SIZE * 2}) {
+ SCOPED_TRACE(testing::Message() << "-msg-size=" << msg_size);
+ string message(msg_size, 'a');
+
+ // Attempt to sign via Begin+Finish.
+ AuthorizationSet out_params;
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+ EXPECT_TRUE(out_params.empty());
+ string signature;
+ auto result = Finish(message, &signature);
+ EXPECT_EQ(result, ErrorCode::INVALID_INPUT_LENGTH);
+
+ // Attempt to sign via Begin+Update (but never get to Finish)
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_, params, &out_params));
+ EXPECT_TRUE(out_params.empty());
+ string output;
+ result = Update(message, &output);
+ EXPECT_EQ(result, ErrorCode::INVALID_INPUT_LENGTH);
+ }
+
+ CheckedDeleteKey();
+}
+
+/*
* SigningOperationsTest.EcdsaNoDigestHugeData
*
* Verifies that ECDSA operations support very large messages, even without digesting. This
@@ -3509,6 +3870,255 @@
}
/*
+ * ImportKeyTest.Ed25519RawSuccess
+ *
+ * Verifies that importing and using a raw Ed25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, Ed25519RawSuccess) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::CURVE_25519)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ KeyFormat::RAW, ed25519_key));
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+ CheckOrigin();
+
+ // The returned cert should hold the correct public key.
+ ASSERT_GT(cert_chain_.size(), 0);
+ X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ ASSERT_NE(kmKeyCert, nullptr);
+ EVP_PKEY_Ptr kmPubKey(X509_get_pubkey(kmKeyCert.get()));
+ ASSERT_NE(kmPubKey.get(), nullptr);
+ size_t kmPubKeySize = 32;
+ uint8_t kmPubKeyData[32];
+ ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+ ASSERT_EQ(kmPubKeySize, 32);
+ EXPECT_EQ(string(kmPubKeyData, kmPubKeyData + 32), ed25519_pubkey);
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+ string signature = SignMessage(message, params);
+ LocalVerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ed25519Pkcs8Success
+ *
+ * Verifies that importing and using a PKCS#8-encoded Ed25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, Ed25519Pkcs8Success) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::CURVE_25519)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, ed25519_pkcs8_key));
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+ CheckOrigin();
+
+ // The returned cert should hold the correct public key.
+ ASSERT_GT(cert_chain_.size(), 0);
+ X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ ASSERT_NE(kmKeyCert, nullptr);
+ EVP_PKEY_Ptr kmPubKey(X509_get_pubkey(kmKeyCert.get()));
+ ASSERT_NE(kmPubKey.get(), nullptr);
+ size_t kmPubKeySize = 32;
+ uint8_t kmPubKeyData[32];
+ ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+ ASSERT_EQ(kmPubKeySize, 32);
+ EXPECT_EQ(string(kmPubKeyData, kmPubKeyData + 32), ed25519_pubkey);
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+ string signature = SignMessage(message, params);
+ LocalVerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ed25519CurveMismatch
+ *
+ * Verifies that importing an Ed25519 key pair with a curve that doesn't match the key fails in
+ * the correct way.
+ */
+TEST_P(ImportKeyTest, Ed25519CurveMismatch) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_NE(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ KeyFormat::RAW, ed25519_key));
+}
+
+/*
+ * ImportKeyTest.Ed25519FormatMismatch
+ *
+ * Verifies that importing an Ed25519 key pair with an invalid format fails.
+ */
+TEST_P(ImportKeyTest, Ed25519FormatMismatch) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::CURVE_25519)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, ed25519_key));
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::CURVE_25519)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ KeyFormat::RAW, ed25519_pkcs8_key));
+}
+
+/*
+ * ImportKeyTest.Ed25519PurposeMismatch
+ *
+ * Verifies that importing an Ed25519 key pair with an invalid purpose fails.
+ */
+TEST_P(ImportKeyTest, Ed25519PurposeMismatch) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ // Can't have both SIGN and ATTEST_KEY
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ KeyFormat::RAW, ed25519_key));
+ // AGREE_KEY is for X25519 (but can only tell the difference if the import key is in
+ // PKCS#8 format and so includes an OID).
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, ed25519_pkcs8_key));
+}
+
+/*
+ * ImportKeyTest.X25519RawSuccess
+ *
+ * Verifies that importing and using a raw X25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, X25519RawSuccess) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .SetDefaultValidity(),
+ KeyFormat::RAW, x25519_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+ CheckOrigin();
+}
+
+/*
+ * ImportKeyTest.X25519Pkcs8Success
+ *
+ * Verifies that importing and using a PKCS#8-encoded X25519 private key works correctly.
+ */
+TEST_P(ImportKeyTest, X25519Pkcs8Success) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, x25519_pkcs8_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::CURVE_25519);
+ CheckOrigin();
+}
+
+/*
+ * ImportKeyTest.X25519CurveMismatch
+ *
+ * Verifies that importing an X25519 key with a curve that doesn't match the key fails in
+ * the correct way.
+ */
+TEST_P(ImportKeyTest, X25519CurveMismatch) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::P_224 /* Doesn't match key */)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .SetDefaultValidity(),
+ KeyFormat::RAW, x25519_key));
+}
+
+/*
+ * ImportKeyTest.X25519FormatMismatch
+ *
+ * Verifies that importing an X25519 key with an invalid format fails.
+ */
+TEST_P(ImportKeyTest, X25519FormatMismatch) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, x25519_key));
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .SetDefaultValidity(),
+ KeyFormat::RAW, x25519_pkcs8_key));
+}
+
+/*
+ * ImportKeyTest.X25519PurposeMismatch
+ *
+ * Verifies that importing an X25519 key pair with an invalid format fails.
+ */
+TEST_P(ImportKeyTest, X25519PurposeMismatch) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, x25519_pkcs8_key));
+ ASSERT_NE(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::CURVE_25519)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, x25519_pkcs8_key));
+}
+
+/*
* ImportKeyTest.AesSuccess
*
* Verifies that importing and using an AES key works.
@@ -6703,8 +7313,6 @@
INSTANTIATE_KEYMINT_AIDL_TEST(TransportLimitTest);
-typedef KeyMintAidlTestBase KeyAgreementTest;
-
static int EcdhCurveToOpenSslCurveName(EcCurve curve) {
switch (curve) {
case EcCurve::P_224:
@@ -6720,10 +7328,108 @@
}
}
+class KeyAgreementTest : public KeyMintAidlTestBase {
+ protected:
+ void GenerateLocalEcKey(EcCurve localCurve, EVP_PKEY_Ptr* localPrivKey,
+ std::vector<uint8_t>* localPublicKey) {
+ // Generate EC key locally (with access to private key material)
+ if (localCurve == EcCurve::CURVE_25519) {
+ uint8_t privKeyData[32];
+ uint8_t pubKeyData[32];
+ X25519_keypair(pubKeyData, privKeyData);
+ *localPublicKey = vector<uint8_t>(pubKeyData, pubKeyData + 32);
+ *localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new_raw_private_key(
+ EVP_PKEY_X25519, nullptr, privKeyData, sizeof(privKeyData)));
+ } else {
+ auto ecKey = EC_KEY_Ptr(EC_KEY_new());
+ int curveName = EcdhCurveToOpenSslCurveName(localCurve);
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curveName));
+ ASSERT_NE(group, nullptr);
+ ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
+ ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1);
+ *localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new());
+ ASSERT_EQ(EVP_PKEY_set1_EC_KEY(localPrivKey->get(), ecKey.get()), 1);
+
+ // Get encoded form of the public part of the locally generated key...
+ unsigned char* p = nullptr;
+ int localPublicKeySize = i2d_PUBKEY(localPrivKey->get(), &p);
+ ASSERT_GT(localPublicKeySize, 0);
+ *localPublicKey =
+ vector<uint8_t>(reinterpret_cast<const uint8_t*>(p),
+ reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
+ OPENSSL_free(p);
+ }
+ }
+
+ void GenerateKeyMintEcKey(EcCurve curve, EVP_PKEY_Ptr* kmPubKey) {
+ vector<uint8_t> challenge = {0x41, 0x42};
+ ErrorCode result =
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_EC_CURVE, curve)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .Authorization(TAG_ALGORITHM, Algorithm::EC)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62})
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .SetDefaultValidity());
+ ASSERT_EQ(ErrorCode::OK, result) << "Failed to generate key";
+ ASSERT_GT(cert_chain_.size(), 0);
+ X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ ASSERT_NE(kmKeyCert, nullptr);
+ // Check that keyAgreement (bit 4) is set in KeyUsage
+ EXPECT_TRUE((X509_get_key_usage(kmKeyCert.get()) & X509v3_KU_KEY_AGREEMENT) != 0);
+ *kmPubKey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get()));
+ ASSERT_NE(*kmPubKey, nullptr);
+ if (dump_Attestations) {
+ for (size_t n = 0; n < cert_chain_.size(); n++) {
+ std::cout << bin2hex(cert_chain_[n].encodedCertificate) << std::endl;
+ }
+ }
+ }
+
+ void CheckAgreement(EVP_PKEY_Ptr kmPubKey, EVP_PKEY_Ptr localPrivKey,
+ const std::vector<uint8_t>& localPublicKey) {
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ string ZabFromKeyMintStr;
+ ASSERT_EQ(ErrorCode::OK,
+ Finish(string(localPublicKey.begin(), localPublicKey.end()), &ZabFromKeyMintStr));
+ vector<uint8_t> ZabFromKeyMint(ZabFromKeyMintStr.begin(), ZabFromKeyMintStr.end());
+ vector<uint8_t> ZabFromTest;
+
+ if (EVP_PKEY_id(kmPubKey.get()) == EVP_PKEY_X25519) {
+ size_t kmPubKeySize = 32;
+ uint8_t kmPubKeyData[32];
+ ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+ ASSERT_EQ(kmPubKeySize, 32);
+
+ uint8_t localPrivKeyData[32];
+ size_t localPrivKeySize = 32;
+ ASSERT_EQ(1, EVP_PKEY_get_raw_private_key(localPrivKey.get(), localPrivKeyData,
+ &localPrivKeySize));
+ ASSERT_EQ(localPrivKeySize, 32);
+
+ uint8_t sharedKey[32];
+ ASSERT_EQ(1, X25519(sharedKey, localPrivKeyData, kmPubKeyData));
+ ZabFromTest = std::vector<uint8_t>(sharedKey, sharedKey + 32);
+ } else {
+ // Perform local ECDH between the two keys so we can check if we get the same Zab..
+ auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(localPrivKey.get(), nullptr));
+ ASSERT_NE(ctx, nullptr);
+ ASSERT_EQ(EVP_PKEY_derive_init(ctx.get()), 1);
+ ASSERT_EQ(EVP_PKEY_derive_set_peer(ctx.get(), kmPubKey.get()), 1);
+ size_t ZabFromTestLen = 0;
+ ASSERT_EQ(EVP_PKEY_derive(ctx.get(), nullptr, &ZabFromTestLen), 1);
+ ZabFromTest.resize(ZabFromTestLen);
+ ASSERT_EQ(EVP_PKEY_derive(ctx.get(), ZabFromTest.data(), &ZabFromTestLen), 1);
+ }
+ EXPECT_EQ(ZabFromKeyMint, ZabFromTest);
+ }
+};
+
/*
* KeyAgreementTest.Ecdh
*
- * Verifies that ECDH works for all curves
+ * Verifies that ECDH works for all required curves
*/
TEST_P(KeyAgreementTest, Ecdh) {
// Because it's possible to use this API with keys on different curves, we
@@ -6737,49 +7443,13 @@
for (auto curve : ValidCurves()) {
for (auto localCurve : ValidCurves()) {
// Generate EC key locally (with access to private key material)
- auto ecKey = EC_KEY_Ptr(EC_KEY_new());
- int curveName = EcdhCurveToOpenSslCurveName(localCurve);
- auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curveName));
- ASSERT_NE(group, nullptr);
- ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
- ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1);
- auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
- ASSERT_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()), 1);
-
- // Get encoded form of the public part of the locally generated key...
- unsigned char* p = nullptr;
- int encodedPublicKeySize = i2d_PUBKEY(pkey.get(), &p);
- ASSERT_GT(encodedPublicKeySize, 0);
- vector<uint8_t> encodedPublicKey(
- reinterpret_cast<const uint8_t*>(p),
- reinterpret_cast<const uint8_t*>(p + encodedPublicKeySize));
- OPENSSL_free(p);
+ EVP_PKEY_Ptr localPrivKey;
+ vector<uint8_t> localPublicKey;
+ GenerateLocalEcKey(localCurve, &localPrivKey, &localPublicKey);
// Generate EC key in KeyMint (only access to public key material)
- vector<uint8_t> challenge = {0x41, 0x42};
- EXPECT_EQ(
- ErrorCode::OK,
- GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .Authorization(TAG_EC_CURVE, curve)
- .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
- .Authorization(TAG_ALGORITHM, Algorithm::EC)
- .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62})
- .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
- .SetDefaultValidity()))
- << "Failed to generate key";
- ASSERT_GT(cert_chain_.size(), 0);
- X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
- ASSERT_NE(kmKeyCert, nullptr);
- // Check that keyAgreement (bit 4) is set in KeyUsage
- EXPECT_TRUE((X509_get_key_usage(kmKeyCert.get()) & X509v3_KU_KEY_AGREEMENT) != 0);
- auto kmPkey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get()));
- ASSERT_NE(kmPkey, nullptr);
- if (dump_Attestations) {
- for (size_t n = 0; n < cert_chain_.size(); n++) {
- std::cout << bin2hex(cert_chain_[n].encodedCertificate) << std::endl;
- }
- }
+ EVP_PKEY_Ptr kmPubKey;
+ GenerateKeyMintEcKey(curve, &kmPubKey);
// Now that we have the two keys, we ask KeyMint to perform ECDH...
if (curve != localCurve) {
@@ -6788,30 +7458,12 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
string ZabFromKeyMintStr;
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
- Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
+ Finish(string(localPublicKey.begin(), localPublicKey.end()),
&ZabFromKeyMintStr));
} else {
// Otherwise if the keys are using the same curve, it should work.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
- string ZabFromKeyMintStr;
- EXPECT_EQ(ErrorCode::OK,
- Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
- &ZabFromKeyMintStr));
- vector<uint8_t> ZabFromKeyMint(ZabFromKeyMintStr.begin(), ZabFromKeyMintStr.end());
-
- // Perform local ECDH between the two keys so we can check if we get the same Zab..
- auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(pkey.get(), nullptr));
- ASSERT_NE(ctx, nullptr);
- ASSERT_EQ(EVP_PKEY_derive_init(ctx.get()), 1);
- ASSERT_EQ(EVP_PKEY_derive_set_peer(ctx.get(), kmPkey.get()), 1);
- size_t ZabFromTestLen = 0;
- ASSERT_EQ(EVP_PKEY_derive(ctx.get(), nullptr, &ZabFromTestLen), 1);
- vector<uint8_t> ZabFromTest;
- ZabFromTest.resize(ZabFromTestLen);
- ASSERT_EQ(EVP_PKEY_derive(ctx.get(), ZabFromTest.data(), &ZabFromTestLen), 1);
-
- EXPECT_EQ(ZabFromKeyMint, ZabFromTest);
+ CheckAgreement(std::move(kmPubKey), std::move(localPrivKey), localPublicKey);
}
CheckedDeleteKey();
@@ -6819,6 +7471,140 @@
}
}
+/*
+ * KeyAgreementTest.EcdhCurve25519
+ *
+ * Verifies that ECDH works for curve25519. This is also covered by the general
+ * KeyAgreementTest.Ecdh case, but is pulled out separately here because this curve was added after
+ * KeyMint 1.0.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ // Generate EC key in KeyMint (only access to public key material)
+ EcCurve curve = EcCurve::CURVE_25519;
+ EVP_PKEY_Ptr kmPubKey = nullptr;
+ GenerateKeyMintEcKey(curve, &kmPubKey);
+
+ // Generate EC key on same curve locally (with access to private key material).
+ EVP_PKEY_Ptr privKey;
+ vector<uint8_t> encodedPublicKey;
+ GenerateLocalEcKey(curve, &privKey, &encodedPublicKey);
+
+ // Agree on a key between local and KeyMint and check it.
+ CheckAgreement(std::move(kmPubKey), std::move(privKey), encodedPublicKey);
+
+ CheckedDeleteKey();
+}
+
+/*
+ * KeyAgreementTest.EcdhCurve25519Imported
+ *
+ * Verifies that ECDH works for an imported curve25519 key.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519Imported) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ // Import x25519 key into KeyMint.
+ EcCurve curve = EcCurve::CURVE_25519;
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, x25519_pkcs8_key));
+ ASSERT_GT(cert_chain_.size(), 0);
+ X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ ASSERT_NE(kmKeyCert, nullptr);
+ EVP_PKEY_Ptr kmPubKey(X509_get_pubkey(kmKeyCert.get()));
+ ASSERT_NE(kmPubKey.get(), nullptr);
+
+ // Expect the import to emit corresponding public key data.
+ size_t kmPubKeySize = 32;
+ uint8_t kmPubKeyData[32];
+ ASSERT_EQ(1, EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+ ASSERT_EQ(kmPubKeySize, 32);
+ EXPECT_EQ(bin2hex(std::vector<uint8_t>(kmPubKeyData, kmPubKeyData + 32)),
+ bin2hex(std::vector<uint8_t>(x25519_pubkey.begin(), x25519_pubkey.end())));
+
+ // Generate EC key on same curve locally (with access to private key material).
+ EVP_PKEY_Ptr privKey;
+ vector<uint8_t> encodedPublicKey;
+ GenerateLocalEcKey(curve, &privKey, &encodedPublicKey);
+
+ // Agree on a key between local and KeyMint and check it.
+ CheckAgreement(std::move(kmPubKey), std::move(privKey), encodedPublicKey);
+
+ CheckedDeleteKey();
+}
+
+/*
+ * KeyAgreementTest.EcdhCurve25519InvalidSize
+ *
+ * Verifies that ECDH fails for curve25519 if the wrong size of public key is provided.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519InvalidSize) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ // Generate EC key in KeyMint (only access to public key material)
+ EcCurve curve = EcCurve::CURVE_25519;
+ EVP_PKEY_Ptr kmPubKey = nullptr;
+ GenerateKeyMintEcKey(curve, &kmPubKey);
+
+ // Generate EC key on same curve locally (with access to private key material).
+ EVP_PKEY_Ptr privKey;
+ vector<uint8_t> encodedPublicKey;
+ GenerateLocalEcKey(curve, &privKey, &encodedPublicKey);
+
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ string ZabFromKeyMintStr;
+ // Send in an incomplete public key.
+ ASSERT_NE(ErrorCode::OK, Finish(string(encodedPublicKey.begin(), encodedPublicKey.end() - 1),
+ &ZabFromKeyMintStr));
+
+ CheckedDeleteKey();
+}
+
+/*
+ * KeyAgreementTest.EcdhCurve25519Mismatch
+ *
+ * Verifies that ECDH fails between curve25519 and other curves.
+ */
+TEST_P(KeyAgreementTest, EcdhCurve25519Mismatch) {
+ if (!Curve25519Supported()) {
+ GTEST_SKIP() << "Test not applicable to device that is not expected to support curve 25519";
+ }
+
+ // Generate EC key in KeyMint (only access to public key material)
+ EcCurve curve = EcCurve::CURVE_25519;
+ EVP_PKEY_Ptr kmPubKey = nullptr;
+ GenerateKeyMintEcKey(curve, &kmPubKey);
+
+ for (auto localCurve : ValidCurves()) {
+ if (localCurve == curve) {
+ continue;
+ }
+ // Generate EC key on a different curve locally (with access to private key material).
+ EVP_PKEY_Ptr privKey;
+ vector<uint8_t> encodedPublicKey;
+ GenerateLocalEcKey(localCurve, &privKey, &encodedPublicKey);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ string ZabFromKeyMintStr;
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
+ Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
+ &ZabFromKeyMintStr));
+ }
+
+ CheckedDeleteKey();
+}
+
INSTANTIATE_KEYMINT_AIDL_TEST(KeyAgreementTest);
using DestroyAttestationIdsTest = KeyMintAidlTestBase;
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 53ceb0d..43ee327 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -190,8 +190,6 @@
}
default: {
- CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
memcpy(dst->u.data.data(), src.data, 16 * sizeof(float));
break;
}
@@ -330,9 +328,6 @@
}
default: {
- CHECK_GE((int32_t)src.sensorType,
- (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
memcpy(dst->data, src.u.data.data(), 16 * sizeof(float));
break;
}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl
index c92ab1a..4f49002 100644
--- a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl
@@ -52,6 +52,9 @@
android.hardware.sensors.AdditionalInfo additional;
android.hardware.sensors.Event.EventPayload.Data data;
android.hardware.sensors.Event.EventPayload.HeadTracker headTracker;
+ android.hardware.sensors.Event.EventPayload.LimitedAxesImu limitedAxesImu;
+ android.hardware.sensors.Event.EventPayload.LimitedAxesImuUncal limitedAxesImuUncal;
+ android.hardware.sensors.Event.EventPayload.Heading heading;
@FixedSize @VintfStability
parcelable Vec4 {
float x;
@@ -86,11 +89,37 @@
int discontinuityCount;
}
@FixedSize @VintfStability
+ parcelable LimitedAxesImu {
+ float x;
+ float y;
+ float z;
+ float xSupported;
+ float ySupported;
+ float zSupported;
+ }
+ @FixedSize @VintfStability
+ parcelable LimitedAxesImuUncal {
+ float x;
+ float y;
+ float z;
+ float xBias;
+ float yBias;
+ float zBias;
+ float xSupported;
+ float ySupported;
+ float zSupported;
+ }
+ @FixedSize @VintfStability
parcelable HeartRate {
float bpm;
android.hardware.sensors.SensorStatus status;
}
@FixedSize @VintfStability
+ parcelable Heading {
+ float heading;
+ float accuracy;
+ }
+ @FixedSize @VintfStability
parcelable MetaData {
android.hardware.sensors.Event.EventPayload.MetaData.MetaDataEventType what;
@Backing(type="int") @VintfStability
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl
index 3d7ab45..8c864e9 100644
--- a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl
@@ -71,5 +71,10 @@
ACCELEROMETER_UNCALIBRATED = 35,
HINGE_ANGLE = 36,
HEAD_TRACKER = 37,
+ ACCELEROMETER_LIMITED_AXES = 38,
+ GYROSCOPE_LIMITED_AXES = 39,
+ ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40,
+ GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41,
+ HEADING = 42,
DEVICE_PRIVATE_BASE = 65536,
}
diff --git a/sensors/aidl/android/hardware/sensors/Event.aidl b/sensors/aidl/android/hardware/sensors/Event.aidl
index fd6a8cc..e8550f1 100644
--- a/sensors/aidl/android/hardware/sensors/Event.aidl
+++ b/sensors/aidl/android/hardware/sensors/Event.aidl
@@ -132,6 +132,23 @@
*/
HeadTracker headTracker;
+ /**
+ * SensorType::ACCELEROMETER_LIMITED_AXES
+ * SensorType::GYROSCOPE_LIMITED_AXES
+ */
+ LimitedAxesImu limitedAxesImu;
+
+ /**
+ * SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED
+ * SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED
+ */
+ LimitedAxesImuUncal limitedAxesImuUncal;
+
+ /**
+ * SensorType::HEADING
+ */
+ Heading heading;
+
@FixedSize
@VintfStability
parcelable Vec4 {
@@ -201,6 +218,70 @@
int discontinuityCount;
}
+ /**
+ * Payload of the ACCELEROMETER_LIMITED_AXES and GYROSCOPE_LIMITED_AXES
+ * sensor types.
+ */
+ @FixedSize
+ @VintfStability
+ parcelable LimitedAxesImu {
+ /**
+ * Acceleration or angular speed values. If certain axes are not
+ * supported, the associated value must be set to 0.
+ */
+ float x;
+ float y;
+ float z;
+
+ /**
+ * Limited axes sensors must not be supported for all three axes.
+ * These values indicate which axes are supported with a 1.0 for
+ * supported, and a 0 for not supported. The supported axes should
+ * be determined at build time and these values must not change
+ * during runtime.
+ */
+ float xSupported;
+ float ySupported;
+ float zSupported;
+ }
+
+ /**
+ * Payload of the ACCELEROMETER_LIMITED_AXES_UNCALIBRATED and
+ * GYROSCOPE_LIMITED_AXES_UNCALIBRATED sensor types.
+ */
+ @FixedSize
+ @VintfStability
+ parcelable LimitedAxesImuUncal {
+ /**
+ * Acceleration (without bias compensation) or angular (speed
+ * (without drift compensation) values. If certain axes are not
+ * supported, the associated value must be set to 0.
+ */
+ float x;
+ float y;
+ float z;
+
+ /**
+ * Estimated bias values for uncalibrated accelerometer or
+ * estimated drift values for uncalibrated gyroscope. If certain
+ * axes are not supported, the associated value must be set to 0.
+ */
+ float xBias;
+ float yBias;
+ float zBias;
+
+ /**
+ * Limited axes sensors must not be supported for all three axes.
+ * These values indicate which axes are supported with a 1.0 for
+ * supported, and a 0 for not supported. The supported axes should
+ * be determined at build time and these values must not change
+ * during runtime.
+ */
+ float xSupported;
+ float ySupported;
+ float zSupported;
+ }
+
@FixedSize
@VintfStability
parcelable HeartRate {
@@ -218,6 +299,27 @@
@FixedSize
@VintfStability
+ parcelable Heading {
+ /**
+ * The direction in which the device is pointing relative to true
+ * north in degrees. The value must be between 0.0 (inclusive) and
+ * 360.0 (exclusive), with 0 indicating north, 90 east, 180 south,
+ * and 270 west.
+ */
+ float heading;
+ /**
+ * Accuracy is defined at 68% confidence. In the case where the
+ * underlying distribution is assumed Gaussian normal, this would be
+ * considered one standard deviation. For example, if the heading
+ * returns 60 degrees, and accuracy returns 10 degrees, then there
+ * is a 68 percent probability of the true heading being between 50
+ * degrees and 70 degrees.
+ */
+ float accuracy;
+ }
+
+ @FixedSize
+ @VintfStability
parcelable MetaData {
MetaDataEventType what;
diff --git a/sensors/aidl/android/hardware/sensors/SensorType.aidl b/sensors/aidl/android/hardware/sensors/SensorType.aidl
index 01e6bee..9098894 100644
--- a/sensors/aidl/android/hardware/sensors/SensorType.aidl
+++ b/sensors/aidl/android/hardware/sensors/SensorType.aidl
@@ -667,6 +667,57 @@
HEAD_TRACKER = 37,
/**
+ * ACCELEROMETER_LIMITED_AXES
+ * reporting-mode: continuous
+ *
+ * Equivalent to ACCELEROMETER, but supporting cases where one or two axes
+ * are not supported.
+ */
+ ACCELEROMETER_LIMITED_AXES = 38,
+
+ /**
+ * GYROSCOPE_LIMITED_AXES
+ * reporting-mode: continuous
+ *
+ * Equivalent to GYROSCOPE, but supporting cases where one or two axes are
+ * not supported.
+ */
+ GYROSCOPE_LIMITED_AXES = 39,
+
+ /**
+ * ACCELEROMETER_LIMITED_AXES_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * Equivalent to ACCELEROMETER_UNCALIBRATED, but supporting cases where one
+ * or two axes are not supported.
+ */
+ ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40,
+
+ /**
+ * GYROSCOPE_LIMITED_AXES_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * Equivalent to GYROSCOPE_UNCALIBRATED, but supporting cases where one or
+ * two axes are not supported.
+ */
+ GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41,
+
+ /**
+ * HEADING
+ * reporting-mode: continuous
+ *
+ * A sensor of this type measures the direction in which the device is
+ * pointing relative to true north in degrees.
+ *
+ * This sensor was added for automotive form factors. Other devices with a
+ * clear forward direction might find it useful as well. However, devices
+ * with a more ambiguous orientation such as phones or wearables might want
+ * to consider using other sensors such as Sensor.TYPE_ROTATION_VECTOR
+ * which might be more suitable.
+ */
+ HEADING = 42,
+
+ /**
* Base for device manufacturers private sensor types.
* These sensor types can't be exposed in the SDK.
*/
diff --git a/sensors/aidl/default/multihal/ConvertUtils.cpp b/sensors/aidl/default/multihal/ConvertUtils.cpp
index 4d6697b..509bbb0 100644
--- a/sensors/aidl/default/multihal/ConvertUtils.cpp
+++ b/sensors/aidl/default/multihal/ConvertUtils.cpp
@@ -131,7 +131,7 @@
break;
case AidlSensorType::POSE_6DOF:
std::copy(std::begin(aidlEvent.payload.get<AidlEvent::EventPayload::pose6DOF>().values),
- std::end(aidlEvent.payload.get<AidlEvent::EventPayload::data>().values),
+ std::end(aidlEvent.payload.get<AidlEvent::EventPayload::pose6DOF>().values),
hidlEvent->u.pose6DOF.data());
break;
case AidlSensorType::DYNAMIC_SENSOR_META:
@@ -318,4 +318,4 @@
} // namespace sensors
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl b/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl
index 2a3fc64..618331b 100644
--- a/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl
+++ b/soundtrigger/aidl/android/hardware/soundtrigger3/ISoundTriggerHw.aidl
@@ -18,15 +18,12 @@
import android.hardware.soundtrigger3.ISoundTriggerHwCallback;
import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback;
-
+import android.media.soundtrigger.ModelParameter;
+import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.SoundModel;
-import android.media.soundtrigger.ModelParameter;
-import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.Properties;
-import android.media.soundtrigger.RecognitionConfig;
/**
* SoundTrigger HAL interface. Used for hardware recognition of hotwords
@@ -196,12 +193,12 @@
* an audio stream associated with this recognition session.
* @param config A RecognitionConfig structure containing attributes of the recognition to
* perform.
- * @throws ServiceSpecificException(RESOURCE_CONTENTION) if the model cannot be started due
+ * @throws ServiceSpecificException(RESOURCE_CONTENTION) if the model cannot be started due
* to resource constraints. This is typically a temporary condition and the client may
* retry after the onResourcesAvailable() global callback is invoked.
- */
- void startRecognition(in int modelHandle, in int deviceHandle,
- in int ioHandle, in RecognitionConfig config);
+ */
+ void startRecognition(
+ in int modelHandle, in int deviceHandle, in int ioHandle, in RecognitionConfig config);
/**
* Stop recognition on a given model.
@@ -235,7 +232,8 @@
* @return This structure indicates supported attributes of the parameter for the given model
* handle. If the parameter is not supported, null is returned.
*/
- @nullable ModelParameterRange queryParameter(in int modelHandle, in ModelParameter modelParam);
+ @nullable ModelParameterRange queryParameter(
+ in int modelHandle, in ModelParameter modelParam);
/**
* Get a model specific parameter.
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
index fc0efc9..1e0f5f0 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatus.aidl
@@ -76,4 +76,5 @@
android.hardware.tv.tuner.FrontendIsdbtPartialReceptionFlag partialReceptionFlag;
int[] streamIdList;
int[] dvbtCellIds;
+ android.hardware.tv.tuner.FrontendScanAtsc3PlpInfo[] allPlpInfo;
}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
index 2cc62d5..cd6ccb3 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusType.aidl
@@ -76,4 +76,5 @@
ISDBT_PARTIAL_RECEPTION_FLAG = 38,
STREAM_ID_LIST = 39,
DVBT_CELL_IDS = 40,
+ ATSC3_ALL_PLP_INFO = 41,
}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
index e7aa070..e240e40 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
@@ -46,4 +46,5 @@
int linkCiCam(in int ciCamId);
void unlinkCiCam(in int ciCamId);
String getHardwareInfo();
+ void removeOutputPid(int pid);
}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
index ae6e46f..b5d0201 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatus.aidl
@@ -27,6 +27,7 @@
import android.hardware.tv.tuner.FrontendModulationStatus;
import android.hardware.tv.tuner.FrontendRollOff;
import android.hardware.tv.tuner.FrontendSpectralInversion;
+import android.hardware.tv.tuner.FrontendScanAtsc3PlpInfo;
import android.hardware.tv.tuner.FrontendStatusAtsc3PlpInfo;
import android.hardware.tv.tuner.FrontendTransmissionMode;
import android.hardware.tv.tuner.LnbVoltage;
@@ -241,5 +242,9 @@
*/
int[] dvbtCellIds;
-
+ /**
+ * A list of all PLPs in the frequency band for ATSC3 frontend, which includes both tuned
+ * and not tuned PLPs for currently watching service.
+ */
+ FrontendScanAtsc3PlpInfo[] allPlpInfo;
}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
index e7da517..8f3f2c5 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusType.aidl
@@ -130,7 +130,7 @@
RF_LOCK,
/**
- * PLP information in a frequency band for ATSC3.0 frontend.
+ * Current tuned PLP information in a frequency band for ATSC3 frontend.
*/
ATSC3_PLP_INFO,
@@ -222,10 +222,16 @@
/**
* Stream ID list included in a transponder.
*/
- STREAM_ID_LIST,
+ STREAM_ID_LIST,
- /**
- * DVB-T Cell Id.
- */
- DVBT_CELL_IDS,
+ /**
+ * DVB-T Cell Id.
+ */
+ DVBT_CELL_IDS,
+
+ /**
+ * All PLP information in a frequency band for ATSC3 frontend, which includes both tuned
+ * and not tuned PLPs for currently watching service.
+ */
+ ATSC3_ALL_PLP_INFO,
}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
index 5b3ce39..f8248e6 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
@@ -146,4 +146,13 @@
* @return the frontend hardware information.
*/
String getHardwareInfo();
+
+ /**
+ * Filter out unnecessary PID from frontend output.
+ *
+ * @param pid specify the PID will be filtered out.
+ *
+ * @return UNAVAILABLE if the frontend doesn’t support PID filtering out.
+ */
+ void removeOutputPid(int pid);
}
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 714612d..f0bf001 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -708,6 +708,20 @@
status.set<FrontendStatus::dvbtCellIds>(dvbtCellIds);
break;
}
+ case FrontendStatusType::ATSC3_ALL_PLP_INFO: {
+ FrontendScanAtsc3PlpInfo info1;
+ info1.plpId = 1;
+ info1.bLlsFlag = false;
+ FrontendScanAtsc3PlpInfo info2;
+ info2.plpId = 2;
+ info2.bLlsFlag = true;
+ FrontendScanAtsc3PlpInfo info3;
+ info3.plpId = 3;
+ info3.bLlsFlag = false;
+ vector<FrontendScanAtsc3PlpInfo> infos = {info1, info2, info3};
+ status.set<FrontendStatus::allPlpInfo>(infos);
+ break;
+ }
default: {
continue;
}
@@ -759,6 +773,13 @@
return ::ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus Frontend::removeOutputPid(int32_t /* in_pid */) {
+ ALOGV("%s", __FUNCTION__);
+
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
FrontendType Frontend::getFrontendType() {
return mType;
}
diff --git a/tv/tuner/aidl/default/Frontend.h b/tv/tuner/aidl/default/Frontend.h
index fdedf1e..3df1aa1 100644
--- a/tv/tuner/aidl/default/Frontend.h
+++ b/tv/tuner/aidl/default/Frontend.h
@@ -50,6 +50,7 @@
::ndk::ScopedAStatus linkCiCam(int32_t in_ciCamId, int32_t* _aidl_return) override;
::ndk::ScopedAStatus unlinkCiCam(int32_t in_ciCamId) override;
::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index 48c1b66..7a5fa6e 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -77,6 +77,7 @@
FrontendStatusType::BERS,
FrontendStatusType::INTERLEAVINGS,
FrontendStatusType::BANDWIDTH,
+ FrontendStatusType::ATSC3_ALL_PLP_INFO,
};
mFrontendStatusCaps[1] = statusCaps;
mMaxUsableFrontends[FrontendType::ATSC3] = 1;
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 41e98ea..62d9b74 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -298,6 +298,13 @@
return AssertionResult(status.isOk());
}
+AssertionResult FrontendTests::removeOutputPid(int32_t removePid) {
+ ndk::ScopedAStatus status;
+ status = mFrontend->removeOutputPid(removePid);
+ return AssertionResult(status.isOk() || status.getServiceSpecificError() ==
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
AssertionResult FrontendTests::unlinkCiCam(int32_t ciCamId) {
ndk::ScopedAStatus status = mFrontend->unlinkCiCam(ciCamId);
return AssertionResult(status.isOk());
@@ -414,6 +421,13 @@
expectStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().begin()));
break;
}
+ case FrontendStatusType::ATSC3_ALL_PLP_INFO: {
+ ASSERT_TRUE(std::equal(
+ realStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().begin(),
+ realStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().end(),
+ expectStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().begin()));
+ break;
+ }
default: {
continue;
}
@@ -501,6 +515,7 @@
ASSERT_TRUE(setFrontendCallback());
if (frontendConf.canConnectToCiCam) {
ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
+ ASSERT_TRUE(removeOutputPid(frontendConf.removePid));
ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
}
ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.h b/tv/tuner/aidl/vts/functional/FrontendTests.h
index 1745f76..537c419 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.h
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.h
@@ -95,6 +95,7 @@
AssertionResult linkCiCam(int32_t ciCamId);
AssertionResult unlinkCiCam(int32_t ciCamId);
AssertionResult verifyHardwareInfo();
+ AssertionResult removeOutputPid(int32_t removePid);
void getFrontendIdByType(FrontendType feType, int32_t& feId);
void tuneTest(FrontendConfig frontendConf);
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index b73d594..3009c4a 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -83,6 +83,7 @@
FrontendType type;
bool canConnectToCiCam;
int32_t ciCamId;
+ int32_t removePid;
FrontendSettings settings;
vector<FrontendStatusType> tuneStatusTypes;
vector<FrontendStatus> expectTuneStatuses;
@@ -304,7 +305,8 @@
// TODO: b/182519645 complete the tune status config
frontendMap[id].tuneStatusTypes = types;
frontendMap[id].expectTuneStatuses = statuses;
- getCiCamInfo(feConfig, frontendMap[id].canConnectToCiCam, frontendMap[id].ciCamId);
+ getCiCamInfo(feConfig, frontendMap[id].canConnectToCiCam, frontendMap[id].ciCamId,
+ frontendMap[id].removePid);
}
}
}
@@ -1004,13 +1006,16 @@
return recordSettings;
}
- static void getCiCamInfo(Frontend feConfig, bool& canConnectToCiCam, int32_t& ciCamId) {
+ static void getCiCamInfo(Frontend feConfig, bool& canConnectToCiCam, int32_t& ciCamId,
+ int32_t& removePid) {
if (!feConfig.hasConnectToCicamId()) {
canConnectToCiCam = false;
ciCamId = -1;
+ removePid = -1;
return;
}
canConnectToCiCam = true;
ciCamId = static_cast<int32_t>(feConfig.getConnectToCicamId());
+ removePid = static_cast<int32_t>(feConfig.getRemoveOutputPid());
}
};
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index 4d519d7..383d49f 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -317,6 +317,7 @@
method @Nullable public java.math.BigInteger getFrequency();
method @Nullable public String getId();
method @Nullable public boolean getIsSoftwareFrontend();
+ method @Nullable public java.math.BigInteger getRemoveOutputPid();
method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
method public void setConnectToCicamId(@Nullable java.math.BigInteger);
method public void setDvbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings);
@@ -325,6 +326,7 @@
method public void setFrequency(@Nullable java.math.BigInteger);
method public void setId(@Nullable String);
method public void setIsSoftwareFrontend(@Nullable boolean);
+ method public void setRemoveOutputPid(@Nullable java.math.BigInteger);
method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
}
diff --git a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
index da77200..fefe86e 100644
--- a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
@@ -42,6 +42,8 @@
"softwareFeInputPath": used as the source of the software frontend.
"connectToCicamId": if the device supports frontend connecting to cicam, the target
cicam id needs to be configured here. Supported in Tuner 1.1 or higher.
+ "removeOutputPid": the unnecessary PID will be filtered out from frontend
+ output. Supported in Tuner 2.0 or higher.
"frequency": the frequency used to configure tune and scan.
"endFrequency": the end frequency of scan. Supported in Tuner 1.1 or higher.
@@ -53,11 +55,13 @@
-->
<frontends>
<frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
- connectToCicamId="0" frequency="578000000" endFrequency="800000000">
+ connectToCicamId="0" removeOutputPid="10" frequency="578000000"
+ endFrequency="800000000">
<dvbtFrontendSettings bandwidth="8" transmissionMode="128" isHighPriority="1"/>
</frontend>
<frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
- connectToCicamId="0" frequency="578000000" endFrequency="800000000">
+ connectToCicamId="0" removeOutputPid="10" frequency="578000000"
+ endFrequency="800000000">
</frontend>
</frontends>
<!-- Filter section:
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index 94f108b..59abd9a 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -94,6 +94,8 @@
"connectToCicamId": if the device supports frontend connecting to cicam, the
target cicam id needs to be configured here. Supported in Tuner 1.1 or
higher.
+ "removeOutputPid": the unnecessary PID will be filtered out from frontend
+ output. Supported in Tuner 2.0 or higher.
"frequency": the frequency used to configure tune and scan.
"endFrequency": the end frequency of scan. Supported in Tuner 1.1 or higher.
@@ -125,6 +127,7 @@
<xs:attribute name="isSoftwareFrontend" type="xs:boolean" use="required"/>
<xs:attribute name="frequency" type="xs:nonNegativeInteger" use="required"/>
<xs:attribute name="connectToCicamId" type="xs:nonNegativeInteger" use="optional"/>
+ <xs:attribute name="removeOutputPid" type="xs:nonNegativeInteger" use="optional"/>
<xs:attribute name="endFrequency" type="xs:nonNegativeInteger" use="optional"/>
</xs:complexType>
diff --git a/usb/aidl/Android.bp b/usb/aidl/Android.bp
new file mode 100644
index 0000000..d1e9e68
--- /dev/null
+++ b/usb/aidl/Android.bp
@@ -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,
+ },
+ },
+ },
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantDetectionStatus.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantDetectionStatus.aidl
index 7ef08d2..24c6966 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantDetectionStatus.aidl
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum ContaminantDetectionStatus {
+ NOT_SUPPORTED = 0,
+ DISABLED = 1,
+ NOT_DETECTED = 2,
+ DETECTED = 3,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantProtectionMode.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantProtectionMode.aidl
index 7ef08d2..9979869 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantProtectionMode.aidl
@@ -31,9 +31,11 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum ContaminantProtectionMode {
+ NONE = 0,
+ FORCE_SINK = 1,
+ FORCE_SOURCE = 2,
+ FORCE_DISABLE = 3,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantProtectionStatus.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantProtectionStatus.aidl
index 7ef08d2..9642261 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ContaminantProtectionStatus.aidl
@@ -31,9 +31,12 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum ContaminantProtectionStatus {
+ NONE = 0,
+ FORCE_SINK = 1,
+ FORCE_SOURCE = 2,
+ FORCE_DISABLE = 3,
+ DISABLED = 4,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsb.aidl
similarity index 72%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsb.aidl
index 7ef08d2..4ba9ff8 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsb.aidl
@@ -31,9 +31,14 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+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 enableUsbDataWhileDocked(in String portName, 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);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsbCallback.aidl
similarity index 62%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsbCallback.aidl
index 7ef08d2..57f02c5 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsbCallback.aidl
@@ -31,9 +31,14 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+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 notifyEnableUsbDataWhileDockedStatus(in String portName, 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);
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortDataRole.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortDataRole.aidl
index 7ef08d2..105b316 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortDataRole.aidl
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum PortDataRole {
+ NONE = 0,
+ HOST = 1,
+ DEVICE = 2,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortMode.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortMode.aidl
index 7ef08d2..34e4334 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortMode.aidl
@@ -31,9 +31,13 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum PortMode {
+ NONE = 0,
+ UFP = 1,
+ DFP = 2,
+ DRP = 3,
+ AUDIO_ACCESSORY = 4,
+ DEBUG_ACCESSORY = 5,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortPowerRole.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortPowerRole.aidl
index 7ef08d2..0e6f3fb 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortPowerRole.aidl
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum PortPowerRole {
+ NONE = 0,
+ SOURCE = 1,
+ SINK = 2,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortRole.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortRole.aidl
index 7ef08d2..c66aecc 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortRole.aidl
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+union PortRole {
+ android.hardware.usb.PortPowerRole powerRole = android.hardware.usb.PortPowerRole.NONE;
+ android.hardware.usb.PortDataRole dataRole;
+ android.hardware.usb.PortMode mode;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortStatus.aidl
similarity index 60%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortStatus.aidl
index 7ef08d2..dfd99fb 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortStatus.aidl
@@ -31,9 +31,23 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+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;
+ android.hardware.usb.UsbDataStatus[] usbDataStatus;
+ boolean powerTransferLimited;
+ android.hardware.usb.PowerBrickStatus powerBrickStatus;
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PowerBrickStatus.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PowerBrickStatus.aidl
index 7ef08d2..01d2fdd 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PowerBrickStatus.aidl
@@ -31,9 +31,10 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum PowerBrickStatus {
+ UNKNOWN = 0,
+ CONNECTED = 1,
+ NOT_CONNECTED = 2,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/Status.aidl
similarity index 85%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/Status.aidl
index 7ef08d2..f28fc2a 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/Status.aidl
@@ -31,9 +31,12 @@
// 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.gnss.visibility_control;
-@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+package android.hardware.usb;
+@Backing(type="int") @VintfStability
+enum Status {
+ SUCCESS = 0,
+ ERROR = 1,
+ INVALID_ARGUMENT = 2,
+ UNRECOGNIZED_ROLE = 3,
+ NOT_SUPPORTED = 4,
}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/UsbDataStatus.aidl
similarity index 86%
copy from gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
copy to usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/UsbDataStatus.aidl
index 7ef08d2..e2c0cfb 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss.visibility_control/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/UsbDataStatus.aidl
@@ -31,9 +31,14 @@
// 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.gnss.visibility_control;
+package android.hardware.usb;
@VintfStability
-interface IGnssVisibilityControl {
- void enableNfwLocationAccess(in String[] proxyApps);
- void setCallback(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback callback);
+enum UsbDataStatus {
+ UNKNOWN = 0,
+ ENABLED = 1,
+ DISABLED_OVERHEAT = 2,
+ DISABLED_CONTAMINANT = 3,
+ DISABLED_DOCK = 4,
+ DISABLED_FORCE = 5,
+ DISABLED_DEBUG = 6,
}
diff --git a/usb/aidl/android/hardware/usb/ContaminantDetectionStatus.aidl b/usb/aidl/android/hardware/usb/ContaminantDetectionStatus.aidl
new file mode 100644
index 0000000..d9bc576
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/ContaminantDetectionStatus.aidl
@@ -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,
+}
diff --git a/usb/aidl/android/hardware/usb/ContaminantProtectionMode.aidl b/usb/aidl/android/hardware/usb/ContaminantProtectionMode.aidl
new file mode 100644
index 0000000..47c073d
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/ContaminantProtectionMode.aidl
@@ -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,
+}
diff --git a/usb/aidl/android/hardware/usb/ContaminantProtectionStatus.aidl b/usb/aidl/android/hardware/usb/ContaminantProtectionStatus.aidl
new file mode 100644
index 0000000..c4fa979
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/ContaminantProtectionStatus.aidl
@@ -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,
+}
diff --git a/usb/aidl/android/hardware/usb/IUsb.aidl b/usb/aidl/android/hardware/usb/IUsb.aidl
new file mode 100644
index 0000000..d296fbb
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/IUsb.aidl
@@ -0,0 +1,107 @@
+/*
+ * 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 function is used to enable USB controller if and when the controller
+ * disabled due to docking event.
+ *
+ * @param portName Name of the port.
+ * @param transactionId ID to be used when invoking the callback.
+ */
+ void enableUsbDataWhileDocked(in String portName, 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);
+}
diff --git a/usb/aidl/android/hardware/usb/IUsbCallback.aidl b/usb/aidl/android/hardware/usb/IUsbCallback.aidl
new file mode 100644
index 0000000..e33672a
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/IUsbCallback.aidl
@@ -0,0 +1,108 @@
+/*
+ * 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 enableUsbDataWhileDocked call to the caller.
+ *
+ * @param portName name of the port for which the enableUsbDataWhileDocked is requested.
+ * @param retval SUCCESS if current request succeeded. FAILURE otherwise.
+ * @param transactionId transactionId sent during enableUsbDataWhileDocked request.
+ */
+ void notifyEnableUsbDataWhileDockedStatus(in String portName, 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);
+}
diff --git a/usb/aidl/android/hardware/usb/PortDataRole.aidl b/usb/aidl/android/hardware/usb/PortDataRole.aidl
new file mode 100644
index 0000000..a69f977
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/PortDataRole.aidl
@@ -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,
+}
diff --git a/usb/aidl/android/hardware/usb/PortMode.aidl b/usb/aidl/android/hardware/usb/PortMode.aidl
new file mode 100644
index 0000000..399f0eb
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/PortMode.aidl
@@ -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,
+}
diff --git a/usb/aidl/android/hardware/usb/PortPowerRole.aidl b/usb/aidl/android/hardware/usb/PortPowerRole.aidl
new file mode 100644
index 0000000..ae3dc47
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/PortPowerRole.aidl
@@ -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,
+}
diff --git a/usb/aidl/android/hardware/usb/PortRole.aidl b/usb/aidl/android/hardware/usb/PortRole.aidl
new file mode 100644
index 0000000..e0429c8
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/PortRole.aidl
@@ -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;
+}
diff --git a/usb/aidl/android/hardware/usb/PortStatus.aidl b/usb/aidl/android/hardware/usb/PortStatus.aidl
new file mode 100644
index 0000000..51bee71
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/PortStatus.aidl
@@ -0,0 +1,118 @@
+/*
+ * 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;
+import android.hardware.usb.PowerBrickStatus;
+import android.hardware.usb.UsbDataStatus;
+
+@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.
+ * Lists reasons for USB data being disabled.
+ */
+ UsbDataStatus[] usbDataStatus;
+ /**
+ * Denoted whether power transfer is limited in the port.
+ */
+ boolean powerTransferLimited;
+ /**
+ * Denotes whether Power brick is connected.
+ */
+ PowerBrickStatus powerBrickStatus;
+}
diff --git a/usb/aidl/android/hardware/usb/PowerBrickStatus.aidl b/usb/aidl/android/hardware/usb/PowerBrickStatus.aidl
new file mode 100644
index 0000000..620fb25
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/PowerBrickStatus.aidl
@@ -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.
+ */
+
+package android.hardware.usb;
+
+@VintfStability
+enum PowerBrickStatus {
+ /**
+ * Status not known.
+ */
+ UNKNOWN = 0,
+ /**
+ * Port partner is power brick.
+ */
+ CONNECTED = 1,
+ /**
+ * Port partner is not power brick.
+ */
+ NOT_CONNECTED = 2,
+}
diff --git a/usb/aidl/android/hardware/usb/Status.aidl b/usb/aidl/android/hardware/usb/Status.aidl
new file mode 100644
index 0000000..468ba4a
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/Status.aidl
@@ -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,
+}
diff --git a/usb/aidl/android/hardware/usb/UsbDataStatus.aidl b/usb/aidl/android/hardware/usb/UsbDataStatus.aidl
new file mode 100644
index 0000000..4b6a41a
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/UsbDataStatus.aidl
@@ -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;
+
+@VintfStability
+enum UsbDataStatus {
+ /**
+ * USB data status not known.
+ */
+ UNKNOWN = 0,
+ /**
+ * USB data is enabled.
+ */
+ ENABLED = 1,
+ /**
+ * USB data is disabled as the port is hot.
+ */
+ DISABLED_OVERHEAT = 2,
+ /**
+ * USB data is disabled as port is contaminated.
+ */
+ DISABLED_CONTAMINANT = 3,
+ /**
+ * USB data is disabled due to dock.
+ */
+ DISABLED_DOCK = 4,
+ /**
+ * USB data is disabled by USB Service.
+ */
+ DISABLED_FORCE = 5,
+ /**
+ * USB data disabled for debug.
+ */
+ DISABLED_DEBUG = 6
+}
diff --git a/usb/aidl/conversion.log b/usb/aidl/conversion.log
new file mode 100644
index 0000000..c090446
--- /dev/null
+++ b/usb/aidl/conversion.log
@@ -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
diff --git a/usb/aidl/default/Android.bp b/usb/aidl/default/Android.bp
new file mode 100644
index 0000000..da0cff2
--- /dev/null
+++ b/usb/aidl/default/Android.bp
@@ -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",
+ ],
+}
diff --git a/usb/aidl/default/Usb.cpp b/usb/aidl/default/Usb.cpp
new file mode 100644
index 0000000..92b09a2
--- /dev/null
+++ b/usb/aidl/default/Usb.cpp
@@ -0,0 +1,727 @@
+/*
+ * 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, ¤tPortStatus);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::enableUsbDataWhileDocked(const string& in_portName, int64_t in_transactionId) {
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyEnableUsbDataWhileDockedStatus(
+ in_portName, Status::NOT_SUPPORTED, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyEnableUsbDataWhileDockedStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+
+ 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, ¤tRole) == 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, ¤tRole) == 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, ¤tRole) == 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].usbDataStatus.push_back(UsbDataStatus::ENABLED);
+
+ 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, ¤tPortStatus);
+ 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, ¤tPortStatus);
+ 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, ¤tPortStatus);
+
+ // 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
diff --git a/usb/aidl/default/Usb.h b/usb/aidl/default/Usb.h
new file mode 100644
index 0000000..7e8422e
--- /dev/null
+++ b/usb/aidl/default/Usb.h
@@ -0,0 +1,80 @@
+/*
+ * 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 enableUsbDataWhileDocked(const string& in_portName,
+ 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
diff --git a/usb/aidl/default/android.hardware.usb-service.example.rc b/usb/aidl/default/android.hardware.usb-service.example.rc
new file mode 100644
index 0000000..335bca7
--- /dev/null
+++ b/usb/aidl/default/android.hardware.usb-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.usb_default /vendor/bin/hw/android.hardware.usb-service.example
+ class hal
+ user system
+ group system
diff --git a/usb/aidl/default/android.hardware.usb-service.example.xml b/usb/aidl/default/android.hardware.usb-service.example.xml
new file mode 100644
index 0000000..6088194
--- /dev/null
+++ b/usb/aidl/default/android.hardware.usb-service.example.xml
@@ -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>
diff --git a/usb/aidl/default/service.cpp b/usb/aidl/default/service.cpp
new file mode 100644
index 0000000..398458a
--- /dev/null
+++ b/usb/aidl/default/service.cpp
@@ -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
+}
diff --git a/usb/aidl/vts/Android.bp b/usb/aidl/vts/Android.bp
new file mode 100644
index 0000000..00a7c93
--- /dev/null
+++ b/usb/aidl/vts/Android.bp
@@ -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",
+ ],
+}
diff --git a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
new file mode 100644
index 0000000..ed3bd6e
--- /dev/null
+++ b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
@@ -0,0 +1,523 @@
+/*
+ * 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 enableUsbData operation
+ ScopedAStatus notifyEnableUsbDataWhileDockedStatus(const string& /*portName*/,
+ Status /*retval*/,
+ int64_t transactionId) override {
+ parent_.last_transactionId = transactionId;
+ parent_.usb_last_cookie = cookie;
+ parent_.enable_usb_data_while_docked_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 notifyEnableUsbDataWhileDockedStatus callback.
+ bool enable_usb_data_while_docked_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 while being docked.
+ * Test case queries the usb ports present in device.
+ * If there is at least one usb port, enabling Usb data while docked
+ * is attempted for the port.
+ * The callback parameters are checked to see if transaction id
+ * matches.
+ */
+TEST_P(UsbAidlTest, enableUsbDataWhileDocked) {
+ ALOGI("UsbAidlTest enableUsbDataWhileDocked 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_while_docked_done = false;
+ transactionId = rand() % 10000;
+ const auto& ret = usb->enableUsbDataWhileDocked(usb_last_port_status.portName, transactionId);
+ ASSERT_TRUE(ret.isOk());
+
+ std::cv_status waitStatus = wait();
+ while (waitStatus == std::cv_status::no_timeout &&
+ enable_usb_data_while_docked_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 enableUsbDataWhileDocked 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();
+}
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 99fd094..2cc1e6a 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -16,7 +16,7 @@
stability: "vintf",
backend: {
java: {
- sdk_version: "module_current",
+ sdk_version: "module_Tiramisu",
enabled: false,
},
ndk: {
@@ -27,7 +27,7 @@
"//apex_available:platform",
"com.android.uwb",
],
- min_sdk_version: "current",
+ min_sdk_version: "Tiramisu",
},
rust: {
enabled: true,
@@ -35,7 +35,7 @@
"//apex_available:platform",
"com.android.uwb",
],
- min_sdk_version: "current",
+ min_sdk_version: "Tiramisu",
},
},
}
@@ -47,7 +47,7 @@
stability: "vintf",
backend: {
java: {
- sdk_version: "module_current",
+ sdk_version: "module_Tiramisu",
enabled: true,
apex_available: [
"com.android.uwb",
@@ -58,7 +58,7 @@
"//apex_available:platform",
"com.android.uwb",
],
- min_sdk_version: "current",
+ min_sdk_version: "Tiramisu",
},
},
}
diff --git a/wifi/1.6/Android.bp b/wifi/1.6/Android.bp
index d293c73..14cb2e0 100644
--- a/wifi/1.6/Android.bp
+++ b/wifi/1.6/Android.bp
@@ -14,6 +14,13 @@
root: "android.hardware",
srcs: [
"IWifi.hal",
+ "IWifiChip.hal",
+ "IWifiNanIface.hal",
+ "IWifiNanIfaceEventCallback.hal",
+ "IWifiRttController.hal",
+ "IWifiRttControllerEventCallback.hal",
+ "IWifiStaIface.hal",
+ "types.hal",
],
interfaces: [
"android.hardware.wifi@1.0",
diff --git a/wifi/1.6/IWifiChip.hal b/wifi/1.6/IWifiChip.hal
new file mode 100644
index 0000000..301bd82
--- /dev/null
+++ b/wifi/1.6/IWifiChip.hal
@@ -0,0 +1,90 @@
+/*
+ * Copyright 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.wifi@1.6;
+
+import @1.0::IWifiIface;
+import @1.0::WifiStatus;
+import @1.5::WifiBand;
+import @1.5::IWifiChip;
+import @1.5::WifiIfaceMode;
+import IWifiRttController;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+interface IWifiChip extends @1.5::IWifiChip {
+
+ /**
+ * Create a RTTController instance.
+ *
+ * RTT controller can be either:
+ * a) Bound to a specific iface by passing in the corresponding |IWifiIface|
+ * object in |iface| param, OR
+ * b) Let the implementation decide the iface to use for RTT operations by
+ * passing null in |iface| param.
+ *
+ * @param boundIface HIDL interface object representing the iface if
+ * the responder must be bound to a specific iface, null otherwise.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ createRttController_1_6(IWifiIface boundIface)
+ generates (WifiStatus status, IWifiRttController rtt);
+
+ /**
+ * Retrieve list of usable Wifi channels for the specified band &
+ * operational modes.
+ *
+ * The list of usable Wifi channels in a given band depends on factors
+ * like current country code, operational mode (e.g. STA, SAP, WFD-CLI,
+ * WFD-GO, TDLS, NAN) and other restrictons due to DFS, cellular coexistence
+ * and conncurency state of the device.
+ *
+ * @param band |WifiBand| for which list of usable channels is requested.
+ * @param ifaceModeMask Bitmask of the modes represented by |WifiIfaceMode|
+ * Bitmask respresents all the modes that the caller is interested
+ * in (e.g. STA, SAP, CLI, GO, TDLS, NAN). E.g. If the caller is
+ * interested in knowing usable channels for P2P CLI, P2P GO & NAN,
+ * ifaceModeMask would be set to
+ * IFACE_MODE_P2P_CLIENT|IFACE_MODE_P2P_GO|IFACE_MODE_NAN.
+ * @param filterMask Bitmask of filters represented by
+ * |UsableChannelFilter|. Specifies whether driver should filter
+ * channels based on additional criteria. If no filter is specified
+ * driver should return usable channels purely based on regulatory
+ * constraints.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ * @return channels List of channels represented by |WifiUsableChannel|
+ * Each entry represents a channel frequency, bandwidth and
+ * bitmask of modes (e.g. STA, SAP, CLI, GO, TDLS, NAN) that are
+ * allowed on that channel. E.g. If only STA mode can be supported
+ * on an indoor channel, only the IFACE_MODE_STA bit would be set
+ * for that channel. If 5GHz SAP cannot be supported, then none of
+ * the 5GHz channels will have IFACE_MODE_SOFTAP bit set.
+ * Note: Bits do not represent concurrency state. Each bit only
+ * represents whether particular mode is allowed on that channel.
+ */
+ getUsableChannels_1_6(WifiBand band, bitfield<WifiIfaceMode> ifaceModeMask,
+ bitfield<UsableChannelFilter> filterMask)
+ generates (WifiStatus status, vec<WifiUsableChannel> channels);
+};
diff --git a/wifi/1.6/IWifiNanIface.hal b/wifi/1.6/IWifiNanIface.hal
new file mode 100644
index 0000000..b92a880
--- /dev/null
+++ b/wifi/1.6/IWifiNanIface.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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.wifi@1.6;
+
+import @1.0::WifiStatus;
+import @1.5::IWifiNanIface;
+import IWifiNanIfaceEventCallback;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.5::IWifiNanIface {
+ /**
+ * Requests notifications of significant events on this iface. Multiple calls
+ * to this must register multiple callbacks each of which must receive all
+ * events.
+ *
+ * @param callback An instance of the |IWifiNanIfaceEventCallback| HIDL interface
+ * object.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ registerEventCallback_1_6(IWifiNanIfaceEventCallback callback) generates (WifiStatus status);
+};
diff --git a/wifi/1.6/IWifiNanIfaceEventCallback.hal b/wifi/1.6/IWifiNanIfaceEventCallback.hal
new file mode 100644
index 0000000..05b8ddf
--- /dev/null
+++ b/wifi/1.6/IWifiNanIfaceEventCallback.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright 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.wifi@1.6;
+
+import @1.0::CommandIdShort;
+import @1.0::WifiNanStatus;
+import @1.5::IWifiNanIfaceEventCallback;
+
+/**
+ * NAN Response and Asynchronous Event Callbacks.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIfaceEventCallback extends @1.5::IWifiNanIfaceEventCallback {
+ /**
+ * Asynchronous callback indicating a data-path (NDP) setup has been completed: received by
+ * both Initiator and Responder.
+ *
+ * Note: supersedes the @1.0::IWifiNanIfaceEventCallback.eventDataPathConfirm() method which is
+ * deprecated as of HAL version 1.2.
+ *
+ * @param event: NanDataPathConfirmInd containing event details.
+ */
+ oneway eventDataPathConfirm_1_6(NanDataPathConfirmInd event);
+
+ /**
+ * Asynchronous callback indicating a data-path (NDP) schedule has been updated (e.g. channels
+ * have been changed).
+ *
+ * @param event: NanDataPathScheduleUpdateInd containing event details.
+ */
+ oneway eventDataPathScheduleUpdate_1_6(NanDataPathScheduleUpdateInd event);
+};
diff --git a/wifi/1.6/IWifiRttController.hal b/wifi/1.6/IWifiRttController.hal
new file mode 100644
index 0000000..0db1d2c
--- /dev/null
+++ b/wifi/1.6/IWifiRttController.hal
@@ -0,0 +1,100 @@
+/*
+ * Copyright 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.wifi@1.6;
+
+import @1.0::CommandId;
+import @1.0::WifiStatus;
+import @1.4::IWifiRttController;
+import IWifiRttControllerEventCallback;
+/**
+ * Interface used to perform RTT(Round trip time) operations.
+ */
+interface IWifiRttController extends @1.4::IWifiRttController {
+ /**
+ * Requests notifications of significant events on this rtt controller.
+ * Multiple calls to this must register multiple callbacks each of which must
+ * receive all events.
+ *
+ * @param callback An instance of the |IWifiRttControllerEventCallback| HIDL
+ * interface object.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ registerEventCallback_1_6(IWifiRttControllerEventCallback callback)
+ generates (WifiStatus status);
+
+ /**
+ * API to request RTT measurement.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param rttConfigs Vector of |RttConfig| parameters.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ rangeRequest_1_6(CommandId cmdId, vec<RttConfig> rttConfigs) generates (WifiStatus status);
+
+ /**
+ * Get RTT responder information e.g. WiFi channel to enable responder on.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return info Instance of |RttResponderInfo|.
+ */
+ getResponderInfo_1_6() generates (WifiStatus status, RttResponder info);
+
+ /**
+ * Enable RTT responder mode.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @parm channelHint Hint of the channel information where RTT responder must
+ * be enabled on.
+ * @param maxDurationInSeconds Timeout of responder mode.
+ * @param info Instance of |RttResponderInfo|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ enableResponder_1_6(CommandId cmdId, WifiChannelInfo channelHint,
+ uint32_t maxDurationInSeconds, RttResponder info) generates (WifiStatus status);
+
+ /**
+ * RTT capabilities of the device.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return capabilities Instance of |RttCapabilities|.
+ */
+ getCapabilities_1_6() generates (WifiStatus status, RttCapabilities capabilities);
+};
diff --git a/wifi/1.6/IWifiRttControllerEventCallback.hal b/wifi/1.6/IWifiRttControllerEventCallback.hal
new file mode 100644
index 0000000..0857b66
--- /dev/null
+++ b/wifi/1.6/IWifiRttControllerEventCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.wifi@1.6;
+
+import @1.4::IWifiRttControllerEventCallback;
+import @1.0::CommandId;
+
+/**
+ * RTT Response and Event Callbacks.
+ */
+interface IWifiRttControllerEventCallback extends @1.4::IWifiRttControllerEventCallback {
+ /*
+ * Invoked when an RTT result is available.
+ *
+ * @param cmdId command Id corresponding to the original request.
+ * @param results Vector of |RttResult| instances.
+ */
+ oneway onResults_1_6(CommandId cmdId, vec<RttResult> results);
+};
diff --git a/wifi/1.6/IWifiStaIface.hal b/wifi/1.6/IWifiStaIface.hal
new file mode 100644
index 0000000..c26e1a0
--- /dev/null
+++ b/wifi/1.6/IWifiStaIface.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.wifi@1.6;
+
+import @1.0::WifiStatus;
+import @1.5::IWifiStaIface;
+
+/**
+ * Interface used to represent a single STA iface.
+ *
+ * IWifiChip.createStaIface() must return a @1.6::IWifiStaIface when supported.
+ */
+interface IWifiStaIface extends @1.5::IWifiStaIface {
+ /**
+ * Retrieve the latest link layer stats.
+ * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set or if
+ * link layer stats collection hasn't been explicitly enabled.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return stats Instance of |LinkLayerStats|.
+ */
+ getLinkLayerStats_1_6() generates (WifiStatus status, StaLinkLayerStats stats);
+};
diff --git a/wifi/1.6/default/Android.bp b/wifi/1.6/default/Android.bp
index 6333b6e..d48d183 100644
--- a/wifi/1.6/default/Android.bp
+++ b/wifi/1.6/default/Android.bp
@@ -33,6 +33,7 @@
"android.hardware.wifi@1.3",
"android.hardware.wifi@1.4",
"android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
"libbase",
"libcutils",
"libhidlbase",
@@ -84,6 +85,7 @@
"android.hardware.wifi@1.3",
"android.hardware.wifi@1.4",
"android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
"libbase",
"libcutils",
"libhidlbase",
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
index bc6bb6a..ee8c818 100644
--- a/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
+++ b/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
@@ -5,6 +5,7 @@
interface android.hardware.wifi@1.3::IWifi default
interface android.hardware.wifi@1.4::IWifi default
interface android.hardware.wifi@1.5::IWifi default
+ interface android.hardware.wifi@1.6::IWifi default
oneshot
disabled
class hal
diff --git a/wifi/1.6/default/hidl_struct_util.cpp b/wifi/1.6/default/hidl_struct_util.cpp
index 3489c9e..2a6b131 100644
--- a/wifi/1.6/default/hidl_struct_util.cpp
+++ b/wifi/1.6/default/hidl_struct_util.cpp
@@ -438,7 +438,7 @@
bool convertLegacyWifiUsableChannelToHidl(
const legacy_hal::wifi_usable_channel& legacy_usable_channel,
- V1_5::WifiUsableChannel* hidl_usable_channel) {
+ V1_6::WifiUsableChannel* hidl_usable_channel) {
if (!hidl_usable_channel) {
return false;
}
@@ -454,13 +454,13 @@
bool convertLegacyWifiUsableChannelsToHidl(
const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
- std::vector<V1_5::WifiUsableChannel>* hidl_usable_channels) {
+ std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels) {
if (!hidl_usable_channels) {
return false;
}
*hidl_usable_channels = {};
for (const auto& legacy_usable_channel : legacy_usable_channels) {
- V1_5::WifiUsableChannel hidl_usable_channel;
+ V1_6::WifiUsableChannel hidl_usable_channel;
if (!convertLegacyWifiUsableChannelToHidl(legacy_usable_channel, &hidl_usable_channel)) {
return false;
}
@@ -894,28 +894,28 @@
bool convertLegacyLinkLayerRadioStatsToHidl(
const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
- V1_5::StaLinkLayerRadioStats* hidl_radio_stat) {
+ V1_6::StaLinkLayerRadioStats* hidl_radio_stat) {
if (!hidl_radio_stat) {
return false;
}
*hidl_radio_stat = {};
hidl_radio_stat->radioId = legacy_radio_stat.stats.radio;
- hidl_radio_stat->V1_3.V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
- hidl_radio_stat->V1_3.V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
- hidl_radio_stat->V1_3.V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
- hidl_radio_stat->V1_3.V1_0.onTimeInMsForScan = legacy_radio_stat.stats.on_time_scan;
- hidl_radio_stat->V1_3.V1_0.txTimeInMsPerLevel = legacy_radio_stat.tx_time_per_levels;
- hidl_radio_stat->V1_3.onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
- hidl_radio_stat->V1_3.onTimeInMsForBgScan = legacy_radio_stat.stats.on_time_gscan;
- hidl_radio_stat->V1_3.onTimeInMsForRoamScan = legacy_radio_stat.stats.on_time_roam_scan;
- hidl_radio_stat->V1_3.onTimeInMsForPnoScan = legacy_radio_stat.stats.on_time_pno_scan;
- hidl_radio_stat->V1_3.onTimeInMsForHs20Scan = legacy_radio_stat.stats.on_time_hs20;
+ hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
+ hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
+ hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
+ hidl_radio_stat->V1_0.onTimeInMsForScan = legacy_radio_stat.stats.on_time_scan;
+ hidl_radio_stat->V1_0.txTimeInMsPerLevel = legacy_radio_stat.tx_time_per_levels;
+ hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
+ hidl_radio_stat->onTimeInMsForBgScan = legacy_radio_stat.stats.on_time_gscan;
+ hidl_radio_stat->onTimeInMsForRoamScan = legacy_radio_stat.stats.on_time_roam_scan;
+ hidl_radio_stat->onTimeInMsForPnoScan = legacy_radio_stat.stats.on_time_pno_scan;
+ hidl_radio_stat->onTimeInMsForHs20Scan = legacy_radio_stat.stats.on_time_hs20;
- std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
+ std::vector<V1_6::WifiChannelStats> hidl_channel_stats;
for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
- V1_3::WifiChannelStats hidl_channel_stat;
+ V1_6::WifiChannelStats hidl_channel_stat;
hidl_channel_stat.onTimeInMs = channel_stat.on_time;
hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
/*
@@ -929,13 +929,13 @@
hidl_channel_stats.push_back(hidl_channel_stat);
}
- hidl_radio_stat->V1_3.channelStats = hidl_channel_stats;
+ hidl_radio_stat->channelStats = hidl_channel_stats;
return true;
}
bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
- V1_5::StaLinkLayerStats* hidl_stats) {
+ V1_6::StaLinkLayerStats* hidl_stats) {
if (!hidl_stats) {
return false;
}
@@ -1010,9 +1010,9 @@
hidl_stats->iface.timeSliceDutyCycleInPercent =
legacy_stats.iface.info.time_slicing_duty_cycle_percent;
// peer info legacy_stats conversion.
- std::vector<V1_5::StaPeerInfo> hidl_peers_info_stats;
+ std::vector<V1_6::StaPeerInfo> hidl_peers_info_stats;
for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
- V1_5::StaPeerInfo hidl_peer_info_stats;
+ V1_6::StaPeerInfo hidl_peer_info_stats;
if (!convertLegacyPeerInfoStatsToHidl(legacy_peer_info_stats, &hidl_peer_info_stats)) {
return false;
}
@@ -1020,9 +1020,9 @@
}
hidl_stats->iface.peers = hidl_peers_info_stats;
// radio legacy_stats conversion.
- std::vector<V1_5::StaLinkLayerRadioStats> hidl_radios_stats;
+ std::vector<V1_6::StaLinkLayerRadioStats> hidl_radios_stats;
for (const auto& legacy_radio_stats : legacy_stats.radios) {
- V1_5::StaLinkLayerRadioStats hidl_radio_stats;
+ V1_6::StaLinkLayerRadioStats hidl_radio_stats;
if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats, &hidl_radio_stats)) {
return false;
}
@@ -1036,7 +1036,7 @@
}
bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
- V1_5::StaPeerInfo* hidl_peer_info_stats) {
+ V1_6::StaPeerInfo* hidl_peer_info_stats) {
if (!hidl_peer_info_stats) {
return false;
}
@@ -1044,9 +1044,9 @@
hidl_peer_info_stats->staCount = legacy_peer_info_stats.peer_info.bssload.sta_count;
hidl_peer_info_stats->chanUtil = legacy_peer_info_stats.peer_info.bssload.chan_util;
- std::vector<V1_5::StaRateStat> hidlRateStats;
+ std::vector<V1_6::StaRateStat> hidlRateStats;
for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
- V1_5::StaRateStat rateStat;
+ V1_6::StaRateStat rateStat;
if (!convertLegacyWifiRateInfoToHidl(legacy_rate_stats.rate, &rateStat.rateInfo)) {
return false;
}
@@ -2134,7 +2134,7 @@
}
bool convertLegacyNdpChannelInfoToHidl(const legacy_hal::NanChannelInfo& legacy_struct,
- V1_2::NanDataPathChannelInfo* hidl_struct) {
+ V1_6::NanDataPathChannelInfo* hidl_struct) {
if (!hidl_struct) {
LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
return false;
@@ -2150,7 +2150,7 @@
}
bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
- V1_2::NanDataPathConfirmInd* hidl_ind) {
+ V1_6::NanDataPathConfirmInd* hidl_ind) {
if (!hidl_ind) {
LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
return false;
@@ -2166,9 +2166,9 @@
hidl_ind->V1_0.status.status = convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
hidl_ind->V1_0.status.description = ""; // TODO: b/34059183
- std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
+ std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
- V1_2::NanDataPathChannelInfo hidl_struct;
+ V1_6::NanDataPathChannelInfo hidl_struct;
if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
return false;
}
@@ -2181,7 +2181,7 @@
bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
- V1_2::NanDataPathScheduleUpdateInd* hidl_ind) {
+ V1_6::NanDataPathScheduleUpdateInd* hidl_ind) {
if (!hidl_ind) {
LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
"hidl_ind is null";
@@ -2190,9 +2190,9 @@
*hidl_ind = {};
hidl_ind->peerDiscoveryAddress = hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
- std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
+ std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
- V1_2::NanDataPathChannelInfo hidl_struct;
+ V1_6::NanDataPathChannelInfo hidl_struct;
if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
return false;
}
@@ -2260,13 +2260,16 @@
return legacy_hal::WIFI_CHAN_WIDTH_5;
case WifiChannelWidthInMhz::WIDTH_10:
return legacy_hal::WIFI_CHAN_WIDTH_10;
+ case V1_6::WifiChannelWidthInMhz::WIDTH_320:
+ return legacy_hal::WIFI_CHAN_WIDTH_320;
case WifiChannelWidthInMhz::WIDTH_INVALID:
return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
};
CHECK(false);
}
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(legacy_hal::wifi_channel_width type) {
+V1_6::WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+ legacy_hal::wifi_channel_width type) {
switch (type) {
case legacy_hal::WIFI_CHAN_WIDTH_20:
return WifiChannelWidthInMhz::WIDTH_20;
@@ -2282,35 +2285,41 @@
return WifiChannelWidthInMhz::WIDTH_5;
case legacy_hal::WIFI_CHAN_WIDTH_10:
return WifiChannelWidthInMhz::WIDTH_10;
+ case legacy_hal::WIFI_CHAN_WIDTH_320:
+ return V1_6::WifiChannelWidthInMhz::WIDTH_320;
default:
return WifiChannelWidthInMhz::WIDTH_INVALID;
};
}
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(V1_4::RttPreamble type) {
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(V1_6::RttPreamble type) {
switch (type) {
- case V1_4::RttPreamble::LEGACY:
+ case V1_6::RttPreamble::LEGACY:
return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
- case V1_4::RttPreamble::HT:
+ case V1_6::RttPreamble::HT:
return legacy_hal::WIFI_RTT_PREAMBLE_HT;
- case V1_4::RttPreamble::VHT:
+ case V1_6::RttPreamble::VHT:
return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
- case V1_4::RttPreamble::HE:
+ case V1_6::RttPreamble::HE:
return legacy_hal::WIFI_RTT_PREAMBLE_HE;
+ case V1_6::RttPreamble::EHT:
+ return legacy_hal::WIFI_RTT_PREAMBLE_EHT;
};
CHECK(false);
}
-V1_4::RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+V1_6::RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
switch (type) {
case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
- return V1_4::RttPreamble::LEGACY;
+ return V1_6::RttPreamble::LEGACY;
case legacy_hal::WIFI_RTT_PREAMBLE_HT:
- return V1_4::RttPreamble::HT;
+ return V1_6::RttPreamble::HT;
case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
- return V1_4::RttPreamble::VHT;
+ return V1_6::RttPreamble::VHT;
case legacy_hal::WIFI_RTT_PREAMBLE_HE:
- return V1_4::RttPreamble::HE;
+ return V1_6::RttPreamble::HE;
+ case legacy_hal::WIFI_RTT_PREAMBLE_EHT:
+ return V1_6::RttPreamble::EHT;
};
CHECK(false) << "Unknown legacy type: " << type;
}
@@ -2329,6 +2338,8 @@
return legacy_hal::WIFI_RTT_BW_80;
case RttBw::BW_160MHZ:
return legacy_hal::WIFI_RTT_BW_160;
+ case RttBw::BW_320MHZ:
+ return legacy_hal::WIFI_RTT_BW_320;
};
CHECK(false);
}
@@ -2347,6 +2358,8 @@
return RttBw::BW_80MHZ;
case legacy_hal::WIFI_RTT_BW_160:
return RttBw::BW_160MHZ;
+ case legacy_hal::WIFI_RTT_BW_320:
+ return RttBw::BW_320MHZ;
};
CHECK(false) << "Unknown legacy type: " << type;
}
@@ -2363,20 +2376,22 @@
CHECK(false);
}
-V1_4::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+V1_6::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
switch (preamble) {
case 0:
- return V1_4::WifiRatePreamble::OFDM;
+ return V1_6::WifiRatePreamble::OFDM;
case 1:
- return V1_4::WifiRatePreamble::CCK;
+ return V1_6::WifiRatePreamble::CCK;
case 2:
- return V1_4::WifiRatePreamble::HT;
+ return V1_6::WifiRatePreamble::HT;
case 3:
- return V1_4::WifiRatePreamble::VHT;
+ return V1_6::WifiRatePreamble::VHT;
case 4:
- return V1_4::WifiRatePreamble::HE;
+ return V1_6::WifiRatePreamble::HE;
+ case 5:
+ return V1_6::WifiRatePreamble::EHT;
default:
- return V1_4::WifiRatePreamble::RESERVED;
+ return V1_6::WifiRatePreamble::RESERVED;
};
CHECK(false) << "Unknown legacy preamble: " << preamble;
}
@@ -2464,7 +2479,7 @@
return true;
}
-bool convertHidlRttConfigToLegacy(const V1_4::RttConfig& hidl_config,
+bool convertHidlRttConfigToLegacy(const V1_6::RttConfig& hidl_config,
legacy_hal::wifi_rtt_config* legacy_config) {
if (!legacy_config) {
return false;
@@ -2491,7 +2506,7 @@
}
bool convertHidlVectorOfRttConfigToLegacy(
- const std::vector<V1_4::RttConfig>& hidl_configs,
+ const std::vector<V1_6::RttConfig>& hidl_configs,
std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
if (!legacy_configs) {
return false;
@@ -2542,7 +2557,7 @@
return true;
}
-bool convertHidlRttResponderToLegacy(const V1_4::RttResponder& hidl_responder,
+bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
legacy_hal::wifi_rtt_responder* legacy_responder) {
if (!legacy_responder) {
return false;
@@ -2556,7 +2571,7 @@
}
bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
- V1_4::RttResponder* hidl_responder) {
+ V1_6::RttResponder* hidl_responder) {
if (!hidl_responder) {
return false;
}
@@ -2570,7 +2585,7 @@
bool convertLegacyRttCapabilitiesToHidl(
const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
- V1_4::RttCapabilities* hidl_capabilities) {
+ V1_6::RttCapabilities* hidl_capabilities) {
if (!hidl_capabilities) {
return false;
}
@@ -2582,17 +2597,19 @@
hidl_capabilities->responderSupported = legacy_capabilities.responder_supported;
hidl_capabilities->preambleSupport = 0;
for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, legacy_hal::WIFI_RTT_PREAMBLE_HT,
- legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE}) {
+ legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE,
+ legacy_hal::WIFI_RTT_PREAMBLE_EHT}) {
if (legacy_capabilities.preamble_support & flag) {
hidl_capabilities->preambleSupport |=
- static_cast<std::underlying_type<V1_4::RttPreamble>::type>(
+ static_cast<std::underlying_type<V1_6::RttPreamble>::type>(
convertLegacyRttPreambleToHidl(flag));
}
}
hidl_capabilities->bwSupport = 0;
for (const auto flag :
{legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10, legacy_hal::WIFI_RTT_BW_20,
- legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160}) {
+ legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160,
+ legacy_hal::WIFI_RTT_BW_320}) {
if (legacy_capabilities.bw_support & flag) {
hidl_capabilities->bwSupport |=
static_cast<std::underlying_type<RttBw>::type>(convertLegacyRttBwToHidl(flag));
@@ -2603,7 +2620,7 @@
}
bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
- V1_4::WifiRateInfo* hidl_rate) {
+ V1_6::WifiRateInfo* hidl_rate) {
if (!hidl_rate) {
return false;
}
@@ -2618,7 +2635,7 @@
}
bool convertLegacyRttResultToHidl(const legacy_hal::wifi_rtt_result& legacy_result,
- V1_4::RttResult* hidl_result) {
+ V1_6::RttResult* hidl_result) {
if (!hidl_result) {
return false;
}
@@ -2660,13 +2677,13 @@
bool convertLegacyVectorOfRttResultToHidl(
const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
- std::vector<V1_4::RttResult>* hidl_results) {
+ std::vector<V1_6::RttResult>* hidl_results) {
if (!hidl_results) {
return false;
}
*hidl_results = {};
for (const auto legacy_result : legacy_results) {
- V1_4::RttResult hidl_result;
+ V1_6::RttResult hidl_result;
if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
return false;
}
diff --git a/wifi/1.6/default/hidl_struct_util.h b/wifi/1.6/default/hidl_struct_util.h
index 15a3205..7f0266a 100644
--- a/wifi/1.6/default/hidl_struct_util.h
+++ b/wifi/1.6/default/hidl_struct_util.h
@@ -25,8 +25,8 @@
#include <android/hardware/wifi/1.3/types.h>
#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
#include <android/hardware/wifi/1.4/types.h>
-#include <android/hardware/wifi/1.5/IWifiChip.h>
-#include <android/hardware/wifi/1.5/types.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/types.h>
#include "wifi_legacy_hal.h"
@@ -95,7 +95,7 @@
const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
std::vector<StaScanData>* hidl_scan_datas);
bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
- V1_5::StaLinkLayerStats* hidl_stats);
+ V1_6::StaLinkLayerStats* hidl_stats);
bool convertLegacyRoamingCapabilitiesToHidl(
const legacy_hal::wifi_roaming_capabilities& legacy_caps,
StaRoamingCapabilities* hidl_caps);
@@ -156,40 +156,40 @@
bool convertLegacyNanDataPathRequestIndToHidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
NanDataPathRequestInd* hidl_ind);
bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
- V1_2::NanDataPathConfirmInd* hidl_ind);
+ V1_6::NanDataPathConfirmInd* hidl_ind);
bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
- V1_2::NanDataPathScheduleUpdateInd* hidl_ind);
+ V1_6::NanDataPathScheduleUpdateInd* hidl_ind);
// RTT controller conversion methods.
-bool convertHidlVectorOfRttConfigToLegacy(const std::vector<V1_4::RttConfig>& hidl_configs,
+bool convertHidlVectorOfRttConfigToLegacy(const std::vector<V1_6::RttConfig>& hidl_configs,
std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
bool convertHidlRttLciInformationToLegacy(const RttLciInformation& hidl_info,
legacy_hal::wifi_lci_information* legacy_info);
bool convertHidlRttLcrInformationToLegacy(const RttLcrInformation& hidl_info,
legacy_hal::wifi_lcr_information* legacy_info);
-bool convertHidlRttResponderToLegacy(const V1_4::RttResponder& hidl_responder,
+bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
legacy_hal::wifi_rtt_responder* legacy_responder);
-bool convertHidlWifiChannelInfoToLegacy(const WifiChannelInfo& hidl_info,
+bool convertHidlWifiChannelInfoToLegacy(const V1_6::WifiChannelInfo& hidl_info,
legacy_hal::wifi_channel_info* legacy_info);
bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
- V1_4::RttResponder* hidl_responder);
+ V1_6::RttResponder* hidl_responder);
bool convertLegacyRttCapabilitiesToHidl(
const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
- V1_4::RttCapabilities* hidl_capabilities);
+ V1_6::RttCapabilities* hidl_capabilities);
bool convertLegacyVectorOfRttResultToHidl(
const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
- std::vector<V1_4::RttResult>* hidl_results);
+ std::vector<V1_6::RttResult>* hidl_results);
uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand band);
uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask);
uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask);
bool convertLegacyWifiUsableChannelsToHidl(
const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
- std::vector<V1_5::WifiUsableChannel>* hidl_usable_channels);
+ std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels);
bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
- V1_5::StaPeerInfo* hidl_peer_info_stats);
+ V1_6::StaPeerInfo* hidl_peer_info_stats);
bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
- V1_4::WifiRateInfo* hidl_rate);
+ V1_6::WifiRateInfo* hidl_rate);
} // namespace hidl_struct_util
} // namespace implementation
} // namespace V1_6
diff --git a/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
index 1182a58..077c6cc 100644
--- a/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
@@ -37,7 +37,7 @@
namespace V1_6 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
-using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
+using ::android::hardware::wifi::V1_6::WifiChannelWidthInMhz;
class HidlStructUtilTest : public Test {};
@@ -216,7 +216,7 @@
peer.rate_stats.push_back(rate_stat2);
}
- V1_5::StaLinkLayerStats converted{};
+ V1_6::StaLinkLayerStats converted{};
hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &converted);
EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.V1_0.beaconRx);
EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.V1_0.avgRssiMgmt);
@@ -294,43 +294,42 @@
EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
EXPECT_EQ(legacy_stats.radios[i].stats.radio, converted.radios[i].radioId);
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time, converted.radios[i].V1_3.V1_0.onTimeInMs);
- EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, converted.radios[i].V1_3.V1_0.txTimeInMs);
- EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, converted.radios[i].V1_3.V1_0.rxTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time, converted.radios[i].V1_0.onTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, converted.radios[i].V1_0.txTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, converted.radios[i].V1_0.rxTimeInMs);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
- converted.radios[i].V1_3.V1_0.onTimeInMsForScan);
+ converted.radios[i].V1_0.onTimeInMsForScan);
EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
- converted.radios[i].V1_3.V1_0.txTimeInMsPerLevel.size());
+ converted.radios[i].V1_0.txTimeInMsPerLevel.size());
for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size(); j++) {
EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
- converted.radios[i].V1_3.V1_0.txTimeInMsPerLevel[j]);
+ converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
}
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
- converted.radios[i].V1_3.onTimeInMsForNanScan);
+ converted.radios[i].onTimeInMsForNanScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
- converted.radios[i].V1_3.onTimeInMsForBgScan);
+ converted.radios[i].onTimeInMsForBgScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
- converted.radios[i].V1_3.onTimeInMsForRoamScan);
+ converted.radios[i].onTimeInMsForRoamScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
- converted.radios[i].V1_3.onTimeInMsForPnoScan);
+ converted.radios[i].onTimeInMsForPnoScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
- converted.radios[i].V1_3.onTimeInMsForHs20Scan);
+ converted.radios[i].onTimeInMsForHs20Scan);
EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
- converted.radios[i].V1_3.channelStats.size());
+ converted.radios[i].channelStats.size());
for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size(); k++) {
auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
- converted.radios[i].V1_3.channelStats[k].channel.width);
+ converted.radios[i].channelStats[k].channel.width);
EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
- converted.radios[i].V1_3.channelStats[k].channel.centerFreq);
+ converted.radios[i].channelStats[k].channel.centerFreq);
EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
- converted.radios[i].V1_3.channelStats[k].channel.centerFreq0);
+ converted.radios[i].channelStats[k].channel.centerFreq0);
EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
- converted.radios[i].V1_3.channelStats[k].channel.centerFreq1);
+ converted.radios[i].channelStats[k].channel.centerFreq1);
EXPECT_EQ(legacy_channel_st.cca_busy_time,
- converted.radios[i].V1_3.channelStats[k].ccaBusyTimeInMs);
- EXPECT_EQ(legacy_channel_st.on_time,
- converted.radios[i].V1_3.channelStats[k].onTimeInMs);
+ converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+ EXPECT_EQ(legacy_channel_st.on_time, converted.radios[i].channelStats[k].onTimeInMs);
}
}
diff --git a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
index 5390411..542b180 100644
--- a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
@@ -238,7 +238,7 @@
bool createRttController() {
bool success = false;
- chip_->createRttController_1_4(
+ chip_->createRttController_1_6(
NULL, [&success](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
if (WifiStatusCode::SUCCESS == status.code) {
ASSERT_NE(rtt.get(), nullptr);
@@ -716,7 +716,7 @@
// Create RTT controller
sp<IWifiRttController> rtt_controller;
- chip_->createRttController_1_4(
+ chip_->createRttController_1_6(
NULL, [&rtt_controller](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
if (WifiStatusCode::SUCCESS == status.code) {
ASSERT_NE(rtt.get(), nullptr);
diff --git a/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
index c7c566b..13b2849 100644
--- a/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
+++ b/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -85,8 +85,13 @@
MOCK_METHOD1(eventDataPathConfirm,
Return<void>(const android::hardware::wifi::V1_0::NanDataPathConfirmInd&));
MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
- MOCK_METHOD1(eventDataPathConfirm_1_2, Return<void>(const NanDataPathConfirmInd&));
- MOCK_METHOD1(eventDataPathScheduleUpdate, Return<void>(const NanDataPathScheduleUpdateInd&));
+ MOCK_METHOD1(eventDataPathConfirm_1_2,
+ Return<void>(const android::hardware::wifi::V1_2::NanDataPathConfirmInd&));
+ MOCK_METHOD1(eventDataPathConfirm_1_6, Return<void>(const NanDataPathConfirmInd&));
+ MOCK_METHOD1(eventDataPathScheduleUpdate,
+ Return<void>(const android::hardware::wifi::V1_2::NanDataPathScheduleUpdateInd&));
+ MOCK_METHOD1(eventDataPathScheduleUpdate_1_6,
+ Return<void>(const NanDataPathScheduleUpdateInd&));
MOCK_METHOD3(notifyCapabilitiesResponse_1_5,
Return<void>(uint16_t, const WifiNanStatus&, const V1_5::NanCapabilities&));
};
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
index c1ce766..11512f4 100644
--- a/wifi/1.6/default/wifi_chip.cpp
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -707,6 +707,21 @@
&WifiChip::triggerSubsystemRestartInternal, hidl_status_cb);
}
+Return<void> WifiChip::createRttController_1_6(const sp<IWifiIface>& bound_iface,
+ createRttController_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createRttControllerInternal_1_6, hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getUsableChannels_1_6(
+ WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+ hidl_bitfield<V1_5::IWifiChip::UsableChannelFilter> filterMask,
+ getUsableChannels_1_6_cb _hidl_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getUsableChannelsInternal_1_6, _hidl_cb, band, ifaceModeMask,
+ filterMask);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
@@ -1114,7 +1129,7 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
-std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> WifiChip::createStaIfaceInternal() {
+std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::createStaIfaceInternal() {
if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
@@ -1144,7 +1159,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
}
-std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> WifiChip::getStaIfaceInternal(
+std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::getStaIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(sta_ifaces_, ifname);
if (!iface.get()) {
@@ -1351,16 +1366,9 @@
}
std::pair<WifiStatus, sp<V1_4::IWifiRttController>> WifiChip::createRttControllerInternal_1_4(
- const sp<IWifiIface>& bound_iface) {
- if (sta_ifaces_.size() == 0 && !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
- LOG(ERROR) << "createRttControllerInternal_1_4: Chip cannot support STAs "
- "(and RTT by extension)";
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- sp<WifiRttController> rtt =
- new WifiRttController(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
- rtt_controllers_.emplace_back(rtt);
- return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
+ const sp<IWifiIface>& /*bound_iface*/) {
+ LOG(ERROR) << "createRttController_1_4 is not supported on this HAL";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
}
WifiStatus WifiChip::registerEventCallbackInternal_1_4(
@@ -1409,7 +1417,31 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-std::pair<WifiStatus, std::vector<WifiUsableChannel>> WifiChip::getUsableChannelsInternal(
+std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> WifiChip::getUsableChannelsInternal(
+ WifiBand /*band*/, uint32_t /*ifaceModeMask*/, uint32_t /*filterMask*/) {
+ LOG(ERROR) << "getUsableChannels is not supported on this HAL";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiChip::triggerSubsystemRestartInternal() {
+ auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, sp<V1_6::IWifiRttController>> WifiChip::createRttControllerInternal_1_6(
+ const sp<IWifiIface>& bound_iface) {
+ if (sta_ifaces_.size() == 0 && !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+ LOG(ERROR) << "createRttControllerInternal_1_6: Chip cannot support STAs "
+ "(and RTT by extension)";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ sp<WifiRttController> rtt =
+ new WifiRttController(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
+ rtt_controllers_.emplace_back(rtt);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
+}
+
+std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> WifiChip::getUsableChannelsInternal_1_6(
WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask) {
legacy_hal::wifi_error legacy_status;
std::vector<legacy_hal::wifi_usable_channel> legacy_usable_channels;
@@ -1421,7 +1453,7 @@
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {createWifiStatusFromLegacyError(legacy_status), {}};
}
- std::vector<WifiUsableChannel> hidl_usable_channels;
+ std::vector<V1_6::WifiUsableChannel> hidl_usable_channels;
if (!hidl_struct_util::convertLegacyWifiUsableChannelsToHidl(legacy_usable_channels,
&hidl_usable_channels)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
@@ -1429,11 +1461,6 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_usable_channels};
}
-WifiStatus WifiChip::triggerSubsystemRestartInternal() {
- auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
WifiStatus WifiChip::handleChipConfiguration(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id) {
// If the chip is already configured in a different mode, stop
diff --git a/wifi/1.6/default/wifi_chip.h b/wifi/1.6/default/wifi_chip.h
index 8a06898..73bdf3a 100644
--- a/wifi/1.6/default/wifi_chip.h
+++ b/wifi/1.6/default/wifi_chip.h
@@ -22,8 +22,9 @@
#include <mutex>
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.4/IWifiRttController.h>
-#include <android/hardware/wifi/1.5/IWifiChip.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/IWifiRttController.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
#include "hidl_callback_util.h"
#include "ringbuffer.h"
@@ -43,14 +44,13 @@
namespace implementation {
using namespace android::hardware::wifi::V1_0;
using V1_5::WifiBand;
-using V1_5::WifiUsableChannel;
/**
* HIDL interface object used to control a Wifi HAL chip instance.
* Since there is only a single chip instance used today, there is no
* identifying handle information stored here.
*/
-class WifiChip : public V1_5::IWifiChip {
+class WifiChip : public V1_6::IWifiChip {
public:
WifiChip(ChipId chip_id, bool is_primary,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -154,6 +154,12 @@
hidl_bitfield<UsableChannelFilter> filterMask,
getUsableChannels_cb _hidl_cb) override;
Return<void> triggerSubsystemRestart(triggerSubsystemRestart_cb hidl_status_cb) override;
+ Return<void> createRttController_1_6(const sp<IWifiIface>& bound_iface,
+ createRttController_1_6_cb hidl_status_cb) override;
+ Return<void> getUsableChannels_1_6(WifiBand band,
+ hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+ hidl_bitfield<UsableChannelFilter> filterMask,
+ getUsableChannels_1_6_cb _hidl_cb) override;
private:
void invalidateAndRemoveAllIfaces();
@@ -191,9 +197,9 @@
std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(const std::string& ifname);
WifiStatus removeP2pIfaceInternal(const std::string& ifname);
- std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> createStaIfaceInternal();
+ std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> createStaIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
- std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> getStaIfaceInternal(const std::string& ifname);
+ std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> getStaIfaceInternal(const std::string& ifname);
WifiStatus removeStaIfaceInternal(const std::string& ifname);
std::pair<WifiStatus, sp<V1_0::IWifiRttController>> createRttControllerInternal(
const sp<IWifiIface>& bound_iface);
@@ -225,13 +231,12 @@
WifiStatus setCoexUnsafeChannelsInternal(std::vector<CoexUnsafeChannel> unsafe_channels,
uint32_t restrictions);
WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
- std::pair<WifiStatus, std::vector<WifiUsableChannel>> getUsableChannelsInternal(
+ std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> getUsableChannelsInternal(
WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
WifiStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
ChipModeId mode_id);
WifiStatus registerDebugRingBufferCallback();
WifiStatus registerRadioModeChangeCallback();
-
std::vector<V1_4::IWifiChip::ChipIfaceCombination> getCurrentModeIfaceCombinations();
std::map<IfaceType, size_t> getCurrentIfaceCombination();
std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
@@ -258,6 +263,10 @@
void invalidateAndClearBridgedAp(const std::string& br_name);
bool findUsingNameFromBridgedApInstances(const std::string& name);
WifiStatus triggerSubsystemRestartInternal();
+ std::pair<WifiStatus, sp<V1_6::IWifiRttController>> createRttControllerInternal_1_6(
+ const sp<IWifiIface>& bound_iface);
+ std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> getUsableChannelsInternal_1_6(
+ WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
ChipId chip_id_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
diff --git a/wifi/1.6/default/wifi_legacy_hal.h b/wifi/1.6/default/wifi_legacy_hal.h
index d87242c..7dc6bd6 100644
--- a/wifi/1.6/default/wifi_legacy_hal.h
+++ b/wifi/1.6/default/wifi_legacy_hal.h
@@ -216,6 +216,7 @@
using ::WIFI_CHAN_WIDTH_10;
using ::WIFI_CHAN_WIDTH_160;
using ::WIFI_CHAN_WIDTH_20;
+using ::WIFI_CHAN_WIDTH_320;
using ::WIFI_CHAN_WIDTH_40;
using ::WIFI_CHAN_WIDTH_5;
using ::WIFI_CHAN_WIDTH_80;
@@ -289,12 +290,14 @@
using ::WIFI_RTT_BW_10;
using ::WIFI_RTT_BW_160;
using ::WIFI_RTT_BW_20;
+using ::WIFI_RTT_BW_320;
using ::WIFI_RTT_BW_40;
using ::WIFI_RTT_BW_5;
using ::WIFI_RTT_BW_80;
using ::wifi_rtt_capabilities;
using ::wifi_rtt_config;
using ::wifi_rtt_preamble;
+using ::WIFI_RTT_PREAMBLE_EHT;
using ::WIFI_RTT_PREAMBLE_HE;
using ::WIFI_RTT_PREAMBLE_HT;
using ::WIFI_RTT_PREAMBLE_LEGACY;
diff --git a/wifi/1.6/default/wifi_nan_iface.cpp b/wifi/1.6/default/wifi_nan_iface.cpp
index 236cb64..1add6dc 100644
--- a/wifi/1.6/default/wifi_nan_iface.cpp
+++ b/wifi/1.6/default/wifi_nan_iface.cpp
@@ -378,15 +378,15 @@
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
- V1_2::NanDataPathConfirmInd hidl_struct;
+ V1_6::NanDataPathConfirmInd hidl_struct;
if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(msg,
&hidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
- for (const auto& callback : shared_ptr_this->getEventCallbacks_1_2()) {
- if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+ if (!callback->eventDataPathConfirm_1_6(hidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
@@ -430,15 +430,15 @@
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
- V1_2::NanDataPathScheduleUpdateInd hidl_struct;
+ V1_6::NanDataPathScheduleUpdateInd hidl_struct;
if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
msg, &hidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
- for (const auto& callback : shared_ptr_this->getEventCallbacks_1_2()) {
- if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+ if (!callback->eventDataPathScheduleUpdate_1_6(hidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
@@ -510,6 +510,10 @@
return event_cb_handler_1_5_.getCallbacks();
}
+std::set<sp<V1_6::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_6() {
+ return event_cb_handler_1_6_.getCallbacks();
+}
+
Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::getNameInternal, hidl_status_cb);
@@ -703,6 +707,14 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
}
+Return<void> WifiNanIface::registerEventCallback_1_6(
+ const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallback_1_6Internal, hidl_status_cb,
+ callback);
+}
+
WifiStatus WifiNanIface::registerEventCallbackInternal(
const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
if (!event_cb_handler_.addCallback(callback)) {
@@ -898,6 +910,25 @@
return createWifiStatusFromLegacyError(legacy_status);
}
+WifiStatus WifiNanIface::registerEventCallback_1_6Internal(
+ const sp<V1_6::IWifiNanIfaceEventCallback>& callback) {
+ sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+ if (!event_cb_handler_.addCallback(callback_1_0)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
+ if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ sp<V1_5::IWifiNanIfaceEventCallback> callback_1_5 = callback;
+ if (!event_cb_handler_1_5_.addCallback(callback_1_5)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ if (!event_cb_handler_1_6_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
} // namespace implementation
} // namespace V1_6
} // namespace wifi
diff --git a/wifi/1.6/default/wifi_nan_iface.h b/wifi/1.6/default/wifi_nan_iface.h
index c445afc..b732ef1 100644
--- a/wifi/1.6/default/wifi_nan_iface.h
+++ b/wifi/1.6/default/wifi_nan_iface.h
@@ -18,8 +18,8 @@
#define WIFI_NAN_IFACE_H_
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.5/IWifiNanIface.h>
-#include <android/hardware/wifi/1.5/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.6/IWifiNanIface.h>
+#include <android/hardware/wifi/1.6/IWifiNanIfaceEventCallback.h>
#include "hidl_callback_util.h"
#include "wifi_iface_util.h"
@@ -36,7 +36,7 @@
/**
* HIDL interface object used to control a NAN Iface instance.
*/
-class WifiNanIface : public V1_5::IWifiNanIface {
+class WifiNanIface : public V1_6::IWifiNanIface {
public:
WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -104,6 +104,8 @@
configRequest_1_4_cb hidl_status_cb) override;
Return<void> getCapabilitiesRequest_1_5(uint16_t cmd_id,
getCapabilitiesRequest_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_6(const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -145,6 +147,8 @@
WifiStatus configRequest_1_5Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
const V1_5::NanConfigRequestSupplemental& msg2);
WifiStatus getCapabilitiesRequest_1_5Internal(uint16_t cmd_id);
+ WifiStatus registerEventCallback_1_6Internal(
+ const sp<V1_6::IWifiNanIfaceEventCallback>& callback);
// all 1_0 and descendant callbacks
std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
@@ -152,6 +156,8 @@
std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
// all 1_5 and descendant callbacks
std::set<sp<V1_5::IWifiNanIfaceEventCallback>> getEventCallbacks_1_5();
+ // all 1_6 and descendant callbacks
+ std::set<sp<V1_6::IWifiNanIfaceEventCallback>> getEventCallbacks_1_6();
std::string ifname_;
bool is_dedicated_iface_;
@@ -161,6 +167,7 @@
hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback> event_cb_handler_;
hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback> event_cb_handler_1_2_;
hidl_callback_util::HidlCallbackHandler<V1_5::IWifiNanIfaceEventCallback> event_cb_handler_1_5_;
+ hidl_callback_util::HidlCallbackHandler<V1_6::IWifiNanIfaceEventCallback> event_cb_handler_1_6_;
DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
};
diff --git a/wifi/1.6/default/wifi_rtt_controller.cpp b/wifi/1.6/default/wifi_rtt_controller.cpp
index f5e1d5a..b328f31 100644
--- a/wifi/1.6/default/wifi_rtt_controller.cpp
+++ b/wifi/1.6/default/wifi_rtt_controller.cpp
@@ -43,7 +43,7 @@
return is_valid_;
}
-std::vector<sp<V1_4::IWifiRttControllerEventCallback>> WifiRttController::getEventCallbacks() {
+std::vector<sp<V1_6::IWifiRttControllerEventCallback>> WifiRttController::getEventCallbacks() {
return event_callbacks_;
}
@@ -102,7 +102,7 @@
}
Return<void> WifiRttController::enableResponder(uint32_t cmd_id,
- const WifiChannelInfo& channel_hint,
+ const V1_0::WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds,
const V1_0::RttResponder& info,
enableResponder_cb hidl_status_cb) {
@@ -144,7 +144,7 @@
}
Return<void> WifiRttController::enableResponder_1_4(uint32_t cmd_id,
- const WifiChannelInfo& channel_hint,
+ const V1_0::WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds,
const V1_4::RttResponder& info,
enableResponder_1_4_cb hidl_status_cb) {
@@ -153,6 +153,42 @@
channel_hint, max_duration_seconds, info);
}
+Return<void> WifiRttController::registerEventCallback_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::registerEventCallbackInternal_1_6, hidl_status_cb,
+ callback);
+}
+
+Return<void> WifiRttController::rangeRequest_1_6(uint32_t cmd_id,
+ const hidl_vec<V1_6::RttConfig>& rtt_configs,
+ rangeRequest_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeRequestInternal_1_6, hidl_status_cb, cmd_id,
+ rtt_configs);
+}
+
+Return<void> WifiRttController::getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getCapabilitiesInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiRttController::getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getResponderInfoInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder_1_6(uint32_t cmd_id,
+ const V1_6::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_6::RttResponder& info,
+ enableResponder_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::enableResponderInternal_1_6, hidl_status_cb, cmd_id,
+ channel_hint, max_duration_seconds, info);
+}
+
std::pair<WifiStatus, sp<IWifiIface>> WifiRttController::getBoundIfaceInternal() {
return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
}
@@ -210,10 +246,9 @@
return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
}
-WifiStatus WifiRttController::enableResponderInternal(uint32_t /* cmd_id */,
- const WifiChannelInfo& /* channel_hint */,
- uint32_t /* max_duration_seconds */,
- const V1_0::RttResponder& /* info */) {
+WifiStatus WifiRttController::enableResponderInternal(
+ uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
+ uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
// Deprecated support for this api
return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
}
@@ -224,14 +259,43 @@
}
WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
- const sp<V1_4::IWifiRttControllerEventCallback>& callback) {
+ const sp<V1_4::IWifiRttControllerEventCallback>& /* callback */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal_1_4(
+ uint32_t /* cmd_id */, const std::vector<V1_4::RttConfig>& /* rtt_configs */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, V1_4::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_4() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_4::RttResponder> WifiRttController::getResponderInfoInternal_1_4() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::enableResponderInternal_1_4(
+ uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
+ uint32_t /* max_duration_seconds */, const V1_4::RttResponder& /* info */) {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback) {
// TODO(b/31632518): remove the callback when the client is destroyed
event_callbacks_.emplace_back(callback);
return createWifiStatus(WifiStatusCode::SUCCESS);
}
-WifiStatus WifiRttController::rangeRequestInternal_1_4(
- uint32_t cmd_id, const std::vector<V1_4::RttConfig>& rtt_configs) {
+WifiStatus WifiRttController::rangeRequestInternal_1_6(
+ uint32_t cmd_id, const std::vector<V1_6::RttConfig>& rtt_configs) {
std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
@@ -245,14 +309,14 @@
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
- std::vector<V1_4::RttResult> hidl_results;
+ std::vector<V1_6::RttResult> hidl_results;
if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(results,
&hidl_results)) {
LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- callback->onResults_1_4(id, hidl_results);
+ callback->onResults_1_6(id, hidl_results);
}
};
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
@@ -260,38 +324,38 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-std::pair<WifiStatus, V1_4::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_4() {
+std::pair<WifiStatus, V1_6::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_6() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_rtt_capabilities legacy_caps;
std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {createWifiStatusFromLegacyError(legacy_status), {}};
}
- V1_4::RttCapabilities hidl_caps;
+ V1_6::RttCapabilities hidl_caps;
if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
}
return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
}
-std::pair<WifiStatus, V1_4::RttResponder> WifiRttController::getResponderInfoInternal_1_4() {
+std::pair<WifiStatus, V1_6::RttResponder> WifiRttController::getResponderInfoInternal_1_6() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_rtt_responder legacy_responder;
std::tie(legacy_status, legacy_responder) = legacy_hal_.lock()->getRttResponderInfo(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {createWifiStatusFromLegacyError(legacy_status), {}};
}
- V1_4::RttResponder hidl_responder;
+ V1_6::RttResponder hidl_responder;
if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder, &hidl_responder)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
}
return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
}
-WifiStatus WifiRttController::enableResponderInternal_1_4(uint32_t cmd_id,
- const WifiChannelInfo& channel_hint,
+WifiStatus WifiRttController::enableResponderInternal_1_6(uint32_t cmd_id,
+ const V1_6::WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds,
- const V1_4::RttResponder& info) {
+ const V1_6::RttResponder& info) {
legacy_hal::wifi_channel_info legacy_channel_info;
if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
diff --git a/wifi/1.6/default/wifi_rtt_controller.h b/wifi/1.6/default/wifi_rtt_controller.h
index b4a2116..fd5f68b 100644
--- a/wifi/1.6/default/wifi_rtt_controller.h
+++ b/wifi/1.6/default/wifi_rtt_controller.h
@@ -19,8 +19,8 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.0/IWifiIface.h>
-#include <android/hardware/wifi/1.4/IWifiRttController.h>
-#include <android/hardware/wifi/1.4/IWifiRttControllerEventCallback.h>
+#include <android/hardware/wifi/1.6/IWifiRttController.h>
+#include <android/hardware/wifi/1.6/IWifiRttControllerEventCallback.h>
#include "wifi_legacy_hal.h"
@@ -33,14 +33,14 @@
/**
* HIDL interface object used to control all RTT operations.
*/
-class WifiRttController : public V1_4::IWifiRttController {
+class WifiRttController : public V1_6::IWifiRttController {
public:
WifiRttController(const std::string& iface_name, const sp<IWifiIface>& bound_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
- std::vector<sp<V1_4::IWifiRttControllerEventCallback>> getEventCallbacks();
+ std::vector<sp<V1_6::IWifiRttControllerEventCallback>> getEventCallbacks();
std::string getIfaceName();
// HIDL methods exposed.
@@ -57,7 +57,7 @@
Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
setLcr_cb hidl_status_cb) override;
Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
- Return<void> enableResponder(uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ Return<void> enableResponder(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds, const V1_0::RttResponder& info,
enableResponder_cb hidl_status_cb) override;
Return<void> disableResponder(uint32_t cmd_id, disableResponder_cb hidl_status_cb) override;
@@ -68,9 +68,19 @@
rangeRequest_1_4_cb hidl_status_cb) override;
Return<void> getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) override;
Return<void> getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) override;
- Return<void> enableResponder_1_4(uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ Return<void> enableResponder_1_4(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds, const V1_4::RttResponder& info,
enableResponder_1_4_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) override;
+ Return<void> rangeRequest_1_6(uint32_t cmd_id, const hidl_vec<V1_6::RttConfig>& rtt_configs,
+ rangeRequest_1_6_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) override;
+ Return<void> getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) override;
+ Return<void> enableResponder_1_6(uint32_t cmd_id, const V1_6::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const V1_6::RttResponder& info,
+ enableResponder_1_6_cb hidl_status_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -85,7 +95,7 @@
WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
- WifiStatus enableResponderInternal(uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ WifiStatus enableResponderInternal(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds,
const V1_0::RttResponder& info);
WifiStatus disableResponderInternal(uint32_t cmd_id);
@@ -95,14 +105,25 @@
const std::vector<V1_4::RttConfig>& rtt_configs);
std::pair<WifiStatus, V1_4::RttCapabilities> getCapabilitiesInternal_1_4();
std::pair<WifiStatus, V1_4::RttResponder> getResponderInfoInternal_1_4();
- WifiStatus enableResponderInternal_1_4(uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
+ const V1_0::WifiChannelInfo& channel_hint,
uint32_t max_duration_seconds,
const V1_4::RttResponder& info);
+ WifiStatus registerEventCallbackInternal_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback);
+ WifiStatus rangeRequestInternal_1_6(uint32_t cmd_id,
+ const std::vector<V1_6::RttConfig>& rtt_configs);
+ std::pair<WifiStatus, V1_6::RttCapabilities> getCapabilitiesInternal_1_6();
+ std::pair<WifiStatus, V1_6::RttResponder> getResponderInfoInternal_1_6();
+ WifiStatus enableResponderInternal_1_6(uint32_t cmd_id,
+ const V1_6::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_6::RttResponder& info);
std::string ifname_;
sp<IWifiIface> bound_iface_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::vector<sp<V1_4::IWifiRttControllerEventCallback>> event_callbacks_;
+ std::vector<sp<V1_6::IWifiRttControllerEventCallback>> event_callbacks_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiRttController);
diff --git a/wifi/1.6/default/wifi_sta_iface.cpp b/wifi/1.6/default/wifi_sta_iface.cpp
index f852d36..dd11839 100644
--- a/wifi/1.6/default/wifi_sta_iface.cpp
+++ b/wifi/1.6/default/wifi_sta_iface.cpp
@@ -150,6 +150,11 @@
&WifiStaIface::getLinkLayerStatsInternal_1_5, hidl_status_cb);
}
+Return<void> WifiStaIface::getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal_1_6, hidl_status_cb);
+}
+
Return<void> WifiStaIface::startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
startRssiMonitoring_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -422,13 +427,17 @@
}
std::pair<WifiStatus, V1_5::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_5() {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_6::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_6() {
legacy_hal::wifi_error legacy_status;
legacy_hal::LinkLayerStats legacy_stats;
std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {createWifiStatusFromLegacyError(legacy_status), {}};
}
- V1_5::StaLinkLayerStats hidl_stats;
+ V1_6::StaLinkLayerStats hidl_stats;
if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &hidl_stats)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
}
diff --git a/wifi/1.6/default/wifi_sta_iface.h b/wifi/1.6/default/wifi_sta_iface.h
index 37358a5..c01c50b 100644
--- a/wifi/1.6/default/wifi_sta_iface.h
+++ b/wifi/1.6/default/wifi_sta_iface.h
@@ -19,7 +19,7 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.5/IWifiStaIface.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
#include "hidl_callback_util.h"
#include "wifi_iface_util.h"
@@ -35,7 +35,7 @@
/**
* HIDL interface object used to control a STA Iface instance.
*/
-class WifiStaIface : public V1_5::IWifiStaIface {
+class WifiStaIface : public V1_6::IWifiStaIface {
public:
WifiStaIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -71,6 +71,7 @@
Return<void> getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) override;
Return<void> getLinkLayerStats_1_3(getLinkLayerStats_1_3_cb hidl_status_cb) override;
Return<void> getLinkLayerStats_1_5(getLinkLayerStats_1_5_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) override;
Return<void> startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
startRssiMonitoring_cb hidl_status_cb) override;
Return<void> stopRssiMonitoring(uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
@@ -116,6 +117,7 @@
std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
std::pair<WifiStatus, V1_3::StaLinkLayerStats> getLinkLayerStatsInternal_1_3();
std::pair<WifiStatus, V1_5::StaLinkLayerStats> getLinkLayerStatsInternal_1_5();
+ std::pair<WifiStatus, V1_6::StaLinkLayerStats> getLinkLayerStatsInternal_1_6();
WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi);
WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
std::pair<WifiStatus, StaRoamingCapabilities> getRoamingCapabilitiesInternal();
diff --git a/wifi/1.6/types.hal b/wifi/1.6/types.hal
new file mode 100644
index 0000000..f1d9d45
--- /dev/null
+++ b/wifi/1.6/types.hal
@@ -0,0 +1,670 @@
+/*
+ * Copyright 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.wifi@1.6;
+
+import @1.0::MacAddress;
+import @1.0::NanDataPathConfirmInd;
+import @1.0::Rssi;
+import @1.0::RttBw;
+import @1.0::RttPeerType;
+import @1.0::RttStatus;
+import @1.0::RttType;
+import @1.0::StaLinkLayerIfaceStats;
+import @1.0::StaLinkLayerRadioStats;
+import @1.0::TimeSpanInPs;
+import @1.0::TimeStampInUs;
+import @1.0::TimeStampInMs;
+import @1.0::WifiChannelInMhz;
+import @1.0::WifiChannelWidthInMhz;
+import @1.0::WifiInformationElement;
+import @1.0::WifiRateNss;
+import @1.4::RttPreamble;
+import @1.4::WifiRatePreamble;
+import @1.5::StaLinkLayerIfaceContentionTimeStats;
+import @1.5::WifiIfaceMode;
+
+/**
+ * Channel operating width in Mhz.
+ */
+enum WifiChannelWidthInMhz : @1.0::WifiChannelWidthInMhz {
+ /**
+ * 320 MHz
+ */
+ WIDTH_320 = 7,
+};
+
+/**
+ * RTT Measurement Bandwidth.
+ */
+enum RttBw : @1.0::RttBw {
+ BW_320MHZ = 0x40,
+};
+
+/**
+ * RTT Measurement Preamble.
+ */
+enum RttPreamble : @1.4::RttPreamble {
+ /**
+ * Preamble type for 11be
+ */
+ EHT = 0x10,
+};
+
+/**
+ * Wifi Rate Preamble
+ */
+enum WifiRatePreamble : @1.4::WifiRatePreamble {
+ /**
+ * Preamble type for 11be
+ */
+ EHT = 6,
+};
+
+/**
+ * Channel information.
+ */
+struct WifiChannelInfo {
+ /**
+ * Channel width (20, 40, 80, 80+80, 160, 320).
+ */
+ WifiChannelWidthInMhz width;
+ /**
+ * Primary 20 MHz channel.
+ */
+ WifiChannelInMhz centerFreq;
+ /**
+ * Center frequency (MHz) first segment.
+ */
+ WifiChannelInMhz centerFreq0;
+ /**
+ * Center frequency (MHz) second segment.
+ */
+ WifiChannelInMhz centerFreq1;
+};
+
+/**
+ * RTT configuration.
+ */
+struct RttConfig {
+ /**
+ * Peer device mac address.
+ */
+ MacAddress addr;
+
+ /**
+ * 1-sided or 2-sided RTT.
+ */
+ RttType type;
+
+ /**
+ * Optional - peer device hint (STA, P2P, AP).
+ */
+ RttPeerType peer;
+
+ /**
+ * Required for STA-AP mode, optional for P2P, NBD etc.
+ */
+ WifiChannelInfo channel;
+
+ /**
+ * Time interval between bursts (units: 100 ms).
+ * Applies to 1-sided and 2-sided RTT multi-burst requests.
+ * Range: 0-31, 0: no preference by initiator (2-sided RTT).
+ */
+ uint32_t burstPeriod;
+
+ /**
+ * Total number of RTT bursts to be executed. It will be
+ * specified in the same way as the parameter "Number of
+ * Burst Exponent" found in the FTM frame format. It
+ * applies to both: 1-sided RTT and 2-sided RTT. Valid
+ * values are 0 to 15 as defined in 802.11mc std.
+ * 0 means single shot
+ * The implication of this parameter on the maximum
+ * number of RTT results is the following:
+ * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
+ * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+ */
+ uint32_t numBurst;
+
+ /**
+ * Num of frames per burst.
+ * Minimum value = 1, Maximum value = 31
+ * For 2-sided this equals the number of FTM frames
+ * to be attempted in a single burst. This also
+ * equals the number of FTM frames that the
+ * initiator will request that the responder send
+ * in a single frame.
+ */
+ uint32_t numFramesPerBurst;
+
+ /**
+ * Number of retries for a failed RTT frame.
+ * Applies to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+ */
+ uint32_t numRetriesPerRttFrame;
+
+ /**
+ * Following fields are only valid for 2-side RTT.
+ *
+ *
+ * Maximum number of retries that the initiator can
+ * retry an FTMR frame.
+ * Minimum value = 0, Maximum value = 3
+ */
+ uint32_t numRetriesPerFtmr;
+
+ /**
+ * Whether to request location civic info or not.
+ */
+ bool mustRequestLci;
+
+ /**
+ * Whether to request location civic records or not.
+ */
+ bool mustRequestLcr;
+
+ /**
+ * Applies to 1-sided and 2-sided RTT. Valid values will
+ * be 2-11 and 15 as specified by the 802.11mc std for
+ * the FTM parameter burst duration. In a multi-burst
+ * request, if responder overrides with larger value,
+ * the initiator will return failure. In a single-burst
+ * request if responder overrides with larger value,
+ * the initiator will sent TMR_STOP to terminate RTT
+ * at the end of the burst_duration it requested.
+ */
+ uint32_t burstDuration;
+
+ /**
+ * RTT preamble to be used in the RTT frames.
+ */
+ RttPreamble preamble;
+
+ /**
+ * RTT BW to be used in the RTT frames.
+ */
+ RttBw bw;
+};
+
+/**
+ * RTT Responder information
+ */
+struct RttResponder {
+ WifiChannelInfo channel;
+
+ RttPreamble preamble;
+};
+
+struct WifiChannelStats {
+ /**
+ * Channel information.
+ */
+ WifiChannelInfo channel;
+ /**
+ * Total time for which the radio is awake on this channel.
+ */
+ uint32_t onTimeInMs;
+ /**
+ * Total time for which CCA is held busy on this channel.
+ */
+ uint32_t ccaBusyTimeInMs;
+};
+
+struct StaLinkLayerRadioStats {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::StaLinkLayerRadioStats V1_0;
+
+ /**
+ * Total time for which the radio is awake due to NAN scan since boot or crash.
+ */
+ uint32_t onTimeInMsForNanScan;
+
+ /**
+ * Total time for which the radio is awake due to background scan since boot or crash.
+ */
+ uint32_t onTimeInMsForBgScan;
+
+ /**
+ * Total time for which the radio is awake due to roam scan since boot or crash.
+ */
+ uint32_t onTimeInMsForRoamScan;
+
+ /**
+ * Total time for which the radio is awake due to PNO scan since boot or crash.
+ */
+ uint32_t onTimeInMsForPnoScan;
+
+ /**
+ * Total time for which the radio is awake due to Hotspot 2.0 scans and GAS exchange since boot
+ * or crash.
+ */
+ uint32_t onTimeInMsForHs20Scan;
+
+ /**
+ * List of channel stats associated with this radio
+ */
+ vec<WifiChannelStats> channelStats;
+
+ /**
+ * Radio ID: An implementation specific value identifying the radio interface for which the
+ * stats are produced. Framework must not interpret this value. It must use this value for
+ * persistently identifying the statistics between calls,
+ * e.g. if the HAL provides them in different order.
+ */
+ int32_t radioId;
+};
+
+/**
+ * Per peer statistics. The types of peer include the Access Point (AP), the Tunneled Direct Link
+ * Setup (TDLS), the Group Owner (GO), the Neighbor Awareness Networking (NAN), etc.
+ */
+struct StaPeerInfo {
+ /**
+ * Station count: The total number of stations currently associated with the peer.
+ */
+ uint16_t staCount;
+ /**
+ * Channel utilization: The percentage of time (normalized to 255, i.e., x% corresponds to
+ * (int) x * 255 / 100) that the medium is sensed as busy measured by either physical or
+ * virtual carrier sense (CS) mechanism.
+ */
+ uint16_t chanUtil;
+ /**
+ * Per rate statistics
+ */
+ vec<StaRateStat> rateStats;
+};
+
+/**
+ * Iface statistics for the current connection.
+ */
+struct StaLinkLayerIfaceStats {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::StaLinkLayerIfaceStats V1_0;
+
+ /**
+ * Duty cycle for the iface.
+ * if this iface is being served using time slicing on a radio with one or more ifaces
+ * (i.e MCC), then the duty cycle assigned to this iface in %.
+ * If not using time slicing (i.e SCC or DBS), set to 100.
+ */
+ uint8_t timeSliceDutyCycleInPercent;
+
+ /**
+ * WME Best Effort (BE) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+
+ /**
+ * WME Background (BK) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+
+ /**
+ * WME Video (VI) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+
+ /**
+ * WME Voice (VO) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+
+ /**
+ * Per peer statistics.
+ */
+ vec<StaPeerInfo> peers;
+};
+
+/**
+ * Link layer stats retrieved via |getLinkLayerStats|.
+ */
+struct StaLinkLayerStats {
+ StaLinkLayerIfaceStats iface;
+
+ vec<StaLinkLayerRadioStats> radios;
+
+ /**
+ * TimeStamp for each stats sample.
+ * This is the absolute milliseconds from boot when these stats were
+ * sampled.
+ */
+ TimeStampInMs timeStampInMs;
+};
+
+/**
+ * Wifi rate info.
+ */
+struct WifiRateInfo {
+ /**
+ * Preamble used for RTT measurements.
+ */
+ WifiRatePreamble preamble;
+
+ /**
+ * Number of spatial streams.
+ */
+ WifiRateNss nss;
+
+ /**
+ * Bandwidth of channel.
+ */
+ WifiChannelWidthInMhz bw;
+
+ /**
+ * OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps.
+ * HT/VHT/HE/EHT it would be mcs index.
+ */
+ uint8_t rateMcsIdx;
+
+ /**
+ * Bitrate in units of 100 Kbps.
+ */
+ uint32_t bitRateInKbps;
+};
+
+/**
+ * Per rate statistics. The rate is characterized by the combination of preamble, number of spatial
+ * streams, transmission bandwidth, and modulation and coding scheme (MCS).
+ */
+struct StaRateStat{
+ /**
+ * Wifi rate information: preamble, number of spatial streams, bandwidth, MCS, etc.
+ */
+ WifiRateInfo rateInfo;
+ /**
+ * Number of successfully transmitted data packets (ACK received)
+ */
+ uint32_t txMpdu;
+ /**
+ * Number of received data packets
+ */
+ uint32_t rxMpdu;
+ /**
+ * Number of data packet losses (no ACK)
+ */
+ uint32_t mpduLost;
+ /**
+ * Number of data packet retries
+ */
+ uint32_t retries;
+};
+
+/**
+ * RTT results.
+ */
+struct RttResult {
+ /**
+ * Peer device mac address.
+ */
+ MacAddress addr;
+
+ /**
+ * Burst number in a multi-burst request.
+ */
+ uint32_t burstNum;
+
+ /**
+ * Total RTT measurement frames attempted.
+ */
+ uint32_t measurementNumber;
+
+ /**
+ * Total successful RTT measurement frames.
+ */
+ uint32_t successNumber;
+
+ /**
+ * Maximum number of "FTM frames per burst" supported by
+ * the responder STA. Applies to 2-sided RTT only.
+ * If reponder overrides with larger value:
+ * - for single-burst request initiator will truncate the
+ * larger value and send a TMR_STOP after receiving as
+ * many frames as originally requested.
+ * - for multi-burst request, initiator will return
+ * failure right away.
+ */
+ uint8_t numberPerBurstPeer;
+
+ /**
+ * Ranging status.
+ */
+ RttStatus status;
+
+ /**
+ * When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+ * this will be the time provided by the responder as to
+ * when the request can be tried again. Applies to 2-sided
+ * RTT only. In sec, 1-31sec.
+ */
+ uint8_t retryAfterDuration;
+
+ /**
+ * RTT type.
+ */
+ RttType type;
+
+ /**
+ * Average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB.
+ */
+ Rssi rssi;
+
+ /**
+ * Rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional).
+ */
+ Rssi rssiSpread;
+
+ /**
+ * 1-sided RTT: TX rate of RTT frame.
+ * 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+ */
+ WifiRateInfo txRate;
+
+ /**
+ * 1-sided RTT: TX rate of Ack from other side.
+ * 2-sided RTT: TX rate of FTM frame coming from responder.
+ */
+ WifiRateInfo rxRate;
+
+ /**
+ * Round trip time in picoseconds
+ */
+ TimeSpanInPs rtt;
+
+ /**
+ * Rtt standard deviation in picoseconds.
+ */
+ TimeSpanInPs rttSd;
+
+ /**
+ * Difference between max and min rtt times recorded in picoseconds.
+ */
+ TimeSpanInPs rttSpread;
+
+ /**
+ * Distance in mm (optional).
+ */
+ int32_t distanceInMm;
+
+ /**
+ * Standard deviation in mm (optional).
+ */
+ int32_t distanceSdInMm;
+
+ /**
+ * Difference between max and min distance recorded in mm (optional).
+ */
+ int32_t distanceSpreadInMm;
+
+ /**
+ * Time of the measurement (in microseconds since boot).
+ */
+ TimeStampInUs timeStampInUs;
+
+ /**
+ * in ms, actual time taken by the FW to finish one burst
+ * measurement. Applies to 1-sided and 2-sided RTT.
+ */
+ uint32_t burstDurationInMs;
+
+ /**
+ * Number of bursts allowed by the responder. Applies
+ * to 2-sided RTT only.
+ */
+ uint32_t negotiatedBurstNum;
+
+ /**
+ * for 11mc only.
+ */
+ WifiInformationElement lci;
+
+ /**
+ * for 11mc only.
+ */
+ WifiInformationElement lcr;
+};
+
+/**
+ * NAN data path channel information provided to the framework.
+ */
+struct NanDataPathChannelInfo {
+ /**
+ * Channel frequency in MHz.
+ */
+ WifiChannelInMhz channelFreq;
+ /**
+ * Channel bandwidth in MHz.
+ */
+ WifiChannelWidthInMhz channelBandwidth;
+ /**
+ * Number of spatial streams used in the channel.
+ */
+ uint32_t numSpatialStreams;
+};
+
+/**
+ * NAN Data path confirmation Indication structure.
+ * Event indication is received on both initiator and responder side when negotiation for a
+ * data-path finish: on success or failure.
+ */
+struct NanDataPathConfirmInd {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::NanDataPathConfirmInd V1_0;
+ /**
+ * The channel(s) on which the NDP is scheduled to operate.
+ * Updates to the operational channels are provided using the |eventDataPathScheduleUpdate|
+ * event.
+ */
+ vec<NanDataPathChannelInfo> channelInfo;
+};
+
+/**
+ * NAN data path channel information update indication structure.
+ * Event indication is received by all NDP owners whenever the channels on which the NDP operates
+ * are updated.
+ * Note: multiple NDPs may share the same schedule, the indication specifies all NDPs to which it
+ * applies.
+ */
+struct NanDataPathScheduleUpdateInd {
+ /**
+ * The discovery address (NMI) of the peer to which the NDP is connected.
+ */
+ MacAddress peerDiscoveryAddress;
+ /**
+ * The updated channel(s) information.
+ */
+ vec<NanDataPathChannelInfo> channelInfo;
+ /**
+ * The list of NDPs to which this update applies.
+ */
+ vec<uint32_t> ndpInstanceIds;
+};
+
+/**
+ * Wifi usable channel information.
+ */
+struct WifiUsableChannel {
+ /**
+ * Wifi channel freqeuncy in MHz.
+ */
+ WifiChannelInMhz channel;
+
+ /**
+ * Wifi channel bandwidth in MHz.
+ */
+ WifiChannelWidthInMhz channelBandwidth;
+
+ /**
+ * Iface modes feasible on this channel.
+ */
+ bitfield<WifiIfaceMode> ifaceModeMask;
+};
+
+/**
+ * RTT Capabilities.
+ */
+struct RttCapabilities {
+ /**
+ * if 1-sided rtt data collection is supported.
+ */
+ bool rttOneSidedSupported;
+
+ /**
+ * if ftm rtt data collection is supported.
+ */
+ bool rttFtmSupported;
+
+ /**
+ * if initiator supports LCI request. Applies to 2-sided RTT.
+ */
+ bool lciSupported;
+
+ /**
+ * if initiator supports LCR request. Applies to 2-sided RTT.
+ */
+ bool lcrSupported;
+
+ /**
+ * if 11mc responder mode is supported.
+ */
+ bool responderSupported;
+
+ /**
+ * Bit mask indicates what preamble is supported by initiator.
+ * Combination of |RttPreamble| values.
+ */
+ bitfield<RttPreamble> preambleSupport;
+
+ /**
+ * Bit mask indicates what BW is supported by initiator.
+ * Combination of |RttBw| values.
+ */
+ bitfield<RttBw> bwSupport;
+
+ /**
+ * Draft 11mc spec version supported by chip.
+ * For instance, version 4.0 must be 40 and version 4.3 must be 43 etc.
+ */
+ uint8_t mcVersion;
+};
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl
index 890d986..4d78640 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Bandwidth.aidl
@@ -41,8 +41,9 @@
BANDWIDTH_80 = 4,
BANDWIDTH_80P80 = 5,
BANDWIDTH_160 = 6,
- BANDWIDTH_2160 = 7,
- BANDWIDTH_4320 = 8,
- BANDWIDTH_6480 = 9,
- BANDWIDTH_8640 = 10,
+ BANDWIDTH_320 = 7,
+ BANDWIDTH_2160 = 8,
+ BANDWIDTH_4320 = 9,
+ BANDWIDTH_6480 = 10,
+ BANDWIDTH_8640 = 11,
}
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
index 6b60d17..af0e960 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
@@ -40,4 +40,5 @@
WIFI_STANDARD_11AC = 2,
WIFI_STANDARD_11AX = 3,
WIFI_STANDARD_11AD = 4,
+ WIFI_STANDARD_11BE = 5,
}
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl
index 844c838..8d8d7bb 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HwModeParams.aidl
@@ -43,4 +43,5 @@
boolean enableHeMultiUserBeamformer;
boolean enableHeTargetWakeTime;
boolean enableEdmg;
+ boolean enable80211BE;
}
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl
index c982402..e605153 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Bandwidth.aidl
@@ -29,8 +29,9 @@
BANDWIDTH_80 = 4,
BANDWIDTH_80P80 = 5,
BANDWIDTH_160 = 6,
- BANDWIDTH_2160 = 7,
- BANDWIDTH_4320 = 8,
- BANDWIDTH_6480 = 9,
- BANDWIDTH_8640 = 10,
+ BANDWIDTH_320 = 7,
+ BANDWIDTH_2160 = 8,
+ BANDWIDTH_4320 = 9,
+ BANDWIDTH_6480 = 10,
+ BANDWIDTH_8640 = 11,
}
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
index 2cda55b..f4e3eb0 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
@@ -27,6 +27,7 @@
* WIFI_STANDARD_11AC = hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 1.
* WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211A and High Efficiency supported.
* WIFI_STANDARD_11AD = hw_mode is HOSTAPD_MODE_IEEE80211AD.
+ * WIFI_STANDARD_11BE = hw_mode is HOSTAPD_MODE_IEEE80211A and Extreme High Throughput supported.
*/
@VintfStability
@Backing(type="int")
@@ -37,4 +38,5 @@
WIFI_STANDARD_11AC = 2,
WIFI_STANDARD_11AX = 3,
WIFI_STANDARD_11AD = 4,
+ WIFI_STANDARD_11BE = 5,
}
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl
index 210e99f..e66a24a 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/HwModeParams.aidl
@@ -68,4 +68,10 @@
* Enable EDMG (802.11ay), this option is only allowed for the 60GHz band.
*/
boolean enableEdmg;
+ /**
+ * Whether IEEE 802.11be (Extreme High Throughput) is enabled or not.
+ * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+ * used with Extreme High Throughput.
+ */
+ boolean enable80211BE;
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WifiTechnology.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WifiTechnology.aidl
index ad36e68..bf5081e 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WifiTechnology.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WifiTechnology.aidl
@@ -39,4 +39,5 @@
HT = 2,
VHT = 3,
HE = 4,
+ EHT = 5,
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WifiTechnology.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WifiTechnology.aidl
index 00c16b4..d364c75 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WifiTechnology.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WifiTechnology.aidl
@@ -39,4 +39,8 @@
* For 802.11ax
*/
HE = 4,
+ /**
+ * For 802.11be
+ */
+ EHT = 5,
}