Merge "Camera: add external camera@3.5"
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
index f27c739..f3256f1 100644
--- a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
@@ -101,6 +101,7 @@
case -ENOENT: {
// No more effects available.
result.resize(i);
+ break;
}
default: {
result.resize(0);
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index 6af774e..f64028c 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -30,7 +30,6 @@
"StatusCode",
"SubscribeFlags",
"SubscribeOptions",
- "VehicleApPowerBootupReason",
"VehicleApPowerStateConfigFlag",
"VehicleApPowerStateReport",
"VehicleApPowerStateReq",
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index e0b54d0..5007a6d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -36,6 +36,9 @@
constexpr int DOOR_1_RIGHT = (int)VehicleAreaDoor::ROW_1_RIGHT;
constexpr int DOOR_2_LEFT = (int)VehicleAreaDoor::ROW_2_LEFT;
constexpr int DOOR_2_RIGHT = (int)VehicleAreaDoor::ROW_2_RIGHT;
+constexpr int WINDOW_1_LEFT = (int)VehicleAreaWindow::ROW_1_LEFT;
+constexpr int WINDOW_2_LEFT = (int)VehicleAreaWindow::ROW_2_LEFT;
+constexpr int WINDOW_2_RIGHT = (int)VehicleAreaWindow::ROW_2_RIGHT;
constexpr int FAN_DIRECTION_FACE = (int)VehicleHvacFanDirection::FACE;
constexpr int FAN_DIRECTION_FLOOR = (int)VehicleHvacFanDirection::FLOOR;
constexpr int OBD2_LIVE_FRAME = (int)VehicleProperty::OBD2_LIVE_FRAME;
@@ -569,13 +572,20 @@
},
{.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
- .access = VehiclePropertyAccess::READ,
+ .access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
VehicleAreaConfig{.areaId = DOOR_1_RIGHT}}},
.initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
{DOOR_1_RIGHT, {.int32Values = {1}}}}},
+ {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_LEFT | WINDOW_2_LEFT |
+ WINDOW_2_RIGHT}}},
+ .initialAreaValues = {{WINDOW_1_LEFT | WINDOW_2_LEFT | WINDOW_2_RIGHT, {.int32Values = {0}}}}},
+
{.config =
{
.prop = WHEEL_TICK,
@@ -601,12 +611,12 @@
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.configArray = {3}},
- .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON_FULL), 0}}},
+ .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}},
{.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
.access = VehiclePropertyAccess::WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::BOOT_COMPLETE), 0}}},
+ .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}},
{.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
.access = VehiclePropertyAccess::READ_WRITE,
@@ -614,11 +624,6 @@
.areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}},
.initialValue = {.int32Values = {100}}},
- {.config = {.prop = toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC},
- .initialValue = {.int32Values = {toInt(VehicleApPowerBootupReason::USER_POWER_ON)}}},
-
{
.config = {.prop = OBD2_LIVE_FRAME,
.access = VehiclePropertyAccess::READ,
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 58d8867..ba81a52 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -157,12 +157,28 @@
// now, just returns OK; otherwise, hal clients crash with property not supported.
return StatusCode::OK;
case AP_POWER_STATE_REPORT:
- // This property has different behavior between get/set. When it is set, the value
- // goes to the vehicle but is NOT updated in the property store back to Android.
- // Commented out for now, because it may mess up automated testing that use the
- // emulator interface.
- // getEmulatorOrDie()->doSetValueFromClient(propValue);
- return StatusCode::OK;
+ switch (propValue.value.int32Values[0]) {
+ case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
+ case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
+ // CPMS is in WAIT_FOR_VHAL state, simply move to ON
+ doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
+ break;
+ case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
+ // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
+ doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
+ break;
+ case toInt(VehicleApPowerStateReport::ON):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
+ // Do nothing
+ break;
+ default:
+ // Unknown state
+ break;
+ }
+ break;
}
}
@@ -408,6 +424,18 @@
return StatusCode::OK;
}
+VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq(
+ VehicleApPowerStateReq state, int32_t param) {
+ auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
+ req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+ req->areaId = 0;
+ req->timestamp = elapsedRealtimeNano();
+ req->status = VehiclePropertyStatus::AVAILABLE;
+ req->value.int32Values[0] = toInt(state);
+ req->value.int32Values[1] = param;
+ return req;
+}
+
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index ec59690..78895e3 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -67,6 +67,7 @@
StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
void onFakeValueGenerated(const VehiclePropValue& value);
+ VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
int32_t targetDisplay);
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 4d07386..4751a76 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -1125,7 +1125,7 @@
/**
* Property to control power state of application processor
*
- * It is assumed that AP's power state is controller by separate power
+ * It is assumed that AP's power state is controlled by a separate power
* controller.
*
* For configuration information, VehiclePropConfig.configArray can have bit flag combining
@@ -1136,7 +1136,7 @@
* 0 if not used.
*
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
- * @access VEHICLE_PROP_ACCESS_READ
+ * @access VehiclePropertyAccess:READ
*/
AP_POWER_STATE_REQ = (
0x0A00
@@ -1155,7 +1155,7 @@
*
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
- * @access VEHICLE_PROP_ACCESS_WRITE
+ * @access VehiclePropertyAccess:WRITE
*/
AP_POWER_STATE_REPORT = (
0x0A01
@@ -2267,17 +2267,8 @@
};
enum VehicleApPowerStateReq : int32_t {
- /** vehicle HAL will never publish this state to AP */
- OFF = 0,
-
- /** vehicle HAL will never publish this state to AP */
- DEEP_SLEEP = 1,
-
- /** AP is on but display must be off. */
- ON_DISP_OFF = 2,
-
- /** AP is on with display on. This state allows full user interaction. */
- ON_FULL = 3,
+ /** Transition Android from WAIT_FOR_VHAL to ON state */
+ ON = 0,
/**
* The power controller has requested AP to shutdown. AP can either enter
@@ -2287,8 +2278,16 @@
* system.
*
* int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type
+ *
+ * SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states.
*/
- SHUTDOWN_PREPARE = 4,
+ SHUTDOWN_PREPARE = 1,
+
+ /** Cancel the shutdown and transition from SHUTDOWN_PREPARE to WAIT_FOR_VHAL state */
+ CANCEL_SHUTDOWN = 2,
+
+ /** VHAL is finished with shutdown procedures and ready for Android to suspend/shutdown */
+ FINISHED = 3,
};
/**
@@ -2314,26 +2313,30 @@
enum VehicleApPowerStateReport : int32_t {
/**
- * AP has finished boot up, and can start shutdown if requested by power
- * controller.
+ * Device has booted, CarService has initialized and is ready to accept commands from VHAL.
+ * Device starts in WAIT_FOR_VHAL state. The user is not logged in, and vendor apps/services
+ * are expected to control the display and audio.
*/
- BOOT_COMPLETE = 0x1,
+ WAIT_FOR_VHAL = 0x1,
/**
- * AP is entering deep sleep state. How this state is implemented may vary
- * depending on each H/W, but AP's power must be kept in this state.
+ * AP is ready to suspend and has entered WAIT_FOR_FINISHED state.
+ *
+ * int32Values[1]: Time to turn on AP in secs. Power controller may turn on
+ * AP after specified time so that AP can run tasks like
+ * update. If it is set to 0, there is no wake up, and power
+ * controller may not necessarily support wake-up.
*/
DEEP_SLEEP_ENTRY = 0x2,
/**
- * AP is exiting from deep sleep state, and is in
- * VehicleApPowerState#SHUTDOWN_PREPARE state.
- * The power controller may change state to other ON states based on the
- * current state.
+ * AP is exiting from deep sleep state, and is in WAIT_FOR_VHAL state.
*/
DEEP_SLEEP_EXIT = 0x3,
/**
+ * AP remains in SHUTDOWN_PREPARE state as idle and cleanup tasks execute.
+ *
* int32Values[1]: Time to postpone shutdown in ms. Maximum value can be
* 5000 ms.
* If AP needs more time, it will send another POSTPONE
@@ -2342,63 +2345,31 @@
SHUTDOWN_POSTPONE = 0x4,
/**
- * AP is starting shutting down. When system completes shutdown, everything
- * will stop in AP as kernel will stop all other contexts. It is
- * responsibility of vehicle HAL or lower level to synchronize that state
- * with external power controller. As an example, some kind of ping
- * with timeout in power controller can be a solution.
+ * AP is ready to shutdown and has entered WAIT_FOR_FINISHED state.
*
* int32Values[1]: Time to turn on AP in secs. Power controller may turn on
* AP after specified time so that AP can run tasks like
* update. If it is set to 0, there is no wake up, and power
- * controller may not necessarily support wake-up. If power
- * controller turns on AP due to timer, it must start with
- * VehicleApPowerState#ON_DISP_OFF state, and after
- * receiving VehicleApPowerSetState#BOOT_COMPLETE, it shall
- * do state transition to
- * VehicleApPowerState#SHUTDOWN_PREPARE.
+ * controller may not necessarily support wake-up.
*/
SHUTDOWN_START = 0x5,
/**
- * User has requested to turn off headunit's display, which is detected in
- * android side.
- * The power controller may change the power state to
- * VehicleApPowerState#ON_DISP_OFF.
+ * AP has transitioned from WAIT_FOR_VHAL state to ON.
*/
- DISPLAY_OFF = 0x6,
+ ON = 0x6,
/**
- * User has requested to turn on headunit's display, most probably from power
- * key input which is attached to headunit. The power controller may change
- * the power state to VehicleApPowerState#ON_FULL.
+ * AP has transitions to SHUTDOWN_PREPARE state. In this state, Garage Mode will execute idle
+ * tasks, and other services that have registered for this state transition may execute
+ * cleanup activities.
*/
- DISPLAY_ON = 0x7,
-};
-
-/**
- * Enum to represent bootup reason.
- */
-enum VehicleApPowerBootupReason : int32_t {
- /**
- * Power on due to user's pressing of power key or rotating of ignition
- * switch.
- */
- USER_POWER_ON = 0,
+ SHUTDOWN_PREPARE = 0x7,
/**
- * Automatic power on triggered by door unlock or any other kind of automatic
- * user detection.
+ * AP has transitioned from SHUTDOWN_PREPARE state to WAIT_FOR_VHAL.
*/
- USER_UNLOCK = 1,
-
- /**
- * Automatic power on triggered by timer. This only happens when AP has asked
- * wake-up after
- * certain time through time specified in
- * VehicleApPowerSetState#SHUTDOWN_START.
- */
- TIMER = 2,
+ SHUTDOWN_CANCELLED = 0x8,
};
enum VehicleHwKeyInputAction : int32_t {
diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal
index 2628af9..f6827d5 100644
--- a/biometrics/face/1.0/types.hal
+++ b/biometrics/face/1.0/types.hal
@@ -245,9 +245,22 @@
RECALIBRATE = 13,
/**
+ * The face is too different from a previous acquisition. This condition
+ * only applies to enrollment. This can happen if the user passes the
+ * device to someone else in the middle of enrollment.
+ */
+ TOO_DIFFERENT = 14,
+
+ /**
+ * The face is too similar to a previous acquisition. This condition only
+ * applies to enrollment. The user should change their pose.
+ */
+ TOO_SIMILAR = 15,
+
+ /**
* Used to enable a vendor-specific acquisition message.
*/
- VENDOR = 14
+ VENDOR = 16
};
/**
diff --git a/bluetooth/.clang-format b/bluetooth/.clang-format
new file mode 100644
index 0000000..9564994
--- /dev/null
+++ b/bluetooth/.clang-format
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+BasedOnStyle: Google
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+
diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
index a634441..b615227 100644
--- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
+++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
@@ -5,11 +5,3 @@
group bluetooth
writepid /dev/stune/foreground/tasks
-on property:vts.native_server.on=1 && property:ro.build.type=userdebug
- stop vendor.bluetooth-1-0
-on property:vts.native_server.on=1 && property:ro.build.type=eng
- stop vendor.bluetooth-1-0
-on property:vts.native_server.on=0 && property:ro.build.type=userdebug
- start vendor.bluetooth-1-0
-on property:vts.native_server.on=0 && property:ro.build.type=eng
- start vendor.bluetooth-1-0
diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc
index 7c74643..18098ca 100644
--- a/bluetooth/1.0/default/async_fd_watcher.cc
+++ b/bluetooth/1.0/default/async_fd_watcher.cc
@@ -18,13 +18,13 @@
#include "async_fd_watcher.h"
+#include <log/log.h>
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <map>
#include <mutex>
#include <thread>
-#include <log/log.h>
#include <vector>
#include "fcntl.h"
#include "sys/select.h"
@@ -159,11 +159,9 @@
TimeoutCallback saved_cb;
{
std::unique_lock<std::mutex> guard(timeout_mutex_);
- if (timeout_ms_ > std::chrono::milliseconds(0))
- saved_cb = timeout_cb_;
+ if (timeout_ms_ > std::chrono::milliseconds(0)) saved_cb = timeout_cb_;
}
- if (saved_cb != nullptr)
- saved_cb();
+ if (saved_cb != nullptr) saved_cb();
continue;
}
@@ -180,14 +178,14 @@
std::unique_lock<std::mutex> guard(internal_mutex_);
for (auto& it : watched_fds_) {
if (FD_ISSET(it.first, &read_fds)) {
- it.second(it.first);
+ it.second(it.first);
}
}
}
}
}
-} // namespace async
-} // namespace bluetooth
-} // namespace hardware
-} // namespace android
+} // namespace async
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/async_fd_watcher.h b/bluetooth/1.0/default/async_fd_watcher.h
index 358cbc3..b51f921 100644
--- a/bluetooth/1.0/default/async_fd_watcher.h
+++ b/bluetooth/1.0/default/async_fd_watcher.h
@@ -60,8 +60,7 @@
std::chrono::milliseconds timeout_ms_;
};
-
-} // namespace async
-} // namespace bluetooth
-} // namespace hardware
-} // namespace android
+} // namespace async
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/bluetooth_address.h b/bluetooth/1.0/default/bluetooth_address.h
index 94bf616..010a113 100644
--- a/bluetooth/1.0/default/bluetooth_address.h
+++ b/bluetooth/1.0/default/bluetooth_address.h
@@ -54,8 +54,8 @@
static bool get_local_address(uint8_t* addr);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace bluetooth
-} // namespace hardware
-} // namespace android
+} // namespace implementation
+} // namespace V1_0
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/bluetooth_hci.h b/bluetooth/1.0/default/bluetooth_hci.h
index e2797b1..c966990 100644
--- a/bluetooth/1.0/default/bluetooth_hci.h
+++ b/bluetooth/1.0/default/bluetooth_hci.h
@@ -29,8 +29,8 @@
namespace V1_0 {
namespace implementation {
-using ::android::hardware::Return;
using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
class BluetoothDeathRecipient;
diff --git a/bluetooth/1.0/default/bt_vendor_lib.h b/bluetooth/1.0/default/bt_vendor_lib.h
index c140e52..c4035b7 100644
--- a/bluetooth/1.0/default/bt_vendor_lib.h
+++ b/bluetooth/1.0/default/bt_vendor_lib.h
@@ -418,13 +418,12 @@
// DIRECTORIES.
// ONLY USED INSIDE transmit_cb.
// DO NOT USE IN NEW HAL IMPLEMENTATIONS GOING FORWARD
-typedef struct
-{
- uint16_t event;
- uint16_t len;
- uint16_t offset;
- uint16_t layer_specific;
- uint8_t data[];
+typedef struct {
+ uint16_t event;
+ uint16_t len;
+ uint16_t offset;
+ uint16_t layer_specific;
+ uint8_t data[];
} HC_BT_HDR;
// /MODIFICATION
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index df40507..98e3273 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -34,7 +34,8 @@
{const_cast<uint8_t*>(data), length}};
ssize_t ret = 0;
do {
- ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, sizeof(iov) / sizeof(iov[0])));
+ ret =
+ TEMP_FAILURE_RETRY(writev(uart_fd_, iov, sizeof(iov) / sizeof(iov[0])));
} while (-1 == ret && EAGAIN == errno);
if (ret == -1) {
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 71f4328..7cb3a11 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -46,9 +46,7 @@
namespace bluetooth {
namespace hci {
-const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const {
- return packet_;
-}
+const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
switch (state_) {
diff --git a/bluetooth/1.0/default/hci_protocol.cc b/bluetooth/1.0/default/hci_protocol.cc
index bf94dfe..7e88dc4 100644
--- a/bluetooth/1.0/default/hci_protocol.cc
+++ b/bluetooth/1.0/default/hci_protocol.cc
@@ -20,8 +20,8 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
#include <log/log.h>
+#include <unistd.h>
namespace android {
namespace hardware {
diff --git a/bluetooth/1.0/default/service.cpp b/bluetooth/1.0/default/service.cpp
index 3a7aad0..dd3f6a9 100644
--- a/bluetooth/1.0/default/service.cpp
+++ b/bluetooth/1.0/default/service.cpp
@@ -24,9 +24,9 @@
static const size_t kMaxThreads = 5;
// Generated HIDL files
-using android::hardware::bluetooth::V1_0::IBluetoothHci;
using android::hardware::defaultPassthroughServiceImplementation;
+using android::hardware::bluetooth::V1_0::IBluetoothHci;
int main() {
- return defaultPassthroughServiceImplementation<IBluetoothHci>(kMaxThreads);
+ return defaultPassthroughServiceImplementation<IBluetoothHci>(kMaxThreads);
}
diff --git a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
index ee7d8d1..07d8d54 100644
--- a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
+++ b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
@@ -252,13 +252,13 @@
});
// Set a timeout flag in each callback.
- conn_watcher.ConfigureTimeout(
- std::chrono::milliseconds(500),
- [&conn_watcher, &timed_out, &timed_out2]() {
- timed_out = true;
- conn_watcher.ConfigureTimeout(std::chrono::seconds(1),
+ conn_watcher.ConfigureTimeout(std::chrono::milliseconds(500),
+ [&conn_watcher, &timed_out, &timed_out2]() {
+ timed_out = true;
+ conn_watcher.ConfigureTimeout(
+ std::chrono::seconds(1),
[&timed_out2]() { timed_out2 = true; });
- });
+ });
EXPECT_FALSE(timed_out);
EXPECT_FALSE(timed_out2);
sleep(1);
@@ -385,8 +385,8 @@
CleanUpServer();
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace bluetooth
-} // namespace hardware
-} // namespace android
+} // namespace implementation
+} // namespace V1_0
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
index ad08086..ba56c0d 100644
--- a/bluetooth/1.0/default/test/h4_protocol_unittest.cc
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -36,8 +36,8 @@
namespace V1_0 {
namespace implementation {
-using ::testing::Eq;
using hci::H4Protocol;
+using ::testing::Eq;
static char sample_data1[100] = "A point is that which has no part.";
static char sample_data2[100] = "A line is breadthless length.";
diff --git a/bluetooth/1.0/default/test/mct_protocol_unittest.cc b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
index d45058e..60dbc88 100644
--- a/bluetooth/1.0/default/test/mct_protocol_unittest.cc
+++ b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
@@ -36,8 +36,8 @@
namespace V1_0 {
namespace implementation {
-using ::testing::Eq;
using hci::MctProtocol;
+using ::testing::Eq;
static char sample_data1[100] = "A point is that which has no part.";
static char sample_data2[100] = "A line is breadthless length.";
diff --git a/bluetooth/1.0/default/test/properties.cc b/bluetooth/1.0/default/test/properties.cc
index 6ac4fb4..70de01e 100644
--- a/bluetooth/1.0/default/test/properties.cc
+++ b/bluetooth/1.0/default/test/properties.cc
@@ -36,7 +36,7 @@
struct property properties[MAX_PROPERTIES];
// Find the correct entry.
-static int property_find(const char *key) {
+static int property_find(const char* key) {
for (int i = 0; i < num_properties; i++) {
if (strncmp(properties[i].key, key, PROP_KEY_MAX) == 0) {
return i;
@@ -45,7 +45,7 @@
return MAX_PROPERTIES;
}
-int property_set(const char *key, const char *value) {
+int property_set(const char* key, const char* value) {
if (strnlen(value, PROP_VALUE_MAX) > PROP_VALUE_MAX) return -1;
// Check to see if the property exists.
@@ -63,7 +63,7 @@
return 0;
}
-int property_get(const char *key, char *value, const char *default_value) {
+int property_get(const char* key, char* value, const char* default_value) {
// This doesn't mock the behavior of default value
if (default_value != NULL) ALOGE("%s: default_value is ignored!", __func__);
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index a8f5bb4..d56e344 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -35,8 +35,8 @@
namespace {
-using android::hardware::bluetooth::V1_0::implementation::VendorInterface;
using android::hardware::hidl_vec;
+using android::hardware::bluetooth::V1_0::implementation::VendorInterface;
struct {
tINT_CMD_CBACK cb;
@@ -258,8 +258,7 @@
fd_watcher_.WatchFdForNonBlockingReads(
fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
fd_watcher_.WatchFdForNonBlockingReads(
- fd_list[CH_ACL_IN],
- [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+ fd_list[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
hci_ = mct_hci;
}
@@ -295,6 +294,7 @@
lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
lib_interface_->cleanup();
+ lib_interface_ = nullptr;
}
if (lib_handle_ != nullptr) {
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index a401ee6..1d69040 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -40,9 +40,9 @@
PacketReadCallback event_cb, PacketReadCallback acl_cb,
PacketReadCallback sco_cb);
static void Shutdown();
- static VendorInterface *get();
+ static VendorInterface* get();
- size_t Send(uint8_t type, const uint8_t *data, size_t length);
+ size_t Send(uint8_t type, const uint8_t* data, size_t length);
void OnFirmwareConfigured(uint8_t result);
@@ -58,15 +58,15 @@
void HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet);
- void *lib_handle_;
- bt_vendor_interface_t *lib_interface_;
+ void* lib_handle_ = nullptr;
+ bt_vendor_interface_t* lib_interface_ = nullptr;
async::AsyncFdWatcher fd_watcher_;
InitializeCompleteCallback initialize_complete_cb_;
- hci::HciProtocol* hci_;
+ hci::HciProtocol* hci_ = nullptr;
PacketReadCallback event_cb_;
- FirmwareStartupTimer *firmware_startup_timer_;
+ FirmwareStartupTimer* firmware_startup_timer_ = nullptr;
};
} // namespace implementation
diff --git a/bluetooth/1.0/vts/OWNERS b/bluetooth/1.0/vts/OWNERS
new file mode 100644
index 0000000..58d3a66
--- /dev/null
+++ b/bluetooth/1.0/vts/OWNERS
@@ -0,0 +1,8 @@
+zachoverflow@google.com
+siyuanh@google.com
+mylesgw@google.com
+jpawlowski@google.com
+apanicke@google.com
+stng@google.com
+hsz@google.com
+
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
index 439c5fb..90fbb3f 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
@@ -26,15 +26,19 @@
#include <VtsHalHidlTargetCallbackBase.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
-#include <queue>
-using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
-using ::android::hardware::bluetooth::V1_0::Status;
+#include <chrono>
+#include <queue>
+#include <thread>
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::sp;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
+using ::android::hardware::bluetooth::V1_0::Status;
#define HCI_MINIMUM_HCI_VERSION 5 // Bluetooth Core Specification 3.0 + HS
#define HCI_MINIMUM_LMP_VERSION 5 // Bluetooth Core Specification 3.0 + HS
@@ -45,6 +49,7 @@
#define WAIT_FOR_HCI_EVENT_TIMEOUT std::chrono::milliseconds(2000)
#define WAIT_FOR_SCO_DATA_TIMEOUT std::chrono::milliseconds(1000)
#define WAIT_FOR_ACL_DATA_TIMEOUT std::chrono::milliseconds(1000)
+#define INTERFACE_CLOSE_DELAY_MS std::chrono::milliseconds(200)
#define COMMAND_HCI_SHOULD_BE_UNKNOWN \
{ 0xff, 0x3B, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
@@ -157,6 +162,11 @@
ALOGI("%s: getService() for bluetooth is %s", __func__,
bluetooth->isRemote() ? "remote" : "local");
+ bluetooth_hci_death_recipient = new BluetoothHciDeathRecipient();
+ ASSERT_NE(bluetooth_hci_death_recipient, nullptr);
+ ASSERT_TRUE(
+ bluetooth->linkToDeath(bluetooth_hci_death_recipient, 0).isOk());
+
bluetooth_cb = new BluetoothHciCallbacks(*this);
ASSERT_NE(bluetooth_cb, nullptr);
@@ -191,12 +201,14 @@
}
virtual void TearDown() override {
- // Should not be checked in production code
- ASSERT_TRUE(bluetooth->close().isOk());
- handle_no_ops();
- EXPECT_EQ(static_cast<size_t>(0), event_queue.size());
- EXPECT_EQ(static_cast<size_t>(0), sco_queue.size());
- EXPECT_EQ(static_cast<size_t>(0), acl_queue.size());
+ ALOGI("TearDown");
+ // Should not be checked in production code
+ ASSERT_TRUE(bluetooth->close().isOk());
+ std::this_thread::sleep_for(INTERFACE_CLOSE_DELAY_MS);
+ handle_no_ops();
+ EXPECT_EQ(static_cast<size_t>(0), event_queue.size());
+ EXPECT_EQ(static_cast<size_t>(0), sco_queue.size());
+ EXPECT_EQ(static_cast<size_t>(0), acl_queue.size());
}
void setBufferSizes();
@@ -214,6 +226,16 @@
void wait_for_command_complete_event(hidl_vec<uint8_t> cmd);
int wait_for_completed_packets_event(uint16_t handle);
+ class BluetoothHciDeathRecipient : public hidl_death_recipient {
+ public:
+ void serviceDied(
+ uint64_t /*cookie*/,
+ const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/)
+ override {
+ FAIL();
+ }
+ };
+
// A simple test implementation of BluetoothHciCallbacks.
class BluetoothHciCallbacks
: public ::testing::VtsHalHidlTargetCallbackBase<BluetoothHidlTest>,
@@ -260,6 +282,7 @@
sp<IBluetoothHci> bluetooth;
sp<BluetoothHciCallbacks> bluetooth_cb;
+ sp<BluetoothHciDeathRecipient> bluetooth_hci_death_recipient;
std::queue<hidl_vec<uint8_t>> event_queue;
std::queue<hidl_vec<uint8_t>> acl_queue;
std::queue<hidl_vec<uint8_t>> sco_queue;
@@ -292,7 +315,7 @@
if (event_is_no_op) {
event_queue.pop();
} else {
- return;
+ break;
}
}
}
@@ -659,10 +682,11 @@
EXPECT_LT(0, max_sco_data_packet_length);
sendAndCheckSCO(1, max_sco_data_packet_length, sco_connection_handles[0]);
int sco_packets_sent = 1;
- int completed_packets = wait_for_completed_packets_event(sco_connection_handles[0]);
+ int completed_packets =
+ wait_for_completed_packets_event(sco_connection_handles[0]);
if (sco_packets_sent != completed_packets) {
- ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, sco_packets_sent,
- completed_packets);
+ ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+ sco_packets_sent, completed_packets);
}
}
@@ -670,10 +694,11 @@
EXPECT_LT(0, max_acl_data_packet_length);
sendAndCheckACL(1, max_acl_data_packet_length, acl_connection_handles[0]);
int acl_packets_sent = 1;
- int completed_packets = wait_for_completed_packets_event(acl_connection_handles[0]);
+ int completed_packets =
+ wait_for_completed_packets_event(acl_connection_handles[0]);
if (acl_packets_sent != completed_packets) {
- ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, acl_packets_sent,
- completed_packets);
+ ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+ acl_packets_sent, completed_packets);
}
}
}
@@ -695,10 +720,11 @@
sendAndCheckSCO(NUM_SCO_PACKETS_BANDWIDTH, max_sco_data_packet_length,
sco_connection_handles[0]);
int sco_packets_sent = NUM_SCO_PACKETS_BANDWIDTH;
- int completed_packets = wait_for_completed_packets_event(sco_connection_handles[0]);
+ int completed_packets =
+ wait_for_completed_packets_event(sco_connection_handles[0]);
if (sco_packets_sent != completed_packets) {
- ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, sco_packets_sent,
- completed_packets);
+ ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+ sco_packets_sent, completed_packets);
}
}
@@ -707,10 +733,11 @@
sendAndCheckACL(NUM_ACL_PACKETS_BANDWIDTH, max_acl_data_packet_length,
acl_connection_handles[0]);
int acl_packets_sent = NUM_ACL_PACKETS_BANDWIDTH;
- int completed_packets = wait_for_completed_packets_event(acl_connection_handles[0]);
+ int completed_packets =
+ wait_for_completed_packets_event(acl_connection_handles[0]);
if (acl_packets_sent != completed_packets) {
- ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__, acl_packets_sent,
- completed_packets);
+ ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
+ acl_packets_sent, completed_packets);
}
}
}
diff --git a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp
index 2a66abe..9abb88d 100644
--- a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp
+++ b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp
@@ -23,47 +23,52 @@
namespace V1_0 {
namespace implementation {
-IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(const char* /* name */) {
- return new BluetoothAudioOffload();
+IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(
+ const char* /* name */) {
+ return new BluetoothAudioOffload();
}
-// Methods from ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
-Return<::android::hardware::bluetooth::a2dp::V1_0::Status> BluetoothAudioOffload::startSession(
- const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>& hostIf __unused,
- const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration& codecConfig __unused) {
- /**
- * Initialize the audio platform if codecConfiguration is supported.
- * Save the the IBluetoothAudioHost interface, so that it can be used
- * later to send stream control commands to the HAL client, based on
- * interaction with Audio framework.
- */
- return ::android::hardware::bluetooth::a2dp::V1_0::Status::FAILURE;
+// Methods from
+// ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
+Return<::android::hardware::bluetooth::a2dp::V1_0::Status>
+BluetoothAudioOffload::startSession(
+ const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>&
+ hostIf __unused,
+ const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration&
+ codecConfig __unused) {
+ /**
+ * Initialize the audio platform if codecConfiguration is supported.
+ * Save the the IBluetoothAudioHost interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ return ::android::hardware::bluetooth::a2dp::V1_0::Status::FAILURE;
}
Return<void> BluetoothAudioOffload::streamStarted(
::android::hardware::bluetooth::a2dp::V1_0::Status status __unused) {
- /**
- * Streaming on control path has started,
- * HAL server should start the streaming on data path.
- */
- return Void();
+ /**
+ * Streaming on control path has started,
+ * HAL server should start the streaming on data path.
+ */
+ return Void();
}
Return<void> BluetoothAudioOffload::streamSuspended(
::android::hardware::bluetooth::a2dp::V1_0::Status status __unused) {
- /**
- * Streaming on control path has suspend,
- * HAL server should suspend the streaming on data path.
- */
- return Void();
+ /**
+ * Streaming on control path has suspend,
+ * HAL server should suspend the streaming on data path.
+ */
+ return Void();
}
Return<void> BluetoothAudioOffload::endSession() {
- /**
- * Cleanup the audio platform as remote A2DP Sink device is no
- * longer active
- */
- return Void();
+ /**
+ * Cleanup the audio platform as remote A2DP Sink device is no
+ * longer active
+ */
+ return Void();
}
} // namespace implementation
diff --git a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h
index 5d07b5b..16a83c2 100644
--- a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h
+++ b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h
@@ -28,27 +28,32 @@
namespace V1_0 {
namespace implementation {
+using ::android::sp;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::sp;
struct BluetoothAudioOffload : public IBluetoothAudioOffload {
- BluetoothAudioOffload() {}
- // Methods from ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
- Return<::android::hardware::bluetooth::a2dp::V1_0::Status> startSession(
- const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>& hostIf,
- const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration& codecConfig) override;
- Return<void> streamStarted(::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
- Return<void> streamSuspended(
- ::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
- Return<void> endSession() override;
+ BluetoothAudioOffload() {}
+ // Methods from
+ // ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
+ Return<::android::hardware::bluetooth::a2dp::V1_0::Status> startSession(
+ const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>&
+ hostIf,
+ const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration&
+ codecConfig) override;
+ Return<void> streamStarted(
+ ::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
+ Return<void> streamSuspended(
+ ::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
+ Return<void> endSession() override;
};
-extern "C" IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(const char* name);
+extern "C" IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(
+ const char* name);
} // namespace implementation
} // namespace V1_0
diff --git a/bluetooth/a2dp/1.0/vts/OWNERS b/bluetooth/a2dp/1.0/vts/OWNERS
new file mode 100644
index 0000000..58d3a66
--- /dev/null
+++ b/bluetooth/a2dp/1.0/vts/OWNERS
@@ -0,0 +1,8 @@
+zachoverflow@google.com
+siyuanh@google.com
+mylesgw@google.com
+jpawlowski@google.com
+apanicke@google.com
+stng@google.com
+hsz@google.com
+
diff --git a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp b/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp
index 1a0342f..d8d0c29 100644
--- a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp
+++ b/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp
@@ -26,85 +26,92 @@
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
-using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
-using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
-using ::android::hardware::bluetooth::a2dp::V1_0::Status;
-using ::android::hardware::bluetooth::a2dp::V1_0::CodecType;
-using ::android::hardware::bluetooth::a2dp::V1_0::SampleRate;
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
using ::android::hardware::bluetooth::a2dp::V1_0::BitsPerSample;
using ::android::hardware::bluetooth::a2dp::V1_0::ChannelMode;
using ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
+using ::android::hardware::bluetooth::a2dp::V1_0::CodecType;
+using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
+using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
+using ::android::hardware::bluetooth::a2dp::V1_0::SampleRate;
+using ::android::hardware::bluetooth::a2dp::V1_0::Status;
// Test environment for Bluetooth HIDL A2DP HAL.
-class BluetoothA2dpHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static BluetoothA2dpHidlEnvironment* Instance() {
- static BluetoothA2dpHidlEnvironment* instance = new BluetoothA2dpHidlEnvironment;
- return instance;
- }
+class BluetoothA2dpHidlEnvironment
+ : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static BluetoothA2dpHidlEnvironment* Instance() {
+ static BluetoothA2dpHidlEnvironment* instance =
+ new BluetoothA2dpHidlEnvironment;
+ return instance;
+ }
- virtual void registerTestServices() override { registerTestService<IBluetoothAudioOffload>(); }
+ virtual void registerTestServices() override {
+ registerTestService<IBluetoothAudioOffload>();
+ }
- private:
- BluetoothA2dpHidlEnvironment() {}
+ private:
+ BluetoothA2dpHidlEnvironment() {}
};
// The main test class for Bluetooth A2DP HIDL HAL.
class BluetoothA2dpHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ // currently test passthrough mode only
+ audio_offload =
+ ::testing::VtsHalHidlTargetTestBase::getService<IBluetoothAudioOffload>(
+ BluetoothA2dpHidlEnvironment::Instance()
+ ->getServiceName<IBluetoothAudioOffload>());
+ ASSERT_NE(audio_offload, nullptr);
+
+ audio_host = new BluetoothAudioHost(*this);
+ ASSERT_NE(audio_host, nullptr);
+
+ codec.codecType = CodecType::AAC;
+ codec.sampleRate = SampleRate::RATE_44100;
+ codec.bitsPerSample = BitsPerSample::BITS_16;
+ codec.channelMode = ChannelMode::STEREO;
+ codec.encodedAudioBitrate = 320000;
+ codec.peerMtu = 1000;
+ }
+
+ virtual void TearDown() override {}
+
+ // A simple test implementation of IBluetoothAudioHost.
+ class BluetoothAudioHost
+ : public ::testing::VtsHalHidlTargetCallbackBase<BluetoothA2dpHidlTest>,
+ public IBluetoothAudioHost {
+ BluetoothA2dpHidlTest& parent_;
+
public:
- virtual void SetUp() override {
- // currently test passthrough mode only
- audio_offload = ::testing::VtsHalHidlTargetTestBase::getService<IBluetoothAudioOffload>(
- BluetoothA2dpHidlEnvironment::Instance()->getServiceName<IBluetoothAudioOffload>());
- ASSERT_NE(audio_offload, nullptr);
+ BluetoothAudioHost(BluetoothA2dpHidlTest& parent) : parent_(parent){};
+ virtual ~BluetoothAudioHost() = default;
- audio_host = new BluetoothAudioHost(*this);
- ASSERT_NE(audio_host, nullptr);
-
- codec.codecType = CodecType::AAC;
- codec.sampleRate = SampleRate::RATE_44100;
- codec.bitsPerSample = BitsPerSample::BITS_16;
- codec.channelMode = ChannelMode::STEREO;
- codec.encodedAudioBitrate = 320000;
- codec.peerMtu = 1000;
- }
-
- virtual void TearDown() override {}
-
- // A simple test implementation of IBluetoothAudioHost.
- class BluetoothAudioHost
- : public ::testing::VtsHalHidlTargetCallbackBase<BluetoothA2dpHidlTest>,
- public IBluetoothAudioHost {
- BluetoothA2dpHidlTest& parent_;
-
- public:
- BluetoothAudioHost(BluetoothA2dpHidlTest& parent) : parent_(parent){};
- virtual ~BluetoothAudioHost() = default;
-
- Return<void> startStream() override {
- parent_.audio_offload->streamStarted(Status::SUCCESS);
- return Void();
- };
-
- Return<void> suspendStream() override {
- parent_.audio_offload->streamSuspended(Status::SUCCESS);
- return Void();
- };
-
- Return<void> stopStream() override { return Void(); };
+ Return<void> startStream() override {
+ parent_.audio_offload->streamStarted(Status::SUCCESS);
+ return Void();
};
- // audio_host is for the Audio HAL to send stream start/suspend/stop commands to Bluetooth
- sp<IBluetoothAudioHost> audio_host;
- // audio_offload is for the Bluetooth HAL to report session started/ended and handled audio
- // stream started/suspended
- sp<IBluetoothAudioOffload> audio_offload;
- // codec is the currently used codec
- CodecConfiguration codec;
+ Return<void> suspendStream() override {
+ parent_.audio_offload->streamSuspended(Status::SUCCESS);
+ return Void();
+ };
+
+ Return<void> stopStream() override { return Void(); };
+ };
+
+ // audio_host is for the Audio HAL to send stream start/suspend/stop commands
+ // to Bluetooth
+ sp<IBluetoothAudioHost> audio_host;
+ // audio_offload is for the Bluetooth HAL to report session started/ended and
+ // handled audio stream started/suspended
+ sp<IBluetoothAudioOffload> audio_offload;
+ // codec is the currently used codec
+ CodecConfiguration codec;
};
// Empty test: Initialize()/Close() are called in SetUp()/TearDown().
@@ -112,15 +119,15 @@
// Test start and end session
TEST_F(BluetoothA2dpHidlTest, StartAndEndSession) {
- EXPECT_EQ(Status::SUCCESS, audio_offload->startSession(audio_host, codec));
- audio_offload->endSession();
+ EXPECT_EQ(Status::SUCCESS, audio_offload->startSession(audio_host, codec));
+ audio_offload->endSession();
}
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(BluetoothA2dpHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- BluetoothA2dpHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
+ ::testing::AddGlobalTestEnvironment(BluetoothA2dpHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ BluetoothA2dpHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
}
diff --git a/boot/1.0/default/Android.mk b/boot/1.0/default/Android.mk
new file mode 100644
index 0000000..7ccc4c8
--- /dev/null
+++ b/boot/1.0/default/Android.mk
@@ -0,0 +1,30 @@
+# TODO(connoro): Remove this file once we eliminate existing usage of
+# PRODUCT_STATIC_BOOT_CONTROL_HAL
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(strip $(PRODUCT_STATIC_BOOT_CONTROL_HAL)),)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.hardware.boot@1.0-impl-wrapper.recovery
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MULTILIB := first
+ifeq ($(TARGET_IS_64_BIT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib64/hw
+else
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib/hw
+endif
+LOCAL_SRC_FILES := BootControl.cpp
+LOCAL_CFLAGS := -DBOOT_CONTROL_RECOVERY
+LOCAL_SHARED_LIBRARIES := \
+ libbase.recovery \
+ liblog.recovery \
+ libhidlbase.recovery \
+ libhidltransport.recovery \
+ libhardware.recovery \
+ libutils.recovery \
+ android.hardware.boot@1.0.recovery
+LOCAL_STATIC_LIBRARIES := $(PRODUCT_STATIC_BOOT_CONTROL_HAL)
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/boot/1.0/default/BootControl.cpp b/boot/1.0/default/BootControl.cpp
index 9a90076..e36407f 100644
--- a/boot/1.0/default/BootControl.cpp
+++ b/boot/1.0/default/BootControl.cpp
@@ -21,6 +21,10 @@
#include <hardware/boot_control.h>
#include "BootControl.h"
+#ifdef BOOT_CONTROL_RECOVERY
+extern const hw_module_t HAL_MODULE_INFO_SYM;
+#endif
+
namespace android {
namespace hardware {
namespace boot {
@@ -92,7 +96,23 @@
return Void();
}
+#ifdef BOOT_CONTROL_RECOVERY
+IBootControl* HIDL_FETCH_IBootControl(const char * /* hal */) {
+ boot_control_module_t* module;
+ // For devices that don't build a standalone libhardware bootctrl impl for recovery,
+ // we simulate the hw_get_module() by accessing it from the current process directly.
+ const hw_module_t* hw_module = &HAL_MODULE_INFO_SYM;
+ if (!hw_module ||
+ strcmp(BOOT_CONTROL_HARDWARE_MODULE_ID, hw_module->id) != 0) {
+ ALOGE("Error loading boot_control HAL implementation: %d.", -EINVAL);
+ return nullptr;
+ }
+ module = reinterpret_cast<boot_control_module_t*>(const_cast<hw_module_t*>(hw_module));
+ module->init(module);
+ return new BootControl(module);
+}
+#else
IBootControl* HIDL_FETCH_IBootControl(const char* /* hal */) {
int ret = 0;
boot_control_module_t* module = NULL;
@@ -106,7 +126,7 @@
module->init(module);
return new BootControl(module);
}
-
+#endif
} // namespace implementation
} // namespace V1_0
} // namespace boot
diff --git a/broadcastradio/common/utils2x/Android.bp b/broadcastradio/common/utils2x/Android.bp
index aab94f2..df2cefe 100644
--- a/broadcastradio/common/utils2x/Android.bp
+++ b/broadcastradio/common/utils2x/Android.bp
@@ -22,6 +22,7 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-Wno-error=implicit-fallthrough",
],
cppflags: [
"-std=c++1z",
diff --git a/broadcastradio/common/utils2x/Utils.cpp b/broadcastradio/common/utils2x/Utils.cpp
index 3e20b35..f292c08 100644
--- a/broadcastradio/common/utils2x/Utils.cpp
+++ b/broadcastradio/common/utils2x/Utils.cpp
@@ -215,7 +215,7 @@
break;
case IdentifierType::DAB_FREQUENCY:
expect(val > 100000u, "f > 100MHz");
- // fallthrough
+ [[fallthrough]];
case IdentifierType::AMFM_FREQUENCY:
case IdentifierType::DRMO_FREQUENCY:
expect(val > 100u, "f > 100kHz");
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index 392ebbc..9c2b02b 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -466,8 +466,8 @@
}
void CameraModule::removeCamera(int cameraId) {
- free_camera_metadata(
- const_cast<camera_metadata_t*>(mCameraInfoMap[cameraId].static_camera_characteristics));
+ free_camera_metadata(const_cast<camera_metadata_t*>(
+ mCameraInfoMap.valueFor(cameraId).static_camera_characteristics));
mCameraInfoMap.removeItem(cameraId);
mDeviceVersionMap.removeItem(cameraId);
}
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 5824be0..4ef5fc9 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -1838,7 +1838,11 @@
// TODO: see if we can save some computation by converting to YV12 here
uint8_t* inData;
size_t inDataSize;
- req->frameIn->map(&inData, &inDataSize);
+ if (req->frameIn->map(&inData, &inDataSize) != 0) {
+ lk.unlock();
+ return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+ }
+
// TODO: in some special case maybe we can decode jpg directly to gralloc output?
ATRACE_BEGIN("MJPGtoI420");
res = libyuv::MJPGToI420(
@@ -2187,6 +2191,7 @@
ALOGI("%s: BLOB format does not support dataSpace %x", __FUNCTION__, ds);
return false;
}
+ break;
case PixelFormat::IMPLEMENTATION_DEFINED:
case PixelFormat::YCBCR_420_888:
case PixelFormat::YV12:
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
index 67b4e44..cef0397 100644
--- a/camera/metadata/3.2/types.hal
+++ b/camera/metadata/3.2/types.hal
@@ -1396,7 +1396,8 @@
*
* <p>The arrangement of color filters on sensor;
* represents the colors in the top-left 2x2 section of
- * the sensor, in reading order.</p>
+ * the sensor, in reading order, for a Bayer camera, or the
+ * light spectrum it captures for MONOCHROME camera.</p>
*/
ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index a37e132..d21bb7c 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -100,7 +100,7 @@
/** android.request.availablePhysicalCameraRequestKeys [static, int32[], hidden]
*
- * <p>A subset of the available request keys that can be overriden for
+ * <p>A subset of the available request keys that can be overridden for
* physical devices backing a logical multi-camera.</p>
*/
ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS,
diff --git a/camera/metadata/3.4/types.hal b/camera/metadata/3.4/types.hal
index b228de8..4eb6929 100644
--- a/camera/metadata/3.4/types.hal
+++ b/camera/metadata/3.4/types.hal
@@ -44,6 +44,21 @@
ANDROID_REQUEST_END_3_4,
+ /** android.scaler.availableRecommendedStreamConfigurations [static, enum[], ndk_public]
+ *
+ * <p>Recommended stream configurations for common client use cases.</p>
+ */
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_SCALER_END,
+
+ /** android.scaler.availableRecommendedInputOutputFormatsMap [static, int32, ndk_public]
+ *
+ * <p>Recommended mappings of image formats that are supported by this
+ * camera device for input streams, to their corresponding output formats.</p>
+ */
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP,
+
+ ANDROID_SCALER_END_3_4,
+
/** android.info.supportedBufferManagementVersion [static, enum, system]
*
* <p>The version of buffer management API this camera device supports and opts into.</p>
@@ -52,12 +67,52 @@
ANDROID_INFO_END_3_4,
+ /** android.depth.availableRecommendedDepthStreamConfigurations [static, int32[], ndk_public]
+ *
+ * <p>Recommended depth stream configurations for common client use cases.</p>
+ */
+ ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_DEPTH_END,
+
+ ANDROID_DEPTH_END_3_4,
+
};
/*
* Enumeration definitions for the various entries that need them
*/
+/** android.scaler.availableFormats enumeration values added since v3.2
+ * @see ANDROID_SCALER_AVAILABLE_FORMATS
+ */
+enum CameraMetadataEnumAndroidScalerAvailableFormats :
+ @3.2::CameraMetadataEnumAndroidScalerAvailableFormats {
+ ANDROID_SCALER_AVAILABLE_FORMATS_RAW10 = 0x25,
+ ANDROID_SCALER_AVAILABLE_FORMATS_RAW12 = 0x26,
+ ANDROID_SCALER_AVAILABLE_FORMATS_Y8 = 0x20203859,
+};
+
+/** android.scaler.availableRecommendedStreamConfigurations enumeration values
+ * @see ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
+ */
+enum CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations : uint32_t {
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW
+ = 0x0,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RECORD
+ = 0x1,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VIDEO_SNAPSHOT
+ = 0x2,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_SNAPSHOT
+ = 0x3,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_ZSL
+ = 0x4,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RAW
+ = 0x5,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END
+ = 0x6,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START
+ = 0x18,
+};
+
/** android.info.supportedBufferManagementVersion enumeration values
* @see ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION
*/
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 94d06e8..c324d59 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -142,6 +142,11 @@
int32_t outputFormat;
};
+enum ReprocessType {
+ PRIV_REPROCESS,
+ YUV_REPROCESS,
+};
+
namespace {
// "device@<version>/legacy/<id>"
const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
@@ -559,7 +564,8 @@
};
struct DeviceCb : public V3_4::ICameraDeviceCallback {
- DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+ DeviceCb(CameraHidlTest *parent, bool checkMonochromeResult) : mParent(parent),
+ mCheckMonochromeResult(checkMonochromeResult) {}
Return<void> processCaptureResult_3_4(
const hidl_vec<V3_4::CaptureResult>& results) override;
Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
@@ -569,6 +575,7 @@
bool processCaptureResultLocked(const CaptureResult& results);
CameraHidlTest *mParent; // Parent object
+ bool mCheckMonochromeResult;
};
struct TorchProviderCb : public ICameraProviderCallback {
@@ -681,6 +688,10 @@
const CameraMetadata& chars, int deviceVersion,
const hidl_vec<hidl_string>& deviceNames);
void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
+ void verifyRecommendedConfigs(const CameraMetadata& metadata);
+ void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
+ void verifyMonochromeCameraResult(
+ const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata);
static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
@@ -698,7 +709,8 @@
/*out*/);
static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
AvailableStream &hfrStream);
- static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
+ static Status isZSLModeAvailable(const camera_metadata_t *staticMeta);
+ static Status isZSLModeAvailable(const camera_metadata_t *staticMeta, ReprocessType reprocType);
static Status getZSLInputOutputMap(camera_metadata_t *staticMeta,
std::vector<AvailableZSLInputOutput> &inputOutputMap);
static Status findLargestSize(
@@ -706,6 +718,7 @@
int32_t format, AvailableStream &result);
static Status isAutoFocusModeAvailable(
CameraParameters &cameraParams, const char *mode) ;
+ static Status isMonochromeCamera(const camera_metadata_t *staticMeta);
protected:
@@ -1049,6 +1062,11 @@
}
request->haveResultMetadata = true;
request->collectedResult.sort();
+
+ // Verify final result metadata
+ if (mCheckMonochromeResult) {
+ mParent->verifyMonochromeCameraResult(request->collectedResult);
+ }
}
uint32_t numBuffersReturned = results.outputBuffers.size();
@@ -2079,7 +2097,8 @@
ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
verifyCameraCharacteristics(status, chars);
-
+ verifyMonochromeCharacteristics(chars, deviceVersion);
+ verifyRecommendedConfigs(chars);
verifyLogicalCameraMetadata(name, device3_x, chars, deviceVersion,
cameraDeviceNames);
});
@@ -2776,13 +2795,34 @@
ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap));
ASSERT_NE(0u, inputOutputMap.size());
+ bool supportMonoY8 = false;
+ if (Status::OK == isMonochromeCamera(staticMeta)) {
+ for (auto& it : inputStreams) {
+ if (it.format == static_cast<uint32_t>(PixelFormat::Y8)) {
+ supportMonoY8 = true;
+ break;
+ }
+ }
+ }
+
int32_t streamId = 0;
+ bool hasPrivToY8 = false, hasY8ToY8 = false, hasY8ToBlob = false;
for (auto& inputIter : inputOutputMap) {
AvailableStream input;
ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat,
input));
ASSERT_NE(0u, inputStreams.size());
+ if (inputIter.inputFormat == static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED)
+ && inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+ hasPrivToY8 = true;
+ } else if (inputIter.inputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+ if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::BLOB)) {
+ hasY8ToBlob = true;
+ } else if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+ hasY8ToY8 = true;
+ }
+ }
AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
inputIter.outputFormat};
std::vector<AvailableStream> outputStreams;
@@ -2844,6 +2884,16 @@
}
}
+ if (supportMonoY8) {
+ if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) {
+ ASSERT_TRUE(hasPrivToY8);
+ }
+ if (Status::OK == isZSLModeAvailable(staticMeta, YUV_REPROCESS)) {
+ ASSERT_TRUE(hasY8ToY8);
+ ASSERT_TRUE(hasY8ToBlob);
+ }
+ }
+
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
@@ -4323,7 +4373,17 @@
// Check whether ZSL is available using the static camera
// characteristics.
-Status CameraHidlTest::isZSLModeAvailable(camera_metadata_t *staticMeta) {
+Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta) {
+ if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) {
+ return Status::OK;
+ } else {
+ return isZSLModeAvailable(staticMeta, YUV_REPROCESS);
+ }
+}
+
+Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta,
+ ReprocessType reprocType) {
+
Status ret = Status::METHOD_NOT_SUPPORTED;
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
@@ -4337,10 +4397,34 @@
}
for (size_t i = 0; i < entry.count; i++) {
- if ((ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
- entry.data.u8[i]) ||
- (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING ==
- entry.data.u8[i]) ){
+ if ((reprocType == PRIV_REPROCESS &&
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING == entry.data.u8[i]) ||
+ (reprocType == YUV_REPROCESS &&
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING == entry.data.u8[i])) {
+ ret = Status::OK;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+// Check whether this is a monochrome camera using the static camera characteristics.
+Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) {
+ Status ret = Status::METHOD_NOT_SUPPORTED;
+ if (nullptr == staticMeta) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ if (0 != rc) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ for (size_t i = 0; i < entry.count; i++) {
+ if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME == entry.data.u8[i]) {
ret = Status::OK;
break;
}
@@ -4459,22 +4543,6 @@
});
ASSERT_TRUE(ret.isOk());
- sp<DeviceCb> cb = new DeviceCb(this);
- 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());
-
- sp<device::V3_3::ICameraDeviceSession> session3_3;
- castSession(session, deviceVersion, &session3_3, session3_4);
- ASSERT_NE(nullptr, session3_4);
-
camera_metadata_t *staticMeta;
ret = device3_x->getCameraCharacteristics([&] (Status s,
CameraMetadata metadata) {
@@ -4493,6 +4561,24 @@
*supportsPartialResults = (*partialResultCount > 1);
}
+ bool checkMonochromeResultTags = Status::OK == isMonochromeCamera(staticMeta) &&
+ deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5;
+ sp<DeviceCb> cb = new DeviceCb(this, checkMonochromeResultTags);
+ 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());
+
+ sp<device::V3_3::ICameraDeviceSession> session3_3;
+ castSession(session, deviceVersion, &session3_3, session3_4);
+ ASSERT_NE(nullptr, session3_4);
+
outputPreviewStreams.clear();
auto rc = getAvailableOutputStreams(staticMeta,
outputPreviewStreams, previewThreshold);
@@ -4562,21 +4648,6 @@
});
ASSERT_TRUE(ret.isOk());
- sp<DeviceCb> cb = new DeviceCb(this);
- ret = device3_x->open(
- cb,
- [&](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());
-
- sp<device::V3_3::ICameraDeviceSession> session3_3;
- sp<device::V3_4::ICameraDeviceSession> session3_4;
- castSession(*session, deviceVersion, &session3_3, &session3_4);
-
camera_metadata_t *staticMeta;
ret = device3_x->getCameraCharacteristics([&] (Status s,
CameraMetadata metadata) {
@@ -4595,6 +4666,23 @@
*supportsPartialResults = (*partialResultCount > 1);
}
+ bool checkMonochromeResultTags = Status::OK == isMonochromeCamera(staticMeta) &&
+ deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5;
+ sp<DeviceCb> cb = new DeviceCb(this, checkMonochromeResultTags);
+ ret = device3_x->open(
+ cb,
+ [&](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());
+
+ sp<device::V3_3::ICameraDeviceSession> session3_3;
+ sp<device::V3_4::ICameraDeviceSession> session3_4;
+ castSession(*session, deviceVersion, &session3_3, &session3_4);
+
outputPreviewStreams.clear();
auto rc = getAvailableOutputStreams(staticMeta,
outputPreviewStreams, previewThreshold);
@@ -4722,6 +4810,7 @@
Return<void> ret = device3_5->getPhysicalCameraCharacteristics(physicalId,
[&](auto status, const auto& chars) {
verifyCameraCharacteristics(status, chars);
+ verifyMonochromeCharacteristics(chars, deviceVersion);
});
ASSERT_TRUE(ret.isOk());
@@ -4773,6 +4862,149 @@
}
}
+void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
+ int deviceVersion) {
+ const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
+ Status rc = isMonochromeCamera(metadata);
+ if (Status::METHOD_NOT_SUPPORTED == rc) {
+ return;
+ }
+ ASSERT_EQ(Status::OK, rc);
+
+ camera_metadata_ro_entry entry;
+ // Check capabilities
+ int retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ ASSERT_EQ(std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING),
+ entry.data.u8 + entry.count);
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_5) {
+ ASSERT_EQ(std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW),
+ entry.data.u8 + entry.count);
+ }
+ }
+
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) {
+ // Check Cfa
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, &entry);
+ if ((0 == retcode) && (entry.count == 1)) {
+ ASSERT_TRUE(entry.data.i32[0] == ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO
+ || entry.data.i32[0] == ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR);
+ }
+
+ // Check availableRequestKeys
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ for (size_t i = 0; i < entry.count; i++) {
+ ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE);
+ ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM);
+ ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS);
+ }
+ } else {
+ ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+ }
+
+ // Check availableResultKeys
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ for (size_t i = 0; i < entry.count; i++) {
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_GREEN_SPLIT);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
+ ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE);
+ ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM);
+ ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS);
+ }
+ } else {
+ ADD_FAILURE() << "Get camera availableResultKeys failed!";
+ }
+
+ // Check availableCharacteristicKeys
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ for (size_t i = 0; i < entry.count; i++) {
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM1);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM2);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX1);
+ ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX2);
+ }
+ } else {
+ ADD_FAILURE() << "Get camera availableResultKeys failed!";
+ }
+
+ // Check blackLevelPattern
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SENSOR_BLACK_LEVEL_PATTERN, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ ASSERT_EQ(entry.count, 4);
+ for (size_t i = 1; i < entry.count; i++) {
+ ASSERT_EQ(entry.data.i32[i], entry.data.i32[0]);
+ }
+ }
+ }
+}
+
+void CameraHidlTest::verifyMonochromeCameraResult(
+ const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata) {
+ camera_metadata_ro_entry entry;
+
+ // Check tags that are not applicable for monochrome camera
+ ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_GREEN_SPLIT));
+ ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_NEUTRAL_COLOR_POINT));
+ ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_MODE));
+ ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_TRANSFORM));
+ ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_GAINS));
+
+ // Check dynamicBlackLevel
+ entry = metadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+ if (entry.count > 0) {
+ ASSERT_EQ(entry.count, 4);
+ for (size_t i = 1; i < entry.count; i++) {
+ ASSERT_FLOAT_EQ(entry.data.f[i], entry.data.f[0]);
+ }
+ }
+
+ // Check noiseProfile
+ entry = metadata.find(ANDROID_SENSOR_NOISE_PROFILE);
+ if (entry.count > 0) {
+ ASSERT_EQ(entry.count, 2);
+ }
+
+ // Check lensShadingMap
+ entry = metadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+ if (entry.count > 0) {
+ ASSERT_EQ(entry.count % 4, 0);
+ for (size_t i = 0; i < entry.count/4; i++) {
+ ASSERT_FLOAT_EQ(entry.data.f[i*4+1], entry.data.f[i*4]);
+ ASSERT_FLOAT_EQ(entry.data.f[i*4+2], entry.data.f[i*4]);
+ ASSERT_FLOAT_EQ(entry.data.f[i*4+3], entry.data.f[i*4]);
+ }
+ }
+
+ // Check tonemapCurve
+ camera_metadata_ro_entry curveRed = metadata.find(ANDROID_TONEMAP_CURVE_RED);
+ camera_metadata_ro_entry curveGreen = metadata.find(ANDROID_TONEMAP_CURVE_GREEN);
+ camera_metadata_ro_entry curveBlue = metadata.find(ANDROID_TONEMAP_CURVE_BLUE);
+ if (curveRed.count > 0 && curveGreen.count > 0 && curveBlue.count > 0) {
+ ASSERT_EQ(curveRed.count, curveGreen.count);
+ ASSERT_EQ(curveRed.count, curveBlue.count);
+ for (size_t i = 0; i < curveRed.count; i++) {
+ ASSERT_FLOAT_EQ(curveGreen.data.f[i], curveRed.data.f[i]);
+ ASSERT_FLOAT_EQ(curveBlue.data.f[i], curveRed.data.f[i]);
+ }
+ }
+}
+
+
// Open a device session with empty callbacks and return static metadata.
void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
sp<ICameraProvider> provider,
@@ -4978,6 +5210,94 @@
ASSERT_TRUE(ret.isOk());
}
+void CameraHidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) {
+ size_t CONFIG_ENTRY_SIZE = 5;
+ 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;
+ uint32_t vendorUsecaseStart =
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START;
+ uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1;
+ usecaseMask &= ~((1 << maxPublicUsecase) - 1);
+
+ const camera_metadata_t* metadata = reinterpret_cast<const camera_metadata_t*> (chars.data());
+
+ camera_metadata_ro_entry recommendedConfigsEntry, recommendedDepthConfigsEntry, ioMapEntry;
+ recommendedConfigsEntry.count = recommendedDepthConfigsEntry.count = ioMapEntry.count = 0;
+ int retCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS, &recommendedConfigsEntry);
+ int depthRetCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS,
+ &recommendedDepthConfigsEntry);
+ int ioRetCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP, &ioMapEntry);
+ if ((0 != retCode) && (0 != depthRetCode)) {
+ //In case both regular and depth recommended configurations are absent,
+ //I/O should be absent as well.
+ ASSERT_NE(ioRetCode, 0);
+ return;
+ }
+
+ camera_metadata_ro_entry availableKeysEntry;
+ retCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &availableKeysEntry);
+ ASSERT_TRUE((0 == retCode) && (availableKeysEntry.count > 0));
+ std::vector<int32_t> availableKeys;
+ availableKeys.reserve(availableKeysEntry.count);
+ availableKeys.insert(availableKeys.end(), availableKeysEntry.data.i32,
+ availableKeysEntry.data.i32 + availableKeysEntry.count);
+
+ if (recommendedConfigsEntry.count > 0) {
+ ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS),
+ availableKeys.end());
+ ASSERT_EQ((recommendedConfigsEntry.count % CONFIG_ENTRY_SIZE), 0);
+ for (size_t i = 0; i < recommendedConfigsEntry.count; i += CONFIG_ENTRY_SIZE) {
+ int32_t entryType =
+ recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET];
+ uint32_t bitfield =
+ recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET];
+ ASSERT_TRUE((entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) ||
+ (entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT));
+ ASSERT_TRUE((bitfield & usecaseMask) == 0);
+ }
+ }
+
+ if (recommendedDepthConfigsEntry.count > 0) {
+ ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+ ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS),
+ availableKeys.end());
+ ASSERT_EQ((recommendedDepthConfigsEntry.count % CONFIG_ENTRY_SIZE), 0);
+ for (size_t i = 0; i < recommendedDepthConfigsEntry.count; i += CONFIG_ENTRY_SIZE) {
+ int32_t entryType =
+ recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET];
+ uint32_t bitfield =
+ recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET];
+ ASSERT_TRUE((entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) ||
+ (entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT));
+ ASSERT_TRUE((bitfield & usecaseMask) == 0);
+ }
+
+ if (recommendedConfigsEntry.count == 0) {
+ //In case regular recommended configurations are absent but suggested depth
+ //configurations are present, I/O should be absent.
+ ASSERT_NE(ioRetCode, 0);
+ }
+ }
+
+ if ((ioRetCode == 0) && (ioMapEntry.count > 0)) {
+ ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP),
+ availableKeys.end());
+ ASSERT_EQ(isZSLModeAvailable(metadata), Status::OK);
+ }
+}
+
int main(int argc, char **argv) {
::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
new file mode 100644
index 0000000..49674e3
--- /dev/null
+++ b/compatibility_matrices/Android.bp
@@ -0,0 +1,77 @@
+// Copyright (C) 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.
+
+vintf_compatibility_matrix {
+ name: "framework_compatibility_matrix.legacy.xml",
+ stem: "compatibility_matrix.legacy.xml",
+ srcs: [
+ "compatibility_matrix.legacy.xml",
+ ],
+ kernel_configs: [
+ // legacy uses O kernel requirements
+ "kernel_config_o_3.18",
+ "kernel_config_o_4.4",
+ "kernel_config_o_4.9",
+ ]
+}
+vintf_compatibility_matrix {
+ name: "framework_compatibility_matrix.1.xml",
+ stem: "compatibility_matrix.1.xml",
+ srcs: [
+ "compatibility_matrix.1.xml",
+ ],
+ kernel_configs: [
+ "kernel_config_o_3.18",
+ "kernel_config_o_4.4",
+ "kernel_config_o_4.9",
+ ]
+}
+vintf_compatibility_matrix {
+ name: "framework_compatibility_matrix.2.xml",
+ stem: "compatibility_matrix.2.xml",
+ srcs: [
+ "compatibility_matrix.2.xml",
+ ],
+ kernel_configs: [
+ "kernel_config_o_mr1_3.18",
+ "kernel_config_o_mr1_4.4",
+ "kernel_config_o_mr1_4.9",
+ ]
+}
+
+vintf_compatibility_matrix {
+ name: "framework_compatibility_matrix.3.xml",
+ stem: "compatibility_matrix.3.xml",
+ srcs: [
+ "compatibility_matrix.3.xml",
+ ],
+ kernel_configs: [
+ "kernel_config_p_4.4",
+ "kernel_config_p_4.9",
+ "kernel_config_p_4.14",
+ ]
+}
+
+vintf_compatibility_matrix {
+ name: "framework_compatibility_matrix.current.xml",
+ stem: "compatibility_matrix.current.xml",
+ srcs: [
+ "compatibility_matrix.current.xml",
+ ],
+ kernel_configs: [
+ "kernel_config_current_4.4",
+ "kernel_config_current_4.9",
+ "kernel_config_current_4.14",
+ ]
+}
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 22d0412..6be6930 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -18,72 +18,6 @@
BUILD_FRAMEWORK_COMPATIBILITY_MATRIX := $(LOCAL_PATH)/compatibility_matrix.mk
-my_kernel_config_data := kernel/configs
-
-# Install all compatibility_matrix.*.xml to /system/etc/vintf
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := framework_compatibility_matrix.legacy.xml
-LOCAL_MODULE_STEM := compatibility_matrix.legacy.xml
-LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_CONFIG_DATA_PATHS := \
- 3.18.0:$(my_kernel_config_data)/o/android-3.18 \
- 4.4.0:$(my_kernel_config_data)/o/android-4.4 \
- 4.9.0:$(my_kernel_config_data)/o/android-4.9 \
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := framework_compatibility_matrix.1.xml
-LOCAL_MODULE_STEM := compatibility_matrix.1.xml
-LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_CONFIG_DATA_PATHS := \
- 3.18.0:$(my_kernel_config_data)/o/android-3.18 \
- 4.4.0:$(my_kernel_config_data)/o/android-4.4 \
- 4.9.0:$(my_kernel_config_data)/o/android-4.9 \
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := framework_compatibility_matrix.2.xml
-LOCAL_MODULE_STEM := compatibility_matrix.2.xml
-LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_CONFIG_DATA_PATHS := \
- 3.18.0:$(my_kernel_config_data)/o-mr1/android-3.18 \
- 4.4.0:$(my_kernel_config_data)/o-mr1/android-4.4 \
- 4.9.0:$(my_kernel_config_data)/o-mr1/android-4.9 \
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := framework_compatibility_matrix.3.xml
-LOCAL_MODULE_STEM := compatibility_matrix.3.xml
-LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_CONFIG_DATA_PATHS := \
- 4.4.107:$(my_kernel_config_data)/p/android-4.4 \
- 4.9.84:$(my_kernel_config_data)/p/android-4.9 \
- 4.14.42:$(my_kernel_config_data)/p/android-4.14 \
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := framework_compatibility_matrix.current.xml
-LOCAL_MODULE_STEM := compatibility_matrix.current.xml
-LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_CONFIG_DATA_PATHS := \
- 4.4.0:$(my_kernel_config_data)/android-4.4 \
- 4.9.0:$(my_kernel_config_data)/android-4.9 \
- 4.14.0:$(my_kernel_config_data)/android-4.14 \
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-
-my_kernel_config_data :=
-
# Framework Compatibility Matrix (common to all FCM versions)
include $(CLEAR_VARS)
diff --git a/compatibility_matrices/build/Android.bp b/compatibility_matrices/build/Android.bp
new file mode 100644
index 0000000..42dc886
--- /dev/null
+++ b/compatibility_matrices/build/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 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.
+
+bootstrap_go_package {
+ name: "vintf-compatibility-matrix-soong-rules",
+ pkgPath: "android/soong/vintf-compatibility-matrix",
+ deps: [
+ "blueprint",
+ "blueprint-proptools",
+ "kernel-config-soong-rules",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "vintf_compatibility_matrix.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go
new file mode 100644
index 0000000..e48f993
--- /dev/null
+++ b/compatibility_matrices/build/vintf_compatibility_matrix.go
@@ -0,0 +1,132 @@
+// Copyright (C) 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.
+
+package vintf
+
+import (
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/kernel/configs"
+)
+
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+var (
+ pctx = android.NewPackageContext("android/vintf")
+
+ assembleVintfRule = pctx.AndroidStaticRule("assemble_vintf", blueprint.RuleParams{
+ Command: `${assembleVintfCmd} -i ${inputs} -o ${out}`,
+ CommandDeps: []string{"${assembleVintfCmd}"},
+ Description: "assemble_vintf -i ${inputs}",
+ }, "inputs")
+
+ kernelConfigTag = dependencyTag{name: "kernel-config"}
+)
+
+const (
+ relpath = "vintf"
+)
+
+type vintfCompatibilityMatrixProperties struct {
+ // set the name of the output
+ Stem *string
+
+ // list of source compatibility matrix XML files
+ Srcs []string
+
+ // list of kernel_config modules to be combined to final output
+ Kernel_configs []string
+}
+
+type vintfCompatibilityMatrixRule struct {
+ android.ModuleBase
+ properties vintfCompatibilityMatrixProperties
+
+ genFile android.WritablePath
+}
+
+func init() {
+ pctx.HostBinToolVariable("assembleVintfCmd", "assemble_vintf")
+ android.RegisterModuleType("vintf_compatibility_matrix", vintfCompatibilityMatrixFactory)
+}
+
+func vintfCompatibilityMatrixFactory() android.Module {
+ g := &vintfCompatibilityMatrixRule{}
+ g.AddProperties(&g.properties)
+ android.InitAndroidArchModule(g, android.DeviceSupported, android.MultilibCommon)
+ return g
+}
+
+var _ android.AndroidMkDataProvider = (*vintfCompatibilityMatrixRule)(nil)
+
+func (g *vintfCompatibilityMatrixRule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ android.ExtractSourcesDeps(ctx, g.properties.Srcs)
+ ctx.AddDependency(ctx.Module(), kernelConfigTag, g.properties.Kernel_configs...)
+}
+
+func (g *vintfCompatibilityMatrixRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+
+ outputFilename := proptools.String(g.properties.Stem)
+ if outputFilename == "" {
+ outputFilename = g.Name()
+ }
+
+ inputPaths := android.PathsForModuleSrc(ctx, g.properties.Srcs)
+ ctx.VisitDirectDepsWithTag(kernelConfigTag, func(m android.Module) {
+ if k, ok := m.(*configs.KernelConfigRule); ok {
+ inputPaths = append(inputPaths, k.OutputPath())
+ } else {
+ ctx.PropertyErrorf("kernel_config",
+ "module %q is not a kernel_config", ctx.OtherModuleName(m))
+ }
+ })
+
+ g.genFile = android.PathForModuleGen(ctx, outputFilename)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: assembleVintfRule,
+ Description: "Framework Compatibility Matrix",
+ Implicits: inputPaths,
+ Output: g.genFile,
+ Args: map[string]string{
+ "inputs": strings.Join(inputPaths.Strings(), ":"),
+ },
+ })
+
+ ctx.InstallFile(android.PathForModuleInstall(ctx, "etc", relpath), outputFilename, g.genFile)
+}
+
+func (g *vintfCompatibilityMatrixRule) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(g.genFile),
+ Extra: []android.AndroidMkExtraFunc{
+ func(w io.Writer, outputFile android.Path) {
+ fmt.Fprintln(w, "LOCAL_MODULE_RELATIVE_PATH :=", relpath)
+ if proptools.String(g.properties.Stem) != "" {
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", proptools.String(g.properties.Stem))
+ }
+ },
+ },
+ }
+}
diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml
index fc7bad6..4cb3776 100644
--- a/compatibility_matrices/compatibility_matrix.3.xml
+++ b/compatibility_matrices/compatibility_matrix.3.xml
@@ -193,7 +193,7 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.composer</name>
- <version>2.1-2</version>
+ <version>2.1-3</version>
<interface>
<name>IComposer</name>
<instance>default</instance>
@@ -445,7 +445,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.hostapd</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IHostapd</name>
<instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index ff5b3e8..fd996fb 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -145,7 +145,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.drm</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>ICryptoFactory</name>
<regex-instance>.*</regex-instance>
@@ -157,7 +157,7 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.drm</name>
- <version>1.1</version>
+ <version>1.2</version>
<interface>
<name>ICryptoFactory</name>
<regex-instance>.*</regex-instance>
@@ -286,7 +286,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.neuralnetworks</name>
- <version>1.0</version>
+ <version>1.0-2</version>
<interface>
<name>IDevice</name>
<regex-instance>.*</regex-instance>
@@ -317,6 +317,14 @@
</interface>
</hal>
<hal format="hidl" optional="true">
+ <name>android.hardware.power.stats</name>
+ <version>1.0</version>
+ <interface>
+ <name>IPowerStats</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
<name>android.hardware.radio</name>
<version>1.0-2</version>
<interface>
@@ -390,6 +398,7 @@
<hal format="hidl" optional="true">
<name>android.hardware.thermal</name>
<version>1.0-1</version>
+ <version>2.0</version>
<interface>
<name>IThermal</name>
<instance>default</instance>
@@ -461,7 +470,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.hostapd</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>IHostapd</name>
<instance>default</instance>
diff --git a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
index a1676be..70b5830 100644
--- a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
+++ b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
@@ -131,6 +131,27 @@
}
}
+/**
+ * Make sure the constrains of hasWideColorDisplay, hasHDRDisplay
+ * are enforced.
+ */
+TEST_F(ConfigstoreHidlTest, TestColorConstrainsBasic) {
+ bool hasWideColorDisplay;
+ bool hasHDRDisplay;
+
+ Return<void> status = sfConfigs->hasWideColorDisplay(
+ [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ status = sfConfigs->hasHDRDisplay([&](OptionalBool arg) { hasHDRDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ // When hasHDRDisplay returns true, hasWideColorDisplay must also return true.
+ if (hasHDRDisplay) {
+ ASSERT_TRUE(hasWideColorDisplay);
+ }
+}
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/configstore/1.2/Android.bp b/configstore/1.2/Android.bp
index cc5644c..bb4dd4a 100644
--- a/configstore/1.2/Android.bp
+++ b/configstore/1.2/Android.bp
@@ -10,10 +10,13 @@
"ISurfaceFlingerConfigs.hal",
],
interfaces: [
- "android.hardware.configstore@1.1",
"android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.1",
+ "android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
"android.hidl.base@1.0",
],
gen_java: true,
-}
\ No newline at end of file
+}
+
diff --git a/configstore/1.2/ISurfaceFlingerConfigs.hal b/configstore/1.2/ISurfaceFlingerConfigs.hal
index c879155..e91b2c7 100644
--- a/configstore/1.2/ISurfaceFlingerConfigs.hal
+++ b/configstore/1.2/ISurfaceFlingerConfigs.hal
@@ -15,8 +15,8 @@
*/
package android.hardware.configstore@1.2;
-import android.hardware.graphics.common@1.1::Dataspace;
import android.hardware.graphics.common@1.1::PixelFormat;
+import android.hardware.graphics.common@1.2::Dataspace;
import @1.1::ISurfaceFlingerConfigs;
import @1.0::OptionalBool;
@@ -34,25 +34,39 @@
useColorManagement() generates (OptionalBool value);
/**
- * Returns the default data space and default pixel format that
- * SurfaceFlinger expects to receive and output.
- * To determine the default data space and default pixel format,
- * there are a few things we recommend to consider:
+ * Returns the default data space and pixel format that SurfaceFlinger
+ * expects to receive and output as well as the wide color gamut data space
+ * and pixel format for wide color gamut surfaces.
+ * To determine the data space and pixel format, there are a few things
+ * we recommend to consider:
*
- * 1. Hardware composer's capability to composite contents with the
+ * 1. Hardware composer's capability to composite contents with the chosen
* data space and pixel format efficiently;
* 2. Hardware composer's ability to composite contents when sRGB contents
- * and the chosen data space contents coexist;
+ * and the chosen wide color gamut data space contents coexist;
* 3. For better blending, consider using pixel format where the alpha
* channel has as many bits as the RGB color channel.
+ * 4. Memory consumption and efficient buffer compression when considering
+ * more bits in pixel format.
*
- * @return dataSpace is the default data space that SurfaceFlinger expects.
+ * @return dataspace is the default data space that SurfaceFlinger expects.
* The data space must not be Dataspace::UNKNOWN, if unspecified,
* the default data space is Dataspace::V0_SRGB;
* @return pixelFormat is the default pixel format that SurfaceFlinger
* expects. If unspecified, the default pixel format is
* PixelFormat::RGBA_8888.
+ * @return wcgDataspace is the data space that SurfaceFlinger expects for
+ * wide color gamut surfaces.
+ * When hasWideColorDisplay returns true, this API must return a
+ * valid wide color gamut data space.
+ * The data space must not be UNKNOWN, if unspecified, the data space
+ * is V0_SRGB by default, which essentially indicates there's no wide
+ * color gamut, meaning hasWideColorDisplay returns false.
+ * @return wcgPixelFormat is the pixel format that SurfaceFlinger expects for
+ * wide color gamut surfaces. If unspecified, the pixel format is
+ * PixelFormat::RGBA_8888 by default.
*/
getCompositionPreference()
- generates (Dataspace dataSpace, PixelFormat pixelFormat);
+ generates (Dataspace dataspace, PixelFormat pixelFormat,
+ Dataspace wcgDataspace, PixelFormat wcgPixelFormat);
};
diff --git a/configstore/1.2/default/SurfaceFlingerConfigs.cpp b/configstore/1.2/default/SurfaceFlingerConfigs.cpp
index ae19dc0..c2cf374 100644
--- a/configstore/1.2/default/SurfaceFlingerConfigs.cpp
+++ b/configstore/1.2/default/SurfaceFlingerConfigs.cpp
@@ -26,8 +26,8 @@
namespace V1_2 {
namespace implementation {
-using ::android::hardware::graphics::common::V1_1::Dataspace;
using ::android::hardware::graphics::common::V1_1::PixelFormat;
+using ::android::hardware::graphics::common::V1_2::Dataspace;
// ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation.
Return<void> SurfaceFlingerConfigs::vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) {
@@ -203,22 +203,41 @@
return Void();
}
-#ifdef COMPOSITION_DATA_SPACE
-static_assert(COMPOSITION_DATA_SPACE != 0, "Expected composition data space must not be UNKNOWN");
+#ifdef DEFAULT_COMPOSITION_DATA_SPACE
+static_assert(DEFAULT_COMPOSITION_DATA_SPACE != 0,
+ "Default composition data space must not be UNKNOWN");
+#endif
+
+#ifdef WCG_COMPOSITION_DATA_SPACE
+static_assert(WCG_COMPOSITION_DATA_SPACE != 0,
+ "Wide color gamut composition data space must not be UNKNOWN");
#endif
Return<void> SurfaceFlingerConfigs::getCompositionPreference(getCompositionPreference_cb _hidl_cb) {
- Dataspace dataSpace = Dataspace::V0_SRGB;
- PixelFormat pixelFormat = PixelFormat::RGBA_8888;
+ Dataspace defaultDataspace = Dataspace::V0_SRGB;
+ PixelFormat defaultPixelFormat = PixelFormat::RGBA_8888;
-#ifdef COMPOSITION_DATA_SPACE
- dataSpace = static_cast<Dataspace>(COMPOSITION_DATA_SPACE);
+#ifdef DEFAULT_COMPOSITION_DATA_SPACE
+ defaultDataspace = static_cast<Dataspace>(DEFAULT_COMPOSITION_DATA_SPACE);
#endif
-#ifdef COMPOSITION_PIXEL_FORMAT
- pixelFormat = static_cast<PixelFormat>(COMPOSITION_PIXEL_FORMAT);
+#ifdef DEFAULT_COMPOSITION_PIXEL_FORMAT
+ defaultPixelFormat = static_cast<PixelFormat>(DEFAULT_COMPOSITION_PIXEL_FORMAT);
#endif
- _hidl_cb(dataSpace, pixelFormat);
+
+ Dataspace wideColorGamutDataspace = Dataspace::V0_SRGB;
+ PixelFormat wideColorGamutPixelFormat = PixelFormat::RGBA_8888;
+
+#ifdef WCG_COMPOSITION_DATA_SPACE
+ wideColorGamutDataspace = static_cast<Dataspace>(WCG_COMPOSITION_DATA_SPACE);
+#endif
+
+#ifdef WCG_COMPOSITION_PIXEL_FORMAT
+ wideColorGamutPixelFormat = static_cast<PixelFormat>(WCG_COMPOSITION_PIXEL_FORMAT);
+#endif
+
+ _hidl_cb(defaultDataspace, defaultPixelFormat, wideColorGamutDataspace,
+ wideColorGamutPixelFormat);
return Void();
}
diff --git a/configstore/1.2/default/surfaceflinger.mk b/configstore/1.2/default/surfaceflinger.mk
index f323999..dab6aa5 100644
--- a/configstore/1.2/default/surfaceflinger.mk
+++ b/configstore/1.2/default/surfaceflinger.mk
@@ -59,10 +59,18 @@
LOCAL_CFLAGS += -DUSE_COLOR_MANAGEMENT
endif
-ifneq ($(SF_COMPOSITION_DATA_SPACE),)
- LOCAL_CFLAGS += -DCOMPOSITION_DATA_SPACE=$(SF_COMPOSITION_DATA_SPACE)
+ifneq ($(SF_DEFAULT_COMPOSITION_DATA_SPACE),)
+ LOCAL_CFLAGS += -DDEFAULT_COMPOSITION_DATA_SPACE=$(SF_DEFAULT_COMPOSITION_DATA_SPACE)
endif
-ifneq ($(SF_COMPOSITION_PIXEL_FORMAT),)
- LOCAL_CFLAGS += -DCOMPOSITION_PIXEL_FORMAT=$(SF_COMPOSITION_PIXEL_FORMAT)
+ifneq ($(SF_DEFAULT_COMPOSITION_PIXEL_FORMAT),)
+ LOCAL_CFLAGS += -DDEFAULT_COMPOSITION_PIXEL_FORMAT=$(SF_DEFAULT_COMPOSITION_PIXEL_FORMAT)
+endif
+
+ifneq ($(SF_WCG_COMPOSITION_DATA_SPACE),)
+ LOCAL_CFLAGS += -DWCG_COMPOSITION_DATA_SPACE=$(SF_WCG_COMPOSITION_DATA_SPACE)
+endif
+
+ifneq ($(SF_WCG_COMPOSITION_PIXEL_FORMAT),)
+ LOCAL_CFLAGS += -DWCG_COMPOSITION_PIXEL_FORMAT=$(SF_WCG_COMPOSITION_PIXEL_FORMAT)
endif
diff --git a/configstore/1.2/vts/functional/Android.bp b/configstore/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..5f1eca6
--- /dev/null
+++ b/configstore/1.2/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 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.
+//
+
+cc_test {
+ name: "VtsHalConfigstoreV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalConfigstoreV1_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.1",
+ "android.hardware.configstore@1.2",
+ ],
+}
+
diff --git a/configstore/1.2/vts/functional/OWNERS b/configstore/1.2/vts/functional/OWNERS
new file mode 100644
index 0000000..2b4fb8c
--- /dev/null
+++ b/configstore/1.2/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+# Graphics team
+lpy@google.com
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
diff --git a/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp
new file mode 100644
index 0000000..dc5fec5
--- /dev/null
+++ b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2017 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 "ConfigstoreHidlHalTest"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/configstore/1.0/types.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <unistd.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::configstore::V1_0::OptionalBool;
+using ::android::hardware::configstore::V1_0::OptionalInt64;
+using ::android::hardware::configstore::V1_0::OptionalUInt64;
+using ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs;
+using ::android::hardware::graphics::common::V1_1::PixelFormat;
+using ::android::hardware::graphics::common::V1_2::Dataspace;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+// Test environment for Configstore HIDL HAL.
+class ConfigstoreHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static ConfigstoreHidlEnvironment* Instance() {
+ static ConfigstoreHidlEnvironment* instance = new ConfigstoreHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<ISurfaceFlingerConfigs>(); }
+};
+
+class ConfigstoreHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ sp<ISurfaceFlingerConfigs> sfConfigs;
+
+ virtual void SetUp() override {
+ sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<ISurfaceFlingerConfigs>(
+ ConfigstoreHidlEnvironment::Instance()->getServiceName<ISurfaceFlingerConfigs>());
+ ASSERT_NE(sfConfigs, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ bool isSupportedWideColorGamut(Dataspace dataspace) {
+ Dataspace standard = static_cast<Dataspace>(dataspace & Dataspace::STANDARD_MASK);
+ return standard == Dataspace::STANDARD_DCI_P3 || standard == Dataspace::STANDARD_BT2020;
+ }
+};
+
+/**
+ * Make sure the constrains of hasWideColorDisplay, hasHDRDisplay
+ * and useColorManagement are enforced.
+ */
+TEST_F(ConfigstoreHidlTest, TestColorConstrainsWithColorManagement) {
+ bool hasWideColorDisplay;
+ bool hasHDRDisplay;
+ bool useColorManagement;
+
+ Return<void> status = sfConfigs->hasWideColorDisplay(
+ [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ status = sfConfigs->hasHDRDisplay([&](OptionalBool arg) { hasHDRDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ status = sfConfigs->useColorManagement(
+ [&](OptionalBool arg) { useColorManagement = arg.specified; });
+ EXPECT_OK(status);
+
+ // When hasHDRDisplay returns true, hasWideColorDisplay must also return true.
+ if (hasHDRDisplay) {
+ ASSERT_TRUE(hasWideColorDisplay);
+ }
+
+ // When hasWideColorDisplay returns true, useColorManagement
+ // must also return true.
+ if (hasWideColorDisplay) {
+ ASSERT_TRUE(useColorManagement);
+ }
+}
+
+TEST_F(ConfigstoreHidlTest, TestGetCompositionPreference) {
+ bool hasWideColorDisplay;
+
+ Return<void> status = sfConfigs->hasWideColorDisplay(
+ [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ Dataspace defaultDataspace, wcgDataspace;
+
+ status = sfConfigs->getCompositionPreference(
+ [&](auto tmpDefaultDataspace, PixelFormat, auto tmpWcgDataspace, PixelFormat) {
+ defaultDataspace = tmpDefaultDataspace;
+ wcgDataspace = tmpWcgDataspace;
+ });
+ EXPECT_OK(status);
+
+ // Default data space and wide color gamut data space must not be UNKNOWN.
+ ASSERT_TRUE(defaultDataspace != Dataspace::UNKNOWN && wcgDataspace != Dataspace::UNKNOWN);
+
+ // If hasWideColorDisplay returns true, the wide color gamut data space must be a valid wide
+ // color gamut.
+ if (hasWideColorDisplay) {
+ ASSERT_TRUE(isSupportedWideColorGamut(wcgDataspace));
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ ConfigstoreHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/confirmationui/support/src/cbor.cpp b/confirmationui/support/src/cbor.cpp
index e7ea164..3685521 100644
--- a/confirmationui/support/src/cbor.cpp
+++ b/confirmationui/support/src/cbor.cpp
@@ -36,11 +36,14 @@
*pos++ = getByte(value, 6);
*pos++ = getByte(value, 5);
*pos++ = getByte(value, 4);
+ [[fallthrough]];
case 4:
*pos++ = getByte(value, 3);
*pos++ = getByte(value, 2);
+ [[fallthrough]];
case 2:
*pos++ = getByte(value, 1);
+ [[fallthrough]];
case 1:
*pos++ = value;
break;
diff --git a/current.txt b/current.txt
index ad45c26..e19fb63 100644
--- a/current.txt
+++ b/current.txt
@@ -388,9 +388,11 @@
2a55e224aa9bc62c0387cd85ad3c97e33f0c33a4e1489cbae86b2523e6f9df35 android.hardware.camera.device@3.2::ICameraDevice
f61b616732d8f374e030f90575d7eba3ecc99d209a05b945949ba892bcb81e1d android.hardware.camera.device@3.2::ICameraDeviceSession
684702a60deef03a1e8093961dc0a18c555c857ad5a77ba7340b0635ae01eb70 android.hardware.camera.device@3.4::ICameraDeviceSession
-a95745bbf76aea16a76518bd7efe70cabc5886d09eaeffc993c2e1787a22ed23 android.hardware.camera.metadata@3.3::types
+291638a1b6d4e63283e9e722ab5049d9351717ffa2b66162124f84d1aa7c2835 android.hardware.camera.metadata@3.2::types
+dd2436f251a90f3e5e7ed773b1aeae21e381b00ae26b10ebe3a1001c894e5980 android.hardware.camera.metadata@3.3::types
da33234403ff5d60f3473711917b9948e6484a4260b5247acdafb111193a9de2 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
-78886339f2c848cf13c1edd3ebba63f89796b2620d3bf3b5c21d038a53519ba0 android.hardware.gnss@1.0::IGnssMeasurementCallback
+21165b8e30c4b2d52980e4728f661420adc16e38bbe73476c06b2085be908f4c android.hardware.gnss@1.0::IGnssCallback
+d702fb01dc2a0733aa820b7eb65435ee3334f75632ef880bafd2fb8803a20a58 android.hardware.gnss@1.0::IGnssMeasurementCallback
b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardware.keymaster@4.0::IKeymasterDevice
574e8f1499436fb4075894dcae0b36682427956ecb114f17f1fe22d116a83c6b android.hardware.neuralnetworks@1.0::IPreparedModel
1fb32361286b938d48a55c2539c846732afce0b99fe08590f556643125bc13d3 android.hardware.neuralnetworks@1.0::types
@@ -398,5 +400,6 @@
1d4a5776614c08b5d794a5ec5ab04697260cbd4b3441d5935cd53ee71d19da02 android.hardware.radio@1.0::IRadioResponse
271187e261b30c01a33011aea257c07a2d2f05b72943ebee89e973e997849973 android.hardware.radio@1.0::types
1d19720d4fd38b1095f0f555a4bd92b3b12c9b1d0f560b0e9a474cd6dcc20db6 android.hardware.radio@1.2::IRadio
+e78cf871f9fd1c072874e481e06e18e2681763cf2aa38c1fd777d53bab4eb69b android.hardware.sensors@1.0::types
1722ad002317b1fae1400de709e90f442d94ef22864e05f7a12af48c32e8edc8 android.hardware.usb@1.1::types
29c8da7a13c40d488f569c812441d5754ee45bdcdb8ce6564f524b708d10a057 android.hardware.vibrator@1.1::types
diff --git a/drm/1.1/README.md b/drm/1.1/README.md
new file mode 100644
index 0000000..e88e6ab
--- /dev/null
+++ b/drm/1.1/README.md
@@ -0,0 +1,84 @@
+# VINTF Device Manifest
+
+In Android Pie, an `<fqname>` tag was introduced to be able to express multiple
+different versions of the same HAL in VINTF manifests (for DRM)
+in device manifest. For devices launching with previous versions of Android and
+upgrading to Android Pie, the device manifest must not use `<fqname>` to
+satisfy requirements for non-optional HALs, because older version of `libvintf`
+do not recognize it, causing errors during OTA update.
+
+Assuming that the HAL provides `@1.0::I*/default`,
+`@1.1::I*/clearkey` and `@1.1::I*/foo` instances:
+
+## Devices upgrading to Android Pie
+
+### `target-level=1` or `target-level=2`
+
+FCM (framework compatibility matrix) version 2 (released in Android Oreo MR1)
+requires DRM 1.0. If the new device manifest has Target FCM Version (i.e.
+`target-level`) 1 or 2, it should use the following snippet:
+
+```xml
+<hal format="hidl">
+ <name>android.hardware.drm</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>ICryptoFactory</name>
+ <instance>default</instance>
+ </interface>
+ <interface>
+ <name>IDrmFactory</name>
+ <instance>default</instance>
+ </interface>
+ <fqname>@1.1::ICryptoFactory/clearkey</fqname>
+ <fqname>@1.1::IDrmFactory/clearkey</fqname>
+ <fqname>@1.1::ICryptoFactory/foo</fqname>
+ <fqname>@1.1::IDrmFactory/foo</fqname>
+</hal>
+```
+
+### `target-level=3`
+
+FCM (framework compatibility matrix) version 3 (released in Android Pie)
+requires DRM 1.1. If the new device manifest has Target FCM Version (i.e.
+`target-level`) 3, it should use the following snippet:
+
+
+```xml
+<hal format="hidl">
+ <name>android.hardware.drm</name>
+ <transport>hwbinder</transport>
+ <version>1.1</version>
+ <interface>
+ <name>ICryptoFactory</name>
+ <instance>clearkey</instance>
+ <instance>foo</instance>
+ </interface>
+ <interface>
+ <name>IDrmFactory</name>
+ <instance>clearkey</instance>
+ <instance>foo</instance>
+ </interface>
+ <fqname>@1.0::ICryptoFactory/default</fqname>
+ <fqname>@1.0::IDrmFactory/default</fqname>
+</hal>
+```
+
+## Devices launching with Android Pie
+If you have a new device launched with Android Pie (no OTA), both of the
+aforementioned snippets can be used. Besides, it is recommended to use the
+new, clearer format:
+
+```xml
+<hal format="hidl">
+ <name>android.hardware.drm</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.0::ICryptoFactory/default</fqname>
+ <fqname>@1.0::IDrmFactory/default</fqname>
+ <fqname>@1.1::ICryptoFactory/clearkey</fqname>
+ <fqname>@1.1::IDrmFactory/clearkey</fqname>
+ <fqname>@1.1::ICryptoFactory/foo</fqname>
+ <fqname>@1.1::IDrmFactory/foo</fqname>
+</hal>
+```
diff --git a/drm/1.2/Android.bp b/drm/1.2/Android.bp
new file mode 100644
index 0000000..66a1bd8
--- /dev/null
+++ b/drm/1.2/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.drm@1.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ICryptoFactory.hal",
+ "IDrmFactory.hal",
+ "IDrmPlugin.hal",
+ ],
+ interfaces: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "KeySetId",
+ "OfflineLicenseState",
+ ],
+ gen_java: false,
+}
+
diff --git a/drm/1.2/ICryptoFactory.hal b/drm/1.2/ICryptoFactory.hal
new file mode 100644
index 0000000..c4a9b4b
--- /dev/null
+++ b/drm/1.2/ICryptoFactory.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 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.
+ */
+package android.hardware.drm@1.2;
+
+import @1.1::ICryptoFactory;
+
+/**
+ * ICryptoFactory is the main entry point for interacting with a vendor's
+ * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions
+ * which are used by a codec to decrypt protected video content.
+ *
+ * The 1.2 factory must always create 1.2 ICryptoPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ *
+ * To use 1.2 features the caller must cast the returned interface to a
+ * 1.2 HAL, using V1_2::IDrmPlugin::castFrom().
+ *
+ * The ICryptoFactory hal is required because all top-level interfaces
+ * have to be updated in a minor uprev.
+ */
+interface ICryptoFactory extends @1.1::ICryptoFactory {
+};
diff --git a/drm/1.2/IDrmFactory.hal b/drm/1.2/IDrmFactory.hal
new file mode 100644
index 0000000..c94e4bb
--- /dev/null
+++ b/drm/1.2/IDrmFactory.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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.
+ */
+package android.hardware.drm@1.2;
+
+import @1.1::IDrmFactory;
+import @1.1::IDrmPlugin;
+
+/**
+ * IDrmFactory is the main entry point for interacting with a vendor's
+ * drm HAL to create drm plugin instances. A drm plugin instance
+ * creates drm sessions which are used to obtain keys for a crypto
+ * session so it can decrypt protected video content.
+ *
+ * The 1.2 factory must always create 1.2 IDrmPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ *
+ * To use 1.2 features the caller must cast the returned interface to a
+ * 1.2 HAL, using V1_2::IDrmPlugin::castFrom().
+ *
+ * The IDrmFactory hal is required because all top-level interfaces
+ * have to be updated in a minor uprev.
+ */
+
+interface IDrmFactory extends @1.1::IDrmFactory {
+};
diff --git a/drm/1.2/IDrmPlugin.hal b/drm/1.2/IDrmPlugin.hal
new file mode 100644
index 0000000..88338d6
--- /dev/null
+++ b/drm/1.2/IDrmPlugin.hal
@@ -0,0 +1,94 @@
+/**
+ * Copyright (C) 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.
+ */
+package android.hardware.drm@1.2;
+
+import @1.1::IDrmPlugin;
+import @1.0::Status;
+
+/**
+ * IDrmPlugin is used to interact with a specific drm plugin that was created by
+ * IDrm::createPlugin. A drm plugin provides methods for obtaining drm keys that
+ * may be used by a codec to decrypt protected video content.
+ */
+interface IDrmPlugin extends @1.1::IDrmPlugin {
+
+ /**
+ * The keys in an offline license allow protected content to be
+ * played even if the device is not connected to a network.
+ * Offline licenses are stored on the device after a key
+ * request/response exchange when the key request KeyType is
+ * OFFLINE. Normally each app is responsible for keeping track of
+ * the KeySetIds it has created. In some situations however, it
+ * may be necessary to request the list of stored offline license
+ * KeySetIds. If an app loses the KeySetId for any stored licenses
+ * that it created, for example, it must be able to recover the
+ * stored KeySetIds so those licenses can be removed when they
+ * expire or when the app is uninstalled.
+ * <p>
+ * This method returns a list of the KeySetIds for all offline
+ * licenses. The offline license KeySetId may be used to query
+ * the status of an offline license or remove it.
+ *
+ * @return status the status of the call. May be OK or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+ * KeySetIds can't be returned.
+ * @return a list of offline license keySetIds. If there are no offline
+ * licenses, the list must be empty and OK must be returned as the
+ * status.
+ */
+ getOfflineLicenseKeySetIds() generates (Status status, vec<KeySetId> keySetIds);
+
+ /**
+ * Normally offline licenses are released using a key
+ * request/response exchange using getKeyRequest where the KeyType
+ * is RELEASE, followed by provideKeyResponse. This allows the
+ * server to cryptographically confirm that the license has been
+ * removed and then adjust the count of offline licenses allocated
+ * to the device.
+ * <p>
+ * In some exceptional situations it may be necessary to directly
+ * remove offline licenses without notifying the server, which may
+ * be performed using this method.
+ *
+ * @param keySetId the id of the offline license to remove
+ * @return status the status of the call. May be one of OK on
+ * success, BAD_VALUE if the license is not found or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+ * KeySetIds can't be returned.
+ */
+ removeOfflineLicense(KeySetId keySetId) generates (Status status);
+
+ /**
+ * Request the state of an offline license. An offline license may
+ * be usable or inactive. The keys in a usable offline license are
+ * available for decryption. When the offline license state is
+ * inactive, the keys have been marked for release using
+ * getKeyRequest with KeyType RELEASE but the key response has not
+ * been received. The keys in an inactive offline license are not
+ * usable for decryption.
+ *
+ * @param keySetId the id of the offline license
+ * @return status the status of the call. May be one of OK on
+ * success, BAD_VALUE if the license is not found or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+ * offline license state can't be queried.
+ * @return the offline license state, one of USABLE or INACTIVE.
+ * If the return status is not OK then state must be set to
+ * UNKNOWN.
+ */
+ getOfflineLicenseState(KeySetId keySetId) generates (Status status,
+ OfflineLicenseState state);
+};
diff --git a/drm/1.2/types.hal b/drm/1.2/types.hal
new file mode 100644
index 0000000..8770c79
--- /dev/null
+++ b/drm/1.2/types.hal
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 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.
+ */
+
+package android.hardware.drm@1.2;
+
+enum OfflineLicenseState : uint32_t {
+ /**
+ * Offline license state is unknown
+ */
+ UNKNOWN,
+
+ /**
+ * Offline license state is usable, the keys may be used for decryption.
+ */
+ USABLE,
+
+ /**
+ * Offline license state is inactive, the keys have been marked for
+ * release using {@link #getKeyRequest} with KEY_TYPE_RELEASE but the
+ * key response has not been received.
+ */
+ INACTIVE
+};
+
+/**
+ * KeySetId is an identifier that references a set of keys in an
+ * offline license. The keySetId is created by the HAL implementation
+ * and returned from provideKeyResponse and getOfflineLicenseIds. The
+ * framework passes KeySetId back to the HAL when referring to the key
+ * set in methods that take a KeySetId as an input parameter.
+ */
+typedef vec<uint8_t> KeySetId;
diff --git a/fastboot/1.0/Android.bp b/fastboot/1.0/Android.bp
index 3267499..467fc6d 100644
--- a/fastboot/1.0/Android.bp
+++ b/fastboot/1.0/Android.bp
@@ -14,9 +14,10 @@
"android.hidl.base@1.0",
],
types: [
- "Status",
+ "FileSystemType",
"Result",
+ "Status",
],
- gen_java: false,
+ gen_java: true,
}
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal
index 7fb38c5..d62676f 100644
--- a/gnss/1.0/IGnssCallback.hal
+++ b/gnss/1.0/IGnssCallback.hal
@@ -115,9 +115,9 @@
/**
* Carrier frequency of the signal tracked, for example it can be the
* GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 =
- * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it
- * is the primary common use central frequency, e.g. L1 = 1575.45 MHz
- * for GPS.
+ * 1176.45 MHz, varying GLO channels, etc. If the field is zero, it is
+ * the primary common use central frequency, e.g. L1 = 1575.45 MHz for
+ * GPS.
*
* For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
* time, two GnssSvInfo structs must be reported for this same
@@ -125,8 +125,7 @@
* to L1 must be filled, and in the other all of the values related to
* L5 must be filled.
*
- * If the data is available, gnssClockFlags must contain
- * HAS_CARRIER_FREQUENCY.
+ * If the data is available, svFlag must contain HAS_CARRIER_FREQUENCY.
*/
float carrierFrequencyHz;
diff --git a/gnss/1.0/IGnssMeasurementCallback.hal b/gnss/1.0/IGnssMeasurementCallback.hal
index d3489e6..2d44766 100644
--- a/gnss/1.0/IGnssMeasurementCallback.hal
+++ b/gnss/1.0/IGnssMeasurementCallback.hal
@@ -436,6 +436,10 @@
* Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
* It contains the measured C/N0 value for the signal at the antenna port.
*
+ * If a signal has separate components (e.g. Pilot and Data channels) and
+ * the receiver only processes one of the components, then the reported
+ * cN0DbHz reflects only the component that is processed.
+ *
* This value is mandatory.
*/
double cN0DbHz;
diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp
new file mode 100644
index 0000000..5385f28
--- /dev/null
+++ b/graphics/bufferqueue/2.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.bufferqueue@2.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IGraphicBufferProducer.hal",
+ "IProducerListener.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "ConnectionType",
+ "SlotIndex",
+ "Status",
+ ],
+ gen_java: true,
+}
+
diff --git a/graphics/bufferqueue/2.0/IGraphicBufferProducer.hal b/graphics/bufferqueue/2.0/IGraphicBufferProducer.hal
new file mode 100644
index 0000000..734c0b4
--- /dev/null
+++ b/graphics/bufferqueue/2.0/IGraphicBufferProducer.hal
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.graphics.bufferqueue@2.0;
+
+import android.hardware.graphics.common@1.2::HardwareBuffer;
+import android.hardware.graphics.common@1.2::HardwareBufferDescription;
+import android.hardware.graphics.common@1.2::Rect;
+
+import IProducerListener;
+
+/**
+ * Ref: frameworks/native/include/gui/IGraphicBufferProducer.h:
+ * IGraphicBufferProducer
+ * This is a wrapper/wrapped HAL interface for the actual binder interface.
+ */
+interface IGraphicBufferProducer {
+ /**
+ * Sets the maximum number of buffers that can be dequeued at one time. If
+ * this method succeeds, any new buffer slots shall be both unallocated and
+ * owned by the buffer queue, i.e., they are not owned by the producer or
+ * the consumer. Calling this may cause some buffer slots to be emptied. If
+ * the caller is caching the contents of the buffer slots, it must empty
+ * that cache after calling this method.
+ *
+ * @p maxDequeuedBuffers must not be less than the number of currently
+ * dequeued buffer slots; otherwise, the returned @p status shall be
+ * `BAD_VALUE`.
+ *
+ * @p maxDequeuedBuffers must be at least 1 (inclusive), but at most
+ * (`NUM_BUFFER_SLOTS` - the minimum undequeued buffer count) (exclusive).
+ * The minimum undequeued buffer count can be obtained by calling
+ * `query(ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS)`.
+ *
+ * Before calling setMaxDequeuedBufferCount(), the caller must make sure
+ * that
+ * - @p maxDequeuedBuffers is greater than or equal to 1.
+ * - @p maxDequeuedBuffers is greater than or equal to the number of
+ * currently dequeued buffer slots.
+ * If any of these conditions do not hold, or if the request to set the new
+ * maximum number of dequeued buffers cannot be accomplished for any other
+ * reasons, `BAD_VALUE` shall be returned in @p status.
+ *
+ * @param maxDequeuedBuffers The desired number of buffers that can be
+ * dequeued at one time.
+ * @return status Status of the call.
+ */
+ setMaxDequeuedBufferCount(
+ int32_t maxDequeuedBuffers
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Assigns a newly created buffer to the given slot index. The client is
+ * expected to mirror the slot-to-buffer mapping so that it is not necessary
+ * to transfer a `HardwareBuffer` object for every dequeue operation.
+ *
+ * If @p slot is not a valid slot index corresponding to a dequeued buffer,
+ * the call shall fail with @p status set to `BAD_VALUE`.
+ *
+ * @param slot Slot index.
+ * @return status Status of the call.
+ * @return buffer New buffer associated to the given slot index.
+ */
+ requestBuffer(
+ int32_t slot
+ ) generates (
+ Status status,
+ HardwareBuffer buffer
+ );
+
+ /**
+ * Sets the async flag: whether the producer intends to asynchronously queue
+ * buffers without blocking. Typically this is used for triple-buffering
+ * and/or when the swap interval is set to zero.
+ *
+ * Enabling async mode may internally allocate an additional buffer to allow
+ * for the asynchronous behavior. If it is not enabled, queue/dequeue calls
+ * may block.
+ *
+ * Changing the async flag may affect the number of available slots. If the
+ * adjustment to the number of slots cannot be made, @p status shall be set
+ * to `BAD_VALUE`.
+ *
+ * @param async True if the asynchronous operation is desired; false
+ * otherwise.
+ * @return status Status of the call.
+ */
+ setAsyncMode(
+ bool async
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Input data for dequeueBuffer() specifying desired attributes of a buffer
+ * to dequeue.
+ *
+ * This structure contains 4 fields from
+ * +llndk libnativewindow#AHardwareBuffer_Desc.
+ *
+ * The `width` and `height` parameters must be no greater than the minimum
+ * of `GL_MAX_VIEWPORT_DIMS` and `GL_MAX_TEXTURE_SIZE` (see:
+ * glGetIntegerv()). An error due to invalid dimensions may not be reported
+ * until updateTexImage() is called.
+ *
+ * If `width` and `height` are both zero, the default dimensions shall be
+ * used. If only one of `width` and `height` is zero, dequeueBuffer() shall
+ * return `BAD_VALUE` in `status`.
+ *
+ * If `format` is zero, the default format shall be used.
+ *
+ * `usage` shall be merged with the usage flags set from the consumer side.
+ *
+ * @sa +llndk libnativewindow#AHardwareBuffer_Desc.
+ */
+ struct DequeueBufferInput {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint64_t usage;
+ };
+
+ /**
+ * Output data for dequeueBuffer().
+ *
+ * A `DequeueBufferOutput` object returned from dequeueBuffer() shall be
+ * valid if and only if `status` returned from the same call is `OK`.
+ */
+ struct DequeueBufferOutput {
+ /**
+ * The number of frames that have elapsed since the buffer was last
+ * queued.
+ */
+ uint64_t bufferAge;
+ /**
+ * Whether the client must call requestBuffer().
+ */
+ bool bufferNeedsReallocation;
+ /**
+ * Whether the client must discard the mirrored slot-to-buffer
+ * mapping.
+ */
+ bool releaseAllBuffers;
+ /**
+ * Fence associated with the buffer.
+ *
+ * If this is an empty fence, the buffer may be written immediately;
+ * otherwise, the buffer must not be written to until the fence signals.
+ */
+ Fence fence;
+ };
+
+ /**
+ * Requests a new buffer slot for the client to use. Ownership of the slot
+ * is transfered to the client, meaning that the server shall not use the
+ * contents of the buffer associated with that slot.
+ *
+ * On success, @p status shall be `OK`, and @p output shall contain valid
+ * information of the call. Otherwise, the contents of @p output are
+ * meaningless.
+ *
+ * The slot index returned in @p slot may or may not contain a buffer
+ * (client-side). If the slot is empty, the client must call
+ * requestBuffer() to assign a new buffer to that slot.
+ *
+ * Once the client is done filling this buffer, it is expected to transfer
+ * buffer ownership back to the server with either cancelBuffer() on
+ * the dequeued slot or to fill in the contents of its associated buffer
+ * contents and call queueBuffer().
+ *
+ * If dequeueBuffer() returns with `output.releaseAllBuffers` set to `true`,
+ * the client is expected to release all of the mirrored slot-to-buffer
+ * mappings.
+ *
+ * If dequeueBuffer() returns with `output.bufferNeedsReallocation` set to
+ * `true`, the client is expected to call requestBuffer() immediately.
+ *
+ * The returned `output.fence` shall be updated to hold the fence associated
+ * with the buffer. The contents of the buffer must not be overwritten until
+ * the fence signals. If the fence is an empty fence, the buffer may be
+ * written immediately.
+ *
+ * This call shall block until a buffer is available to be dequeued. If
+ * both the producer and consumer are controlled by the app, then this call
+ * can never block and shall return `WOULD_BLOCK` in @p status if no buffer
+ * is available.
+ *
+ * If a dequeue operation shall cause certain conditions on the number of
+ * buffers to be violated (such as the maximum number of dequeued buffers),
+ * @p status shall be set to `INVALID_OPERATION` to indicate failure.
+ *
+ * If a dequeue operation cannot be completed within the time period
+ * previously set by setDequeueTimeout(), the return @p status shall
+ * `TIMED_OUT`.
+ *
+ * See @ref DequeueBufferInput for more information on the @p input
+ * parameter.
+ *
+ * @param input See #DequeueBufferInput for more information.
+ * @param status Status of the call.
+ * @param slot Slot index.
+ * @param output See #DequeueBufferOutput for more information.
+ *
+ * @sa queueBuffer(), requestBuffer().
+ */
+ dequeueBuffer(
+ DequeueBufferInput input
+ ) generates (
+ Status status,
+ int32_t slot,
+ DequeueBufferOutput output
+ );
+
+ /**
+ * Attempts to remove all ownership of the buffer in the given slot from the
+ * buffer queue.
+ *
+ * If this call succeeds, the slot shall be freed, and there shall be no way
+ * to obtain the buffer from this interface. The freed slot shall remain
+ * unallocated until either it is selected to hold a freshly allocated
+ * buffer in dequeueBuffer() or a buffer is attached to the slot. The buffer
+ * must have already been dequeued, and the caller must already possesses
+ * the buffer (i.e., must have called requestBuffer()).
+ *
+ * @param slot Slot index.
+ * @return status Status of the call.
+ */
+ detachBuffer(
+ int32_t slot
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Dequeues a buffer slot, requests the buffer associated to the slot, and
+ * detaches it from the buffer queue. This is equivalent to calling
+ * dequeueBuffer(), requestBuffer(), and detachBuffer() in succession except
+ * for two things:
+ * 1. It is unnecessary to provide a #DequeueBufferInput object.
+ * 2. The call shall not block, since if it cannot find an appropriate
+ * buffer to return, it shall return an error instead.
+ *
+ * Only slots that are free but still contain a buffer shall be considered,
+ * and the oldest of those shall be returned. @p buffer is equivalent to the
+ * buffer that would be returned from requestBuffer(), and @p fence is
+ * equivalent to the fence that would be returned from dequeueBuffer().
+ *
+ * @return status Status of the call.
+ * @return buffer Buffer just released from the buffer queue.
+ * @return fence Fence associated to @p buffer.
+ *
+ * @sa dequeueBuffer(), requestBuffer(), detachBuffer().
+ */
+ detachNextBuffer(
+ ) generates (
+ Status status,
+ HardwareBuffer buffer,
+ Fence fence
+ );
+
+ /**
+ * Attempts to transfer ownership of a buffer to the buffer queue.
+ *
+ * If this call succeeds, it shall be as if this buffer was dequeued from the
+ * returned slot index. As such, this call shall fail if attaching this
+ * buffer would cause too many buffers to be simultaneously dequeued.
+ *
+ * If the returned @p releaseAllBuffers is `true`, the caller is expected to
+ * release all of the mirrored slot-to-buffer mappings.
+ *
+ * See dequeueBuffer() for conditions that may cause the call to fail.
+ *
+ * @param buffer Buffer to attach to the buffer queue.
+ * @return status Status of the call.
+ * @return slot Slot index assigned to @p buffer.
+ * @return releaseAllBuffers Whether the caller is expected to release all
+ * of the mirrored slot-to-buffer mappings.
+ *
+ * @sa dequeueBuffer().
+ */
+ attachBuffer(
+ HardwareBuffer buffer
+ ) generates (
+ Status status,
+ int32_t slot,
+ bool releaseAllBuffers
+ );
+
+ struct QueueBufferInput {
+ /**
+ * Timestamp in nanoseconds.
+ */
+ int64_t timestamp;
+ /**
+ * Whether the timestamp was synthesized at queue time.
+ */
+ bool isAutoTimestamp;
+ /**
+ * Dataspace of the contents.
+ *
+ * @sa +ndk libnativewindow#ADataSpace.
+ */
+ int32_t dataSpace;
+ /**
+ * Crop rectangle that is used as a hint to the consumer.
+ */
+ Rect crop;
+ /**
+ * Transformation flags.
+ *
+ * @sa +ndk libnativewindow#ANativeWindowTransform.
+ */
+ int32_t transform;
+ /**
+ * The sticky transform set in Surface (only used by the LEGACY camera
+ * mode).
+ *
+ * @sa +ndk libnativewindow#ANativeWindowTransform.
+ */
+ int32_t stickyTransform;
+ /**
+ * Fence that the consumer must wait on before reading the buffer. An
+ * empty fence indicates that the buffer is ready immediately.
+ */
+ Fence fence;
+ /**
+ * List of rectangular pieces covering the damage region.
+ */
+ vec<Rect> surfaceDamage;
+ };
+
+ /**
+ * Information about the queued buffer. `QueueBufferOutput` is used in both
+ * queueBuffer() and connect().
+ */
+ struct QueueBufferOutput {
+ /**
+ * Default width of a buffer in the buffer queue.
+ */
+ uint32_t width;
+ /**
+ * Default height of a buffer in the buffer queue.
+ */
+ uint32_t height;
+ /**
+ * The transform hint of the buffer queue.
+ *
+ * @sa +ndk libnativewindow#ANativeWindowTransform.
+ */
+ int32_t transformHint;
+ /**
+ * The number of pending buffers in the buffer queue. If this is
+ * returned from queueBuffer(), the number shall include the buffer that
+ * has just been queued.
+ */
+ uint32_t numPendingBuffers;
+ /**
+ * The frame number of the next frame. The buffer queue maintains this
+ * number and makes sure that it is increasing for every successful
+ * queueBuffer() call.
+ */
+ uint64_t nextFrameNumber;
+ /**
+ * After a successful queueBuffer() call, #bufferReplaced shall be set to
+ * true if the queued buffer replaced a previously queued buffer that
+ * has not been consumed.
+ */
+ bool bufferReplaced;
+ };
+
+ /**
+ * Indicates that the client has finished filling in the contents of the
+ * buffer associated with slot and transfers ownership of that slot back to
+ * the buffer queue.
+ *
+ * @p status may be set to `BAD_VALUE` if any of the following conditions
+ * hold:
+ * - The buffer queue is operating in the asynchronous mode, and the
+ * buffer count was smaller than the maximum number of buffers that can
+ * be allocated at once.
+ * - @p slot is an invalid slot index, i.e., the slot is not owned by the
+ * client by previously calling dequeueBuffer(), requestBuffer() or
+ * attachBuffer().
+ * - The crop rectangle is not contained in the buffer.
+ *
+ * Upon success, the output shall be filled with meaningful values
+ * (refer to the documentation of @ref QueueBufferOutput).
+ *
+ * @param slot Slot index.
+ * @param input See @ref QueueBufferInput.
+ * @return status Status of the call.
+ * @return output See @ref QueueBufferOutput.
+ *
+ * @sa #QueueBufferInput, #QueueBufferOutput, dequeueBuffer().
+ */
+ queueBuffer(
+ int32_t slot,
+ QueueBufferInput input
+ ) generates (
+ Status status,
+ QueueBufferOutput output
+ );
+
+ /**
+ * Indicates that the client does not wish to fill in the buffer associated
+ * with the slot and transfers ownership of the slot back to the server. The
+ * buffer is not queued for use by the consumer.
+ *
+ * If @p fence is not an empty fence, the buffer shall not be overwritten
+ * until the fence signals. @p fence is usually obtained from
+ * dequeueBuffer().
+ *
+ * @param slot Slot index.
+ * @param fence Fence for the canceled buffer.
+ * @return status Status of the call.
+ */
+ cancelBuffer(
+ int32_t slot,
+ Fence fence
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Retrieves information for this surface.
+ *
+ * @param what What to query. @p what must be one of the values in
+ * +llndk libnativewindow#ANativeWindowQuery.
+ * @return status Status of the call.
+ * @return value The value queried. The set of possible values depends on
+ * the value of @p what.
+ *
+ * @sa +llndk libnativewindow#ANativeWindowQuery.
+ */
+ query(
+ int32_t what
+ ) generates (
+ int32_t result,
+ int32_t value
+ );
+
+ /**
+ * Attempts to connect the client as a producer of the buffer queue.
+ * This method must be called before any other methods in this interface.
+ *
+ * If the buffer queue does not have a consumer ready (connected), the
+ * return @p status shall be `NO_INIT`.
+ *
+ * If any of the following conditions hold, the error code `BAD_VALUE` shall
+ * be reported in @p status:
+ * - The producer is already connected.
+ * - The number of available slots cannot be adjusted to accommodate the
+ * supplied value of @p producerControlledByApp.
+ *
+ * @param listener An optional callback object that can be provided if the
+ * client wants to be notified when the consumer releases a buffer back
+ * to the buffer queue.
+ * @param api How the client shall write to buffers.
+ * @param producerControlledByApp `true` if the producer is hosted by an
+ * untrusted process (typically application-forked processes). If both
+ * the producer and the consumer are controlled by app, the buffer queue
+ * shall operate in the asynchronous mode regardless of the async flag
+ * set by setAsyncMode().
+ * @return status Status of the call.
+ * @return output See #QueueBufferOutput for more information.
+ *
+ * @sa #QueueBufferOutput, disconnect(), setAsyncMode().
+ */
+ connect(
+ IProducerListener listener,
+ ConnectionType api,
+ bool producerControlledByApp
+ ) generates (
+ Status status,
+ QueueBufferOutput output
+ );
+
+ /**
+ * Attempts to disconnect the client from the producer end of the buffer
+ * queue.
+ *
+ * Calling this method shall cause any subsequent calls to other
+ * @ref IGraphicBufferProducer methods apart from connect() to fail.
+ * A successful connect() call afterwards may allow other methods to succeed
+ * again.
+ *
+ * Disconnecting from an abandoned buffer queue is legal and is considered a
+ * no-op.
+ *
+ * @param api The type of connection to disconnect. Supplying the value of
+ * `CURRENTLY_CONNECTED` to @p api has the same effect as supplying the
+ * current connection type. If the producer end is not connected,
+ * supplying `CURRENTLY_CONNECTED` shall result in a successful no-op
+ * call.
+ * @return status Status of the call.
+ *
+ * @sa connect().
+ */
+ disconnect(
+ ConnectionType api
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Allocates buffers based on the given dimensions, format and usage.
+ *
+ * This function shall allocate up to the maximum number of buffers
+ * permitted by the current buffer queue configuration. It shall use the
+ * given format, dimensions, and usage bits, which are interpreted in the
+ * same way as for dequeueBuffer(), and the async flag must be set the same
+ * way as for dequeueBuffer() to ensure that the correct number of buffers
+ * are allocated. This is most useful to avoid an allocation delay during
+ * dequeueBuffer(). If there are already the maximum number of buffers
+ * allocated, this function has no effect.
+ *
+ * A value of 0 in @p width, @p height or @p format indicates that the
+ * buffer queue can pick the default value.
+ *
+ * @param width Width of buffers to allocate.
+ * @param height Height of buffers to allocate.
+ * @param format Format of buffers to allocate.
+ * @param usage Usage of bufferes to allocate.
+ * @return status Status of the call.
+ */
+ allocateBuffers(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ uint64_t usage
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Sets whether dequeueBuffer() is allowed to allocate new buffers.
+ *
+ * Normally dequeueBuffer() does not discriminate between free slots which
+ * already have an allocated buffer and those which do not, and shall
+ * allocate a new buffer if the slot doesn't have a buffer or if the slot's
+ * buffer doesn't match the requested size, format, or usage. This method
+ * allows the producer to restrict the eligible slots to those which already
+ * have an allocated buffer of the correct size, format, and usage. If no
+ * eligible slot is available, dequeueBuffer() shall block or return an
+ * error.
+ *
+ * @param allow Whether to allow new buffers to be allocated in
+ * dequeueBuffer().
+ * @return status Status of the call.
+ */
+ allowAllocation(
+ bool allow
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Sets the current generation number of the buffer queue.
+ *
+ * This generation number shall be inserted into any buffers allocated by the
+ * buffer queue, and any attempts to attach a buffer with a different
+ * generation number shall fail. Buffers already in the queue are not
+ * affected and shall retain their current generation number. The generation
+ * number defaults to 0, i.e., buffers allocated before the first call to
+ * setGenerationNumber() shall be given 0 as their generation numbers.
+ *
+ * @param generationNumber New generation number. The client must make sure
+ * that @p generationNumber is different from the previous generation
+ * number if it wants to deprecate old buffers.
+ * @return status Status of the call.
+ */
+ setGenerationNumber(
+ uint32_t generationNumber
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Sets how long dequeueBuffer() shall wait for a buffer to become available
+ * before returning an error `TIMED_OUT`.
+ *
+ * This timeout also affects the attachBuffer() call, which shall block if
+ * there is not a free slot available into which the attached buffer can be
+ * placed.
+ *
+ * By default, the buffer queue shall wait forever, which is equivalent to
+ * setting @p timeoutNs equal to any negative number (such as `-1`). If
+ * @p timeoutNs is non-negative, setDequeueTimeout() shall disable
+ * non-blocking mode and its corresponding spare buffer (which is used to
+ * ensure a buffer is always available).
+ *
+ * Changing the dequeue timeout may affect the number of buffers. (See
+ * setAsyncMode().) If the adjustment to the number of buffers inside the
+ * buffer queue is not feasible, @p status shall be set to `BAD_VALUE`.
+ *
+ * @param timeoutNs Amount of time dequeueBuffer() is allowed to block
+ * before returning `TIMED_OUT`. If @p timeoutNs is negative,
+ * dequeueBuffer() shall not be able to return `TIMED_OUT`. Instead, it
+ * may block forever or return `WOULD_BLOCK`.
+ * @return status Status of the call.
+ *
+ * @sa dequeueBuffer(), setAsyncMode(), query().
+ */
+ setDequeueTimeout(
+ int64_t timeoutNs
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Returns a unique id for this buffer queue.
+ *
+ * @return id System-wide unique id of the buffer queue.
+ */
+ getUniqueId(
+ ) generates (
+ uint64_t id
+ );
+
+ /**
+ * Returns the name of the connected consumer.
+ *
+ * \note This is used for debugging only.
+ *
+ * @return name Name of the consumer.
+ */
+ getConsumerName(
+ ) generates (
+ string name
+ );
+
+};
+
diff --git a/graphics/bufferqueue/2.0/IProducerListener.hal b/graphics/bufferqueue/2.0/IProducerListener.hal
new file mode 100644
index 0000000..bc478ed
--- /dev/null
+++ b/graphics/bufferqueue/2.0/IProducerListener.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.graphics.bufferqueue@2.0;
+
+/**
+ * Listener interface.
+ */
+interface IProducerListener {
+ /**
+ * Notifies the listener when buffers are released.
+ *
+ * This function is usually called by the consumer.
+ *
+ * @param count The number of buffers released (since the last call to
+ * onBufferReleased()).
+ */
+ oneway onBuffersReleased(uint32_t count);
+};
+
diff --git a/graphics/bufferqueue/2.0/types.hal b/graphics/bufferqueue/2.0/types.hal
new file mode 100644
index 0000000..f6bc2d9
--- /dev/null
+++ b/graphics/bufferqueue/2.0/types.hal
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.graphics.bufferqueue@2.0;
+
+/**
+ * Possible return values from a function call.
+ */
+enum Status : int32_t {
+ /**
+ * The call succeeds.
+ */
+ OK = 0,
+ /**
+ * The function fails allocate memory.
+ */
+ NO_MEMORY = -12,
+ /**
+ * The buffer queue has been abandoned, no consumer is connected, or no
+ * producer is connected at the time of the call.
+ */
+ NO_INIT = -19,
+ /**
+ * Some of the provided input arguments are invalid.
+ */
+ BAD_VALUE = -22,
+ /**
+ * An unexpected death of some object prevents the operation from
+ * continuing.
+ *
+ * @note This status value is different from a transaction failure, which
+ * should be detected by isOk().
+ */
+ DEAD_OBJECT = -32,
+ /**
+ * The internal state of the buffer queue does not permit the operation.
+ */
+ INVALID_OPERATION = -38,
+ /**
+ * The call fails to finish within the specified time limit.
+ */
+ TIMED_OUT = -110,
+ /**
+ * The buffer queue is operating in a non-blocking mode, but the call cannot
+ * be completed without blocking.
+ */
+ WOULD_BLOCK = 0xfffffffb,
+ /**
+ * The call fails because of a reason not listed above.
+ */
+ UNKNOWN_ERROR = 0xffffffff,
+};
+
+/**
+ * Special values for a slot index.
+ */
+enum SlotIndex : int32_t {
+ /**
+ * Invalid/unspecified slot index. This may be returned from a function that
+ * returns a slot index if the call is unsuccessful.
+ */
+ INVALID = -1,
+ UNSPECIFIED = -1,
+};
+
+/**
+ * An "empty" fence can be an empty handle (containing no fds and no ints) or a
+ * fence with one fd that is equal to -1 and no ints.
+ *
+ * A valid fence is an empty fence or a native handle with exactly one fd and no
+ * ints.
+ */
+typedef handle Fence;
+
+/**
+ * How buffers shall be produced. One of these values must be provided in a call
+ * to IGraphicBufferProducer::connect() and
+ * IGraphicBufferProducer::disconnect().
+ */
+enum ConnectionType : int32_t {
+ /**
+ * This value can be used only as an input to
+ * IGraphicBufferProducer::disconnect().
+ */
+ CURRENTLY_CONNECTED = -1,
+ /**
+ * Buffers shall be queued by EGL via `eglSwapBuffers()` after being filled
+ * using OpenGL ES.
+ */
+ EGL = 1,
+ /**
+ * Buffers shall be queued after being filled using the CPU.
+ */
+ CPU = 2,
+ /**
+ * Buffers shall be queued by Stagefright after being filled by a video
+ * decoder. The video decoder can either be a software or hardware decoder.
+ */
+ MEDIA = 3,
+ /**
+ * Buffers shall be queued by the camera HAL.
+ */
+ CAMERA = 4,
+};
+
+
diff --git a/graphics/common/1.2/Android.bp b/graphics/common/1.2/Android.bp
new file mode 100644
index 0000000..a3ebdbf
--- /dev/null
+++ b/graphics/common/1.2/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.common@1.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ ],
+ types: [
+ "ColorMode",
+ "Dataspace",
+ "HardwareBuffer",
+ ],
+ gen_java: true,
+ gen_java_constants: true,
+}
+
diff --git a/graphics/common/1.2/types.hal b/graphics/common/1.2/types.hal
new file mode 100644
index 0000000..15f2c14
--- /dev/null
+++ b/graphics/common/1.2/types.hal
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.graphics.common@1.2;
+
+import @1.1::BufferUsage;
+import @1.1::ColorMode;
+import @1.1::Dataspace;
+import @1.1::PixelFormat;
+
+@export(name="android_dataspace_v1_2_t", value_prefix="HAL_DATASPACE_",
+ export_parent="false")
+enum Dataspace : @1.1::Dataspace {
+ /**
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, sRGB transfer and BT2020 standard
+ */
+ DISPLAY_BT2020 = STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL,
+};
+
+enum ColorMode : @1.1::ColorMode {
+ /**
+ * DISPLAY_BT2020 corresponds with display settings that implement the ITU-R
+ * Recommendation BT.2020 / Rec. 2020 for UHDTV, but specifies an SRGB
+ * transfer function.
+ *
+ * Primaries:
+ * x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Transfer Function is sRGB
+ */
+ DISPLAY_BT2020 = 13,
+};
+
+/**
+ * HIDL counterpart of `AHardwareBuffer_Desc`.
+ *
+ * An `AHardwareBuffer_Desc` object can be converted to and from a
+ * `HardwareBufferDescription` object by `memcpy()`.
+ *
+ * @sa +ndk libnativewindow#AHardwareBuffer_Desc.
+ */
+typedef uint32_t[10] HardwareBufferDescription;
+
+/**
+ * HIDL counterpart of `AHardwareBuffer`.
+ *
+ * AHardwareBuffer_createFromHandle() can be used to convert a `HardwareBuffer`
+ * object to an `AHardwareBuffer` object.
+ *
+ * Conversely, AHardwareBuffer_getNativeHandle() can be used to extract a native
+ * handle from an `AHardwareBuffer` object. Paired with `AHardwareBuffer_Desc`,
+ * AHardwareBuffer_getNativeHandle() can be used to convert between
+ * `HardwareBuffer` and `AHardwareBuffer`.
+ *
+ * @sa +ndk libnativewindow#AHardwareBuffer".
+ */
+struct HardwareBuffer {
+ HardwareBufferDescription description;
+ handle nativeHandle;
+};
+
+/**
+ * HIDL counterpart of `ARect`.
+ *
+ * @sa +ndk libarect_headers#ARect.
+ */
+typedef int32_t[4] Rect;
+
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
index 2cbf044..f249f1a 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
@@ -186,6 +186,8 @@
: mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
+ virtual ~ComposerLayerResource() = default;
+
Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
@@ -211,6 +213,8 @@
VIRTUAL,
};
+ virtual ~ComposerDisplayResource() = default;
+
ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
uint32_t outputBufferCacheSize)
: mType(type),
diff --git a/graphics/composer/2.3/Android.bp b/graphics/composer/2.3/Android.bp
index 78da099..6d29348 100644
--- a/graphics/composer/2.3/Android.bp
+++ b/graphics/composer/2.3/Android.bp
@@ -13,6 +13,7 @@
interfaces: [
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hidl.base@1.0",
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
index 089438e..7856658 100644
--- a/graphics/composer/2.3/IComposerClient.hal
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -16,6 +16,10 @@
package android.hardware.graphics.composer@2.3;
+import android.hardware.graphics.common@1.1::RenderIntent;
+import android.hardware.graphics.common@1.1::PixelFormat;
+import android.hardware.graphics.common@1.2::ColorMode;
+import android.hardware.graphics.common@1.2::Dataspace;
import android.hardware.graphics.composer@2.1::IComposerClient.Command;
import @2.2::IComposerClient;
import @2.1::Display;
@@ -87,6 +91,185 @@
generates (Error error,
uint8_t port,
vec<uint8_t> data);
+ /**
+ * getReadbackBufferAttributes_2_3
+ * Returns the format which should be used when allocating a buffer for use by
+ * device readback as well as the dataspace in which its contents must be
+ * interpreted.
+ *
+ * The width and height of this buffer must be those of the currently-active
+ * display configuration, and the usage flags must consist of the following:
+ * BufferUsage::CPU_READ | BufferUsage::GPU_TEXTURE |
+ * BufferUsage::COMPOSER_OUTPUT
+ *
+ * The format and dataspace provided must be sufficient such that if a
+ * correctly-configured buffer is passed into setReadbackBuffer, filled by
+ * the device, and then displayed by the client as a full-screen buffer, the
+ * output of the display remains the same (subject to the note about protected
+ * content in the description of setReadbackBuffer).
+ *
+ * If the active configuration or color mode of this display has changed
+ * since a previous call to this function, it must be called again prior to
+ * setting a readback buffer such that the returned format and dataspace will
+ * be updated accordingly.
+ *
+ * Parameters:
+ * @param display - the display on which to create the layer.
+ *
+ * @return format - the format the client should use when allocating a device
+ * readback buffer
+ * @return dataspace - the dataspace to use when interpreting the
+ * contents of a device readback buffer
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * UNSUPPORTED if not supported on underlying HAL
+ *
+ * See also:
+ * setReadbackBuffer
+ * getReadbackBufferFence
+ */
+ getReadbackBufferAttributes_2_3(Display display)
+ generates (Error error,
+ PixelFormat format,
+ Dataspace dataspace);
+
+ /**
+ * getClientTargetSupport_2_3
+ * Returns whether a client target with the given properties can be
+ * handled by the device.
+ *
+ * This function must return true for a client target with width and
+ * height equal to the active display configuration dimensions,
+ * PixelFormat::RGBA_8888, and Dataspace::UNKNOWN. It is not required to
+ * return true for any other configuration.
+ *
+ * @param display is the display to query.
+ * @param width is the client target width in pixels.
+ * @param height is the client target height in pixels.
+ * @param format is the client target format.
+ * @param dataspace is the client target dataspace, as described in
+ * setLayerDataspace.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * UNSUPPORTED when the given configuration is not supported.
+ */
+ @callflow(next="*")
+ getClientTargetSupport_2_3(Display display,
+ uint32_t width,
+ uint32_t height,
+ PixelFormat format,
+ Dataspace dataspace)
+ generates (Error error);
+
+ enum FormatColorComponent : uint8_t {
+ /* The first component (eg, for RGBA_8888, this is R) */
+ FORMAT_COMPONENT_0 = 1 << 0,
+ /* The second component (eg, for RGBA_8888, this is G) */
+ FORMAT_COMPONENT_1 = 1 << 1,
+ /* The third component (eg, for RGBA_8888, this is B) */
+ FORMAT_COMPONENT_2 = 1 << 2,
+ /* The fourth component (eg, for RGBA_8888, this is A) */
+ FORMAT_COMPONENT_3 = 1 << 3,
+ };
+
+ /**
+ * Query for what types of color sampling the hardware supports.
+ *
+ * @param display is the display where the samples are collected.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display was passed in, or
+ * UNSUPPORTED when there is no efficient way to sample.
+ * @return format The format of the sampled pixels.
+ * @return dataspace The dataspace of the sampled pixels.
+ * @return componentMask The mask of which components can be sampled.
+ */
+ getDisplayedContentSamplingAttributes(Display display)
+ generates (Error error,
+ PixelFormat format,
+ Dataspace dataspace,
+ bitfield<FormatColorComponent> componentMask);
+
+ /** DisplayedContentSampling values passed to setDisplayedContentSamplingEnabled. */
+ enum DisplayedContentSampling : int32_t {
+ INVALID = 0,
+
+ /** Enable content sampling. */
+ ENABLE = 1,
+
+ /** Disable content sampling. */
+ DISABLE = 2,
+ };
+
+ /**
+ * Enables or disables the collection of color content statistics
+ * on this display.
+ *
+ * Sampling occurs on the contents of the final composition on this display
+ * (i.e., the contents presented on screen). Samples should be collected after all
+ * color transforms have been applied.
+ *
+ * Sampling support is optional, and is set to DISABLE by default.
+ * On each call to ENABLE, all collected statistics must be reset.
+ *
+ * Sample data can be queried via getDisplayedContentSample().
+ *
+ * @param display is the display to which the sampling mode is set.
+ * @param enabled indicates whether to enable or disable sampling.
+ * @param componentMask The mask of which components should be sampled. If zero, all supported
+ * components are to be enabled.
+ * @param maxFrames is the maximum number of frames that should be stored before discard.
+ * The sample represents the most-recently posted frames.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in,
+ * BAD_PARAMETER when enabled was an invalid value, or
+ * NO_RESOURCES when the requested ringbuffer size via maxFrames was
+ * not available.
+ * UNSUPPORTED when there is no efficient way to sample.
+ */
+ setDisplayedContentSamplingEnabled(
+ Display display, DisplayedContentSampling enable,
+ bitfield<FormatColorComponent> componentMask, uint64_t maxFrames)
+ generates (Error error);
+
+ /**
+ * Collects the results of display content color sampling for display.
+ *
+ * Collection of data can occur whether the sampling is in ENABLE or
+ * DISABLE state.
+ *
+ * @param display is the display to which the sampling is collected.
+ * @param maxFrames is the maximum number of frames that should be represented in the sample.
+ * The sample represents the most-recently posted frames.
+ * If maxFrames is 0, all frames are to be represented by the sample.
+ * @param timestamp is the timestamp after which any frames were posted that should be
+ * included in the sample. Timestamp is CLOCK_MONOTONIC.
+ * If timestamp is 0, do not filter from the sample by time.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display was passed in, or
+ * UNSUPPORTED when there is no efficient way to sample, or
+ * BAD_PARAMETER when the component is not supported by the hardware.
+ * @return frameCount The number of frames represented by this sample.
+ * @return sampleComponent0 is a histogram counting how many times a pixel of a given value
+ * was displayed onscreen for FORMAT_COMPONENT_0.
+ * The buckets of the histogram are evenly weighted, the number of buckets
+ * is device specific.
+ * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that
+ * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels
+ * were displayed onscreen in range 0x40->0x7F, etc.
+ * @return sampleComponent1 is the same sample definition as sampleComponent0,
+ * but for FORMAT_COMPONENT_1.
+ * @return sampleComponent2 is the same sample definition as sampleComponent0,
+ * but for FORMAT_COMPONENT_2.
+ * @return sampleComponent3 is the same sample definition as sampleComponent0,
+ * but for FORMAT_COMPONENT_3.
+ */
+ getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp)
+ generates (Error error,
+ uint64_t frameCount,
+ vec<uint64_t> sampleComponent0,
+ vec<uint64_t> sampleComponent1,
+ vec<uint64_t> sampleComponent2,
+ vec<uint64_t> sampleComponent3);
/**
* Executes commands from the input command message queue. Return values
@@ -113,4 +296,58 @@
bool outQueueChanged,
uint32_t outLength,
vec<handle> outHandles);
+
+ /**
+ * Returns the render intents supported by the specified display and color
+ * mode.
+ *
+ * For SDR color modes, RenderIntent::COLORIMETRIC must be supported. For
+ * HDR color modes, RenderIntent::TONE_MAP_COLORIMETRIC must be supported.
+ *
+ * @param display is the display to query.
+ * @param mode is the color mode to query.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_PARAMETER when an invalid color mode was passed in.
+ * @return intents is an array of render intents.
+ */
+ getRenderIntents_2_3(Display display, ColorMode mode)
+ generates (Error error,
+ vec<RenderIntent> intents);
+
+ /**
+ * Returns the color modes supported on this display.
+ *
+ * All devices must support at least ColorMode::NATIVE.
+ *
+ * @param display is the display to query.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return modes is an array of color modes.
+ */
+ getColorModes_2_3(Display display)
+ generates (Error error,
+ vec<ColorMode> modes);
+
+ /**
+ * Sets the color mode and render intent of the given display.
+ *
+ * The color mode and render intent change must take effect on next
+ * presentDisplay.
+ *
+ * All devices must support at least ColorMode::NATIVE and
+ * RenderIntent::COLORIMETRIC, and displays are assumed to be in this mode
+ * upon hotplug.
+ *
+ * @param display is the display to which the color mode is set.
+ * @param mode is the color mode to set to.
+ * @param intent is the render intent to set to.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_PARAMETER when mode or intent is invalid
+ * UNSUPPORTED when mode or intent is not supported on this
+ * display.
+ */
+ setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent)
+ generates (Error error);
};
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index 3f7b2c9..6c95a1f 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -34,6 +34,7 @@
namespace V2_3 {
using android::hardware::MessageQueue;
+using android::hardware::graphics::common::V1_2::Dataspace;
using android::hardware::graphics::composer::V2_1::Error;
using android::hardware::graphics::composer::V2_1::IComposerCallback;
using android::hardware::graphics::composer::V2_1::Layer;
@@ -43,6 +44,16 @@
// units of uint32_t's.
class CommandWriterBase : public V2_2::CommandWriterBase {
public:
+ void setLayerDataspace(Dataspace dataspace) {
+ setLayerDataspaceInternal(static_cast<int32_t>(dataspace));
+ }
+
+ void setClientTarget(uint32_t slot, const native_handle_t* target, int acquireFence,
+ Dataspace dataspace, const std::vector<IComposerClient::Rect>& damage) {
+ setClientTargetInternal(slot, target, acquireFence, static_cast<int32_t>(dataspace),
+ damage);
+ }
+
CommandWriterBase(uint32_t initialMaxSize) : V2_2::CommandWriterBase(initialMaxSize) {}
static constexpr uint16_t kSetLayerColorTransformLength = 16;
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index c805472..be0ef4c 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -38,6 +38,41 @@
template <typename Interface, typename Hal>
class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interface, Hal> {
public:
+ Return<Error> setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override {
+ return mHal->setColorMode_2_3(display, mode, intent);
+ }
+
+ Return<void> getRenderIntents_2_3(Display display, ColorMode mode,
+ IComposerClient::getRenderIntents_2_3_cb hidl_cb) override {
+ std::vector<RenderIntent> intents;
+ Error err = mHal->getRenderIntents_2_3(display, mode, &intents);
+ hidl_cb(err, intents);
+ return Void();
+ }
+
+ Return<void> getColorModes_2_3(Display display,
+ IComposerClient::getColorModes_2_3_cb hidl_cb) override {
+ hidl_vec<ColorMode> modes;
+ Error err = mHal->getColorModes_2_3(display, &modes);
+ hidl_cb(err, modes);
+ return Void();
+ }
+
+ Return<void> getReadbackBufferAttributes_2_3(
+ Display display, IComposerClient::getReadbackBufferAttributes_2_3_cb hidl_cb) override {
+ PixelFormat format = PixelFormat::RGB_888;
+ Dataspace dataspace = Dataspace::UNKNOWN;
+ Error error = mHal->getReadbackBufferAttributes_2_3(display, &format, &dataspace);
+ hidl_cb(error, format, dataspace);
+ return Void();
+ }
+
+ Return<Error> getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override {
+ Error err = mHal->getClientTargetSupport_2_3(display, width, height, format, dataspace);
+ return err;
+ }
+
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
auto client = std::make_unique<ComposerClientImpl>(hal);
return client->init() ? std::move(client) : nullptr;
@@ -56,6 +91,42 @@
return Void();
}
+ Return<void> getDisplayedContentSamplingAttributes(
+ uint64_t display,
+ IComposerClient::getDisplayedContentSamplingAttributes_cb hidl_cb) override {
+ common::V1_1::PixelFormat format;
+ common::V1_2::Dataspace dataspace;
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask;
+ Error error =
+ mHal->getDisplayedContentSamplingAttributes(display, format, dataspace, componentMask);
+ hidl_cb(error, format, dataspace, componentMask);
+ return Void();
+ }
+
+ Return<Error> setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) override {
+ return mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
+ }
+
+ Return<void> getDisplayedContentSample(
+ uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+ IComposerClient::getDisplayedContentSample_cb hidl_cb) override {
+ uint64_t frameCount;
+ hidl_vec<uint64_t> sampleComponent0;
+ hidl_vec<uint64_t> sampleComponent1;
+ hidl_vec<uint64_t> sampleComponent2;
+ hidl_vec<uint64_t> sampleComponent3;
+
+ Error error = mHal->getDisplayedContentSample(display, maxFrames, timestamp, frameCount,
+ sampleComponent0, sampleComponent1,
+ sampleComponent2, sampleComponent3);
+ hidl_cb(error, frameCount, sampleComponent0, sampleComponent1, sampleComponent2,
+ sampleComponent3);
+ return Void();
+ }
+
Return<void> executeCommands_2_3(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
IComposerClient::executeCommands_2_2_cb hidl_cb) override {
std::lock_guard<std::mutex> lock(mCommandEngineMutex);
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
index 0f6205a..8ca5d75 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
@@ -25,15 +25,65 @@
namespace V2_3 {
namespace hal {
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
using V2_1::Display;
using V2_1::Error;
using V2_1::Layer;
class ComposerHal : public V2_2::hal::ComposerHal {
public:
+ Error setColorMode_2_2(Display display, common::V1_1::ColorMode mode,
+ RenderIntent intent) override {
+ return setColorMode_2_3(display, static_cast<ColorMode>(mode), intent);
+ }
+
+ Error getColorModes_2_2(Display display, hidl_vec<common::V1_1::ColorMode>* outModes) override {
+ return getColorModes_2_3(display, reinterpret_cast<hidl_vec<ColorMode>*>(outModes));
+ }
+
+ Error getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
+ common::V1_1::PixelFormat format,
+ common::V1_1::Dataspace dataspace) override {
+ return getClientTargetSupport_2_3(display, width, height, static_cast<PixelFormat>(format),
+ static_cast<Dataspace>(dataspace));
+ }
+
+ Error getReadbackBufferAttributes(Display display, common::V1_1::PixelFormat* outFormat,
+ common::V1_1::Dataspace* outDataspace) override {
+ return getReadbackBufferAttributes_2_3(display, reinterpret_cast<PixelFormat*>(outFormat),
+ reinterpret_cast<Dataspace*>(outDataspace));
+ }
+
+ virtual Error setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) = 0;
+
+ virtual Error getRenderIntents_2_3(Display display, ColorMode mode,
+ std::vector<RenderIntent>* outIntents) = 0;
+
+ virtual Error getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) = 0;
+
+ virtual Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) = 0;
+ virtual Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace) = 0;
+
virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData) = 0;
virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0;
+ virtual Error getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) = 0;
+ virtual Error setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) = 0;
+ virtual Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
+ uint64_t timestamp, uint64_t& frameCount,
+ hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index ed1878b..8d444c8 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -34,6 +34,10 @@
namespace detail {
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
using V2_1::Display;
using V2_1::Error;
@@ -41,6 +45,32 @@
template <typename Hal>
class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
public:
+ Error setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override {
+ return setColorMode_2_2(display, static_cast<common::V1_1::ColorMode>(mode), intent);
+ }
+
+ Error getRenderIntents_2_3(Display display, ColorMode mode,
+ std::vector<RenderIntent>* outIntents) override {
+ return getRenderIntents(display, static_cast<common::V1_1::ColorMode>(mode), outIntents);
+ }
+
+ Error getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) override {
+ return getColorModes_2_2(display,
+ reinterpret_cast<hidl_vec<common::V1_1::ColorMode>*>(outModes));
+ }
+
+ Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override {
+ return getClientTargetSupport_2_2(display, width, height, format,
+ static_cast<common::V1_1::Dataspace>(dataspace));
+ }
+
+ Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace) override {
+ return getReadbackBufferAttributes(
+ display, outFormat, reinterpret_cast<common::V1_1::Dataspace*>(outDataspace));
+ }
+
Error getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData) override {
if (!mDispatch.getDisplayIdentificationData) {
@@ -74,6 +104,65 @@
return static_cast<Error>(err);
}
+ Error getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) override {
+ if (!mDispatch.getDisplayedContentSamplingAttributes) {
+ return Error::UNSUPPORTED;
+ }
+ int32_t formatRaw = 0;
+ int32_t dataspaceRaw = 0;
+ uint8_t componentMaskRaw = 0;
+ int32_t errorRaw = mDispatch.getDisplayedContentSamplingAttributes(
+ mDevice, display, &formatRaw, &dataspaceRaw, &componentMaskRaw);
+ auto error = static_cast<Error>(errorRaw);
+ if (error == Error::NONE) {
+ format = static_cast<PixelFormat>(formatRaw);
+ dataspace = static_cast<Dataspace>(dataspaceRaw);
+ componentMask =
+ static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(componentMaskRaw);
+ }
+ return error;
+ };
+
+ Error setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) override {
+ if (!mDispatch.setDisplayedContentSamplingEnabled) {
+ return Error::UNSUPPORTED;
+ }
+ return static_cast<Error>(mDispatch.setDisplayedContentSamplingEnabled(
+ mDevice, display, static_cast<int32_t>(enable), componentMask, maxFrames));
+ }
+
+ Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+ uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) override {
+ if (!mDispatch.getDisplayedContentSample) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t size[4] = {0};
+ auto errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
+ &frameCount, size, nullptr);
+ if (errorRaw != HWC2_ERROR_NONE) {
+ return static_cast<Error>(errorRaw);
+ }
+
+ sampleComponent0.resize(size[0]);
+ sampleComponent1.resize(size[1]);
+ sampleComponent2.resize(size[2]);
+ sampleComponent3.resize(size[3]);
+ uint64_t* samples[] = {sampleComponent0.data(), sampleComponent1.data(),
+ sampleComponent2.data(), sampleComponent3.data()};
+ errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
+ &frameCount, size, samples);
+ return static_cast<Error>(errorRaw);
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_2::initDispatch()) {
@@ -84,6 +173,12 @@
&mDispatch.getDisplayIdentificationData);
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
&mDispatch.setLayerColorTransform);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
+ &mDispatch.getDisplayedContentSamplingAttributes);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED,
+ &mDispatch.setDisplayedContentSamplingEnabled);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE,
+ &mDispatch.getDisplayedContentSample);
return true;
}
@@ -91,11 +186,19 @@
struct {
HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
+ HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES getDisplayedContentSamplingAttributes;
+ HWC2_PFN_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED setDisplayedContentSamplingEnabled;
+ HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLE getDisplayedContentSample;
} mDispatch = {};
using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
using BaseType2_1::mDevice;
+ using BaseType2_2::getClientTargetSupport_2_2;
+ using BaseType2_2::getColorModes_2_2;
+ using BaseType2_2::getReadbackBufferAttributes;
+ using BaseType2_2::getRenderIntents;
+ using BaseType2_2::setColorMode_2_2;
};
} // namespace detail
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index f1d3a50..9304992 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -45,6 +45,10 @@
return client;
}
+sp<IComposerClient> ComposerClient::getRaw() const {
+ return mClient;
+}
+
bool ComposerClient::getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData) {
bool supported = true;
@@ -64,6 +68,88 @@
return supported;
}
+std::vector<ColorMode> ComposerClient::getColorModes_2_3(Display display) {
+ std::vector<ColorMode> modes;
+ mClient->getColorModes_2_3(display, [&](const auto& tmpError, const auto& tmpModes) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get color modes";
+ modes = tmpModes;
+ });
+ return modes;
+}
+
+void ComposerClient::setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) {
+ Error error = mClient->setColorMode_2_3(display, mode, intent);
+ ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set color mode";
+}
+
+std::vector<RenderIntent> ComposerClient::getRenderIntents_2_3(Display display, ColorMode mode) {
+ std::vector<RenderIntent> intents;
+ mClient->getRenderIntents_2_3(display, mode, [&](const auto& tmpError, const auto& tmpIntents) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents";
+ intents = tmpIntents;
+ });
+ return intents;
+}
+
+void ComposerClient::getReadbackBufferAttributes_2_3(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace) {
+ mClient->getReadbackBufferAttributes_2_3(
+ display,
+ [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
+ *outPixelFormat = tmpOutPixelFormat;
+ *outDataspace = tmpOutDataspace;
+ });
+}
+
+bool ComposerClient::getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) {
+ Error error = mClient->getClientTargetSupport_2_3(display, width, height, format, dataspace);
+ return error == Error::NONE;
+}
+
+Error ComposerClient::getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
+ auto error = Error::BAD_PARAMETER;
+ mClient->getDisplayedContentSamplingAttributes(
+ display, [&](const auto& tmpError, const auto& tmpFormat, const auto& tmpDataspace,
+ const auto& tmpComponentMask) {
+ error = tmpError;
+ format = tmpFormat;
+ dataspace = tmpDataspace;
+ componentMask = tmpComponentMask;
+ });
+ return error;
+}
+
+Error ComposerClient::setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) {
+ return mClient->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
+}
+
+Error ComposerClient::getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
+ uint64_t timestamp, uint64_t& frameCount,
+ hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) {
+ auto error = Error::BAD_PARAMETER;
+ mClient->getDisplayedContentSample(
+ display, maxFrames, timestamp,
+ [&](const auto& tmpError, const auto& tmpFrameCount, const auto& tmpSamples0,
+ const auto& tmpSamples1, const auto& tmpSamples2, const auto& tmpSamples3) {
+ error = tmpError;
+ frameCount = tmpFrameCount;
+ sampleComponent0 = tmpSamples0;
+ sampleComponent1 = tmpSamples1;
+ sampleComponent2 = tmpSamples2;
+ sampleComponent3 = tmpSamples3;
+ });
+ return error;
+}
+
} // namespace vts
} // namespace V2_3
} // namespace composer
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index 103b85a..4b9c955 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -32,7 +32,12 @@
namespace V2_3 {
namespace vts {
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
using V2_1::Display;
+using V2_1::Error;
using V2_3::IComposer;
using V2_3::IComposerClient;
@@ -59,8 +64,33 @@
explicit ComposerClient(const sp<IComposerClient>& client)
: V2_2::vts::ComposerClient(client), mClient(client) {}
+ sp<IComposerClient> getRaw() const;
+
bool getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData);
+ Error getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask);
+ Error setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames);
+ Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+ uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3);
+
+ std::vector<ColorMode> getColorModes_2_3(Display display);
+
+ void setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent);
+
+ std::vector<RenderIntent> getRenderIntents_2_3(Display display, ColorMode mode);
+
+ void getReadbackBufferAttributes_2_3(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace);
+
+ bool getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace);
private:
const sp<IComposerClient> mClient;
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index 1030ddc..a294825 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -33,6 +33,11 @@
namespace vts {
namespace {
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+
// Test environment for graphics.composer
class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -64,6 +69,8 @@
// assume the first display is primary and is never removed
mPrimaryDisplay = waitForFirstDisplay();
+ mInvalidDisplayId = GetInvalidDisplayId();
+
// explicitly disable vsync
mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
mComposerCallback->setVsyncAllowed(false);
@@ -80,6 +87,22 @@
}
}
+ // 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
+ Display GetInvalidDisplayId() {
+ std::vector<Display> validDisplays = mComposerCallback->getDisplays();
+ uint64_t id = std::numeric_limits<uint64_t>::max();
+ while (id > 0) {
+ if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+ return id;
+ }
+ id--;
+ }
+
+ return 0;
+ }
+
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
// use the slot count usually set by SF
@@ -90,6 +113,7 @@
sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
// the first display and is assumed never to be removed
Display mPrimaryDisplay;
+ Display mInvalidDisplayId;
std::unique_ptr<CommandWriterBase> mWriter;
std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
@@ -128,6 +152,185 @@
}
/**
+ * TestIComposerClient::getReadbackBufferAttributes_2_3
+ */
+TEST_F(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) {
+ Dataspace dataspace;
+ PixelFormat pixelFormat;
+
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferAttributes_2_3(
+ mPrimaryDisplay, &pixelFormat, &dataspace));
+}
+
+/**
+ * Test IComposerClient::getClientTargetSupport_2_3
+ */
+TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) {
+ std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+ IComposerClient::Attribute::WIDTH);
+ int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+ IComposerClient::Attribute::HEIGHT);
+ ASSERT_LT(0, width);
+ ASSERT_LT(0, height);
+
+ mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+
+ ASSERT_TRUE(mComposerClient->getClientTargetSupport_2_3(
+ mPrimaryDisplay, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN));
+ }
+}
+/**
+ * Test IComposerClient::getClientTargetSupport_2_3
+ *
+ * Test that IComposerClient::getClientTargetSupport_2_3 returns
+ * Error::BAD_DISPLAY when passed in an invalid display handle
+ */
+
+TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) {
+ std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+ IComposerClient::Attribute::WIDTH);
+ int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+ IComposerClient::Attribute::HEIGHT);
+ ASSERT_LT(0, width);
+ ASSERT_LT(0, height);
+
+ mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+
+ Error error = mComposerClient->getRaw()->getClientTargetSupport_2_3(
+ mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN);
+
+ EXPECT_EQ(Error::BAD_DISPLAY, error);
+ }
+}
+
+/**
+ * Test IComposerClient::getRenderIntents_2_3
+ */
+TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3) {
+ std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
+ for (auto mode : modes) {
+ std::vector<RenderIntent> intents =
+ mComposerClient->getRenderIntents_2_3(mPrimaryDisplay, mode);
+
+ bool isHdr;
+ switch (mode) {
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ isHdr = true;
+ break;
+ default:
+ isHdr = false;
+ break;
+ }
+ RenderIntent requiredIntent =
+ isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;
+
+ auto iter = std::find(intents.cbegin(), intents.cend(), requiredIntent);
+ EXPECT_NE(intents.cend(), iter);
+ }
+}
+
+/*
+ * Test IComposerClient::getRenderIntents_2_3
+ *
+ * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_DISPLAY when
+ * passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) {
+ std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
+ for (auto mode : modes) {
+ mComposerClient->getRaw()->getRenderIntents_2_3(
+ mInvalidDisplayId, mode,
+ [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); });
+ }
+}
+
+/*
+ * Test IComposerClient::getRenderIntents_2_3
+ *
+ * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_PARAMETER when
+ * pased either an invalid Color mode or an invalid Render Intent
+ */
+TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) {
+ mComposerClient->getRaw()->getRenderIntents_2_3(
+ mPrimaryDisplay, static_cast<ColorMode>(-1),
+ [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); });
+}
+
+/**
+ * IComposerClient::getColorModes_2_3
+ */
+TEST_F(GraphicsComposerHidlTest, GetColorModes_2_3) {
+ std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
+
+ auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE);
+ ASSERT_NE(colorModes.cend(), native);
+}
+
+/*
+ * Test IComposerClient::getColorModes_2_3
+ *
+ * Test that IComposerClient::getColorModes_2_3 returns Error::BAD_DISPLAY when
+ * passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) {
+ mComposerClient->getRaw()->getColorModes_2_3(
+ mInvalidDisplayId,
+ [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); });
+}
+
+/**
+ * IComposerClient::setColorMode_2_3
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3) {
+ std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
+ for (auto mode : colorModes) {
+ std::vector<RenderIntent> intents =
+ mComposerClient->getRenderIntents_2_3(mPrimaryDisplay, mode);
+ for (auto intent : intents) {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode_2_3(mPrimaryDisplay, mode, intent));
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE,
+ RenderIntent::COLORIMETRIC));
+}
+
+/*
+ * Test IComposerClient::setColorMode_2_3
+ *
+ * Test that IComposerClient::setColorMode_2_3 returns an Error::BAD_DISPLAY
+ * when passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) {
+ Error error = mComposerClient->getRaw()->setColorMode_2_3(mInvalidDisplayId, ColorMode::NATIVE,
+ RenderIntent::COLORIMETRIC);
+
+ ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/*
+ * Test IComposerClient::setColorMode_2_3
+ *
+ * Test that IComposerClient::setColorMode_2_3 returns Error::BAD_PARAMETER when
+ * passed an invalid Color mode or an invalid render intent
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) {
+ Error colorModeError = mComposerClient->getRaw()->setColorMode_2_3(
+ mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC);
+ EXPECT_EQ(Error::BAD_PARAMETER, colorModeError);
+
+ Error renderIntentError = mComposerClient->getRaw()->setColorMode_2_3(
+ mPrimaryDisplay, ColorMode::NATIVE, static_cast<RenderIntent>(-1));
+ EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError);
+}
+
+/**
* Test IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM.
* TODO Add color to the layer, use matrix to keep only red component,
* and check.
@@ -152,6 +355,78 @@
execute();
}
+TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
+ using common::V1_1::PixelFormat;
+ using common::V1_2::Dataspace;
+
+ int constexpr invalid = -1;
+ auto format = static_cast<PixelFormat>(invalid);
+ auto dataspace = static_cast<Dataspace>(invalid);
+ auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
+ auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
+ dataspace, componentMask);
+
+ if (error == Error::UNSUPPORTED) {
+ SUCCEED() << "Device does not support optional extension. Test skipped";
+ return;
+ }
+
+ EXPECT_EQ(error, Error::NONE);
+ EXPECT_NE(format, static_cast<PixelFormat>(invalid));
+ EXPECT_NE(dataspace, static_cast<Dataspace>(invalid));
+ EXPECT_NE(componentMask,
+ static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid));
+};
+
+TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
+ auto const maxFrames = 10;
+ auto const enableAllComponents = 0;
+ auto error = mComposerClient->setDisplayedContentSamplingEnabled(
+ mPrimaryDisplay, IComposerClient::DisplayedContentSampling::ENABLE, enableAllComponents,
+ maxFrames);
+ if (error == Error::UNSUPPORTED) {
+ SUCCEED() << "Device does not support optional extension. Test skipped";
+ return;
+ }
+ EXPECT_EQ(error, Error::NONE);
+
+ error = mComposerClient->setDisplayedContentSamplingEnabled(
+ mPrimaryDisplay, IComposerClient::DisplayedContentSampling::DISABLE, enableAllComponents,
+ maxFrames);
+ EXPECT_EQ(error, Error::NONE);
+}
+
+TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) {
+ int constexpr invalid = -1;
+ auto format = static_cast<PixelFormat>(invalid);
+ auto dataspace = static_cast<Dataspace>(invalid);
+ auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
+ auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
+ dataspace, componentMask);
+
+ uint64_t maxFrames = 10;
+ uint64_t timestamp = 0;
+ uint64_t frameCount = 0;
+ hidl_array<hidl_vec<uint64_t>, 4> histogram;
+ error = mComposerClient->getDisplayedContentSample(mPrimaryDisplay, maxFrames, timestamp,
+ frameCount, histogram[0], histogram[1],
+ histogram[2], histogram[3]);
+ if (error == Error::UNSUPPORTED) {
+ SUCCEED() << "Device does not support optional extension. Test skipped";
+ return;
+ }
+
+ EXPECT_EQ(error, Error::NONE);
+ EXPECT_LE(frameCount, maxFrames);
+ for (auto i = 0; i < histogram.size(); i++) {
+ if (componentMask & (1 << i)) {
+ EXPECT_NE(histogram[i].size(), 0);
+ } else {
+ EXPECT_EQ(histogram[i].size(), 0);
+ }
+ }
+}
+
} // namespace
} // namespace vts
} // namespace V2_3
diff --git a/keymaster/3.0/vts/functional/authorization_set.h b/keymaster/3.0/vts/functional/authorization_set.h
index 5f92d81..60b00e4 100644
--- a/keymaster/3.0/vts/functional/authorization_set.h
+++ b/keymaster/3.0/vts/functional/authorization_set.h
@@ -201,7 +201,7 @@
void push_back(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data, size_t data_length) {
hidl_vec<uint8_t> new_blob;
new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
- push_back(ttag, std::move(new_blob));
+ push_back(ttag, new_blob);
}
/**
@@ -225,8 +225,7 @@
}
hidl_vec<KeyParameter> hidl_data() const {
- hidl_vec<KeyParameter> result;
- result.setToExternal(const_cast<KeyParameter*>(data()), size());
+ hidl_vec<KeyParameter> result(begin(), end());
return result;
}
@@ -252,7 +251,7 @@
size_t data_length) {
hidl_vec<uint8_t> new_blob;
new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
- push_back(ttag, std::move(new_blob));
+ push_back(ttag, new_blob);
return *this;
}
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index afbcdac..d6b50f5 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -18,6 +18,8 @@
#include <assert.h>
+#include <android-base/logging.h>
+
namespace android {
namespace hardware {
namespace keymaster {
@@ -97,10 +99,10 @@
if (prev->tag == Tag::INVALID) continue;
if (!keyParamEqual(*prev, *curr)) {
- result.emplace_back(std::move(*prev));
+ result.push_back(std::move(*prev));
}
}
- result.emplace_back(std::move(*prev));
+ result.push_back(std::move(*prev));
std::swap(data_, result);
}
@@ -127,6 +129,16 @@
}
}
+void AuthorizationSet::Filter(std::function<bool(const KeyParameter&)> doKeep) {
+ std::vector<KeyParameter> result;
+ for (auto& param : data_) {
+ if (doKeep(param)) {
+ result.push_back(std::move(param));
+ }
+ }
+ std::swap(data_, result);
+}
+
KeyParameter& AuthorizationSet::operator[](int at) {
return data_[at];
}
@@ -191,6 +203,7 @@
struct OutStreams {
std::ostream& indirect;
std::ostream& elements;
+ size_t skipped;
};
OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
@@ -229,6 +242,7 @@
OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
// skip invalid entries.
+ ++out.skipped;
return out;
}
template <typename T>
@@ -248,7 +262,12 @@
template <>
struct choose_serializer<> {
- static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; }
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ LOG(WARNING) << "Trying to serialize unknown tag " << unsigned(param.tag)
+ << ". Did you forget to add it to all_tags_t?";
+ ++out.skipped;
+ return out;
+ }
};
template <TagType tag_type, Tag tag, typename... Tail>
@@ -269,7 +288,7 @@
std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
std::stringstream indirect;
std::stringstream elements;
- OutStreams streams = {indirect, elements};
+ OutStreams streams = {indirect, elements, 0};
for (const auto& param : params) {
serialize(streams, param);
}
@@ -289,7 +308,7 @@
return out;
}
uint32_t elements_size = pos;
- uint32_t element_count = params.size();
+ uint32_t element_count = params.size() - streams.skipped;
out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
@@ -310,6 +329,7 @@
struct InStreams {
std::istream& indirect;
std::istream& elements;
+ size_t invalids;
};
InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
@@ -331,6 +351,7 @@
InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
// there should be no invalid KeyParamaters but if handle them as zero sized.
+ ++in.invalids;
return in;
}
@@ -398,13 +419,28 @@
// TODO write one-shot stream buffer to avoid copying here
std::stringstream indirect(indirect_buffer);
std::stringstream elements(elements_buffer);
- InStreams streams = {indirect, elements};
+ InStreams streams = {indirect, elements, 0};
params->resize(element_count);
for (uint32_t i = 0; i < element_count; ++i) {
deserialize(streams, &(*params)[i]);
}
+
+ /*
+ * There are legacy blobs which have invalid tags in them due to a bug during serialization.
+ * This makes sure that invalid tags are filtered from the result before it is returned.
+ */
+ if (streams.invalids > 0) {
+ std::vector<KeyParameter> filtered(element_count - streams.invalids);
+ auto ifiltered = filtered.begin();
+ for (auto& p : *params) {
+ if (p.tag != Tag::INVALID) {
+ *ifiltered++ = std::move(p);
+ }
+ }
+ *params = std::move(filtered);
+ }
return in;
}
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
index 83b1d69..458053a 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -20,6 +20,9 @@
#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <memory>
+#include <vector>
+
namespace android {
namespace hardware {
namespace keymaster {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
index 193e4ea..a131423 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -142,6 +142,11 @@
std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
/**
+ * Modifies this Authorization set such that it only keeps the entries for which doKeep
+ * returns true.
+ */
+ void Filter(std::function<bool(const KeyParameter&)> doKeep);
+ /**
* Returns the nth element of the set.
* Like for std::vector::operator[] there is no range check performed. Use of out of range
* indices is undefined.
@@ -210,8 +215,7 @@
}
hidl_vec<KeyParameter> hidl_data() const {
- hidl_vec<KeyParameter> result;
- result.setToExternal(const_cast<KeyParameter*>(data()), size());
+ hidl_vec<KeyParameter> result(begin(), end());
return result;
}
@@ -237,7 +241,7 @@
size_t data_length) {
hidl_vec<uint8_t> new_blob;
new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
- push_back(ttag, std::move(new_blob));
+ push_back(ttag, new_blob);
return *this;
}
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 9e7d252..61c444c 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -122,6 +122,7 @@
DECLARE_TYPED_TAG(CREATION_DATETIME);
DECLARE_TYPED_TAG(DIGEST);
DECLARE_TYPED_TAG(EC_CURVE);
+DECLARE_TYPED_TAG(HARDWARE_TYPE);
DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
DECLARE_TYPED_TAG(INVALID);
DECLARE_TYPED_TAG(KEY_SIZE);
@@ -162,12 +163,13 @@
TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t,
TAG_ALLOW_WHILE_ON_BODY_t, TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t,
TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t,
- TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t,
- TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t,
- TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t,
- TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
- TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t,
- TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_USER_PRESENCE_REQUIRED_t>;
+ TAG_HARDWARE_TYPE_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t,
+ TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
+ TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t,
+ TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t,
+ TAG_DIGEST_t, TAG_PADDING_t, TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t,
+ TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t, TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t,
+ TAG_TRUSTED_CONFIRMATION_REQUIRED_t, TAG_TRUSTED_USER_PRESENCE_REQUIRED_t>;
template <typename TypedTagType>
struct TypedTag2ValueType;
@@ -220,6 +222,7 @@
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, f.hardwareType)
template <TagType tag_type, Tag tag, typename ValueT>
inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 90a0f1b..5e5ae8d 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -33,25 +33,19 @@
namespace support {
-inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
- bool inPlace = true) {
- hidl_vec<uint8_t> result;
- result.setToExternal(const_cast<unsigned char*>(data), length, !inPlace);
+inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length) {
+ hidl_vec<uint8_t> result(data, data + length);
return result;
}
-inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value, bool inPlace = true) {
- hidl_vec<uint8_t> result;
- result.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.data())),
- static_cast<size_t>(value.size()), !inPlace);
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value) {
+ hidl_vec<uint8_t> result(reinterpret_cast<const uint8_t*>(value.data()),
+ reinterpret_cast<const uint8_t*>(value.data()) + value.size());
return result;
}
-inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob,
- bool inPlace = true) {
- hidl_vec<uint8_t> result;
- result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size()),
- !inPlace);
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob) {
+ hidl_vec<uint8_t> result(blob.data(), blob.data() + static_cast<size_t>(blob.size()));
return result;
}
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 784ae30..a9c6f6c 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -181,7 +181,35 @@
return d2i_X509(nullptr, &p, blob.size());
}
-bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain) {
+bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain, const std::string& msg,
+ const std::string& signature) {
+ {
+ EVP_MD_CTX md_ctx_verify;
+ X509_Ptr signing_cert(parse_cert_blob(chain[0]));
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ EXPECT_TRUE(signing_pubkey);
+ ERR_print_errors_cb(
+ [](const char* str, size_t len, void* ctx) -> int {
+ (void)ctx;
+ std::cerr << std::string(str, len) << std::endl;
+ return 1;
+ },
+ nullptr);
+
+ EVP_MD_CTX_init(&md_ctx_verify);
+
+ bool result = false;
+ EXPECT_TRUE((result = EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL,
+ signing_pubkey.get())));
+ EXPECT_TRUE(
+ (result = result && EVP_DigestVerifyUpdate(&md_ctx_verify, msg.c_str(), msg.size())));
+ EXPECT_TRUE((result = result && EVP_DigestVerifyFinal(
+ &md_ctx_verify,
+ reinterpret_cast<const uint8_t*>(signature.c_str()),
+ signature.size())));
+ EVP_MD_CTX_cleanup(&md_ctx_verify);
+ if (!result) return false;
+ }
for (size_t i = 0; i < chain.size(); ++i) {
X509_Ptr key_cert(parse_cert_blob(chain[i]));
X509_Ptr signing_cert;
@@ -3833,8 +3861,8 @@
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
.Authorization(TAG_INCLUDE_UNIQUE_ID)));
hidl_vec<hidl_vec<uint8_t>> cert_chain;
@@ -3844,7 +3872,13 @@
.Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
&cert_chain));
EXPECT_GE(cert_chain.size(), 2U);
- EXPECT_TRUE(verify_chain(cert_chain));
+
+ string message = "12345678901234567890123456789012";
+ string signature = SignMessage(message, AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+
+ EXPECT_TRUE(verify_chain(cert_chain, message, signature));
EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
key_characteristics_.softwareEnforced, //
key_characteristics_.hardwareEnforced, //
@@ -3890,7 +3924,11 @@
.Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
&cert_chain));
EXPECT_GE(cert_chain.size(), 2U);
- EXPECT_TRUE(verify_chain(cert_chain));
+
+ string message(1024, 'a');
+ string signature = SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+
+ EXPECT_TRUE(verify_chain(cert_chain, message, signature));
EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
key_characteristics_.softwareEnforced, //
diff --git a/media/bufferpool/2.0/IAccessor.hal b/media/bufferpool/2.0/IAccessor.hal
index 66707fe..b889518 100644
--- a/media/bufferpool/2.0/IAccessor.hal
+++ b/media/bufferpool/2.0/IAccessor.hal
@@ -67,6 +67,7 @@
* to get shared buffers from the buffer pool.
* @return connectionId Id of IConnection. The Id identifies
* sender and receiver in FMQ messages during buffer transfer.
+ * @return msgId Id of the most recent message from buffer pool.
* @return toFmqDesc FMQ descriptor. The descriptor is used to
* post buffer status messages.
* @return fromFmqDesc FMQ descriptor. The descriptor is used to
@@ -75,6 +76,7 @@
connect(IObserver observer)
generates (ResultStatus status, IConnection connection,
int64_t connectionId,
+ uint32_t msgId,
fmq_sync<BufferStatusMessage> toFmqDesc,
fmq_unsync<BufferInvalidationMessage> fromFmqDesc);
};
diff --git a/media/bufferpool/2.0/IObserver.hal b/media/bufferpool/2.0/IObserver.hal
index a998836..62f247e 100644
--- a/media/bufferpool/2.0/IObserver.hal
+++ b/media/bufferpool/2.0/IObserver.hal
@@ -29,6 +29,7 @@
* message.
*
* @param connectionId the connection Id of the specific buffer pool client
+ * @param msgId Id of the most recent message
*/
- oneway onMessage(int64_t connectionId);
+ oneway onMessage(int64_t connectionId, uint32_t msgId);
};
diff --git a/media/c2/1.0/Android.bp b/media/c2/1.0/Android.bp
new file mode 100644
index 0000000..28829d2
--- /dev/null
+++ b/media/c2/1.0/Android.bp
@@ -0,0 +1,51 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.media.c2@1.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IComponent.hal",
+ "IComponentInterface.hal",
+ "IComponentListener.hal",
+ "IComponentStore.hal",
+ "IConfigurable.hal",
+ "IInputSurface.hal",
+ "IInputSurfaceConnection.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media.bufferpool@1.0",
+ "android.hardware.media.omx@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "BaseBlock",
+ "Block",
+ "Buffer",
+ "FieldDescriptor",
+ "FieldId",
+ "FieldSupportedValues",
+ "FieldSupportedValuesQuery",
+ "FieldSupportedValuesQueryResult",
+ "FrameData",
+ "InfoBuffer",
+ "ParamDescriptor",
+ "ParamField",
+ "ParamFieldValues",
+ "SettingResult",
+ "Status",
+ "StructDescriptor",
+ "Work",
+ "WorkBundle",
+ "WorkOrdinal",
+ "Worklet",
+ ],
+ gen_java: false,
+}
+
diff --git a/media/c2/1.0/IComponent.hal b/media/c2/1.0/IComponent.hal
new file mode 100644
index 0000000..7fd551f
--- /dev/null
+++ b/media/c2/1.0/IComponent.hal
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
+import android.hardware.media.omx@1.0::IGraphicBufferSource;
+
+import IConfigurable;
+import IComponentInterface;
+import IComponentListener;
+import IInputSurface;
+import IInputSurfaceConnection;
+
+/**
+ * Interface for a Codec2 component corresponding to API level 1.0 or below.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status.
+ */
+interface IComponent {
+
+ // METHODS AVAILABLE WHEN RUNNING
+ // =========================================================================
+
+ /**
+ * Queues up work for the component.
+ *
+ * This method must be supported in running (including tripped) states.
+ *
+ * It is acceptable for this method to return `OK` and return an error value
+ * using the IComponentListener::onWorkDone() callback.
+ *
+ * @param workBundle `WorkBundle` object containing a list of `Work` objects
+ * to queue to the component.
+ * @return status Status of the call, which may be
+ * - `OK` - Works in @p workBundle were successfully queued.
+ * - `BAD_INDEX` - Some component id in some `Worklet` is not valid.
+ * - `CANNOT_DO` - The components are not tunneled but some `Work` object
+ * contains tunneling information.
+ * - `NO_MEMORY` - Not enough memory to queue @p workBundle.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ queue(WorkBundle workBundle) generates (Status status);
+
+ /**
+ * Discards and abandons any pending `Work` items for the component.
+ *
+ * This method must be supported in running (including tripped) states.
+ *
+ * `Work` that could be immediately abandoned/discarded must be returned in
+ * @p flushedWorkBundle. The order in which queued `Work` items are
+ * discarded can be arbitrary.
+ *
+ * `Work` that could not be abandoned or discarded immediately must be
+ * marked to be discarded at the earliest opportunity, and must be returned
+ * via IComponentListener::onWorkDone(). This must be completed within
+ * 500ms.
+ *
+ * @return status Status of the call, which may be
+ * - `OK` - The component has been successfully flushed.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return flushedWorkBundle `WorkBundle` object containing flushed `Work`
+ * items.
+ */
+ flush(
+ ) generates (
+ Status status,
+ WorkBundle flushedWorkBundle
+ );
+
+ /**
+ * Drains the component, and optionally downstream components. This is a
+ * signalling method; as such it does not wait for any work completion.
+ *
+ * The last `Work` item is marked as "drain-till-here", so the component is
+ * notified not to wait for further `Work` before it processes what is
+ * already queued. This method can also be used to set the end-of-stream
+ * flag after `Work` has been queued. Client can continue to queue further
+ * `Work` immediately after this method returns.
+ *
+ * This method must be supported in running (including tripped) states.
+ *
+ * `Work` that is completed must be returned via
+ * IComponentListener::onWorkDone().
+ *
+ * @param withEos Whether to drain the component with marking end-of-stream.
+ * @return status Status of the call, which may be
+ * - `OK` - The drain request has been successfully recorded.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ drain(bool withEos) generates (Status status);
+
+ /**
+ * Starts using a surface for output.
+ *
+ * This method must not block.
+ *
+ * @param blockPoolId Id of the `C2BlockPool` to be associated with the
+ * output surface.
+ * @param surface Output surface.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `CANNOT_DO` - The component does not support an output surface.
+ * - `REFUSED` - The output surface cannot be accessed.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ setOutputSurface(
+ uint64_t blockPoolId,
+ IGraphicBufferProducer surface
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Starts using an input surface.
+ *
+ * The component must be in running state.
+ *
+ * @param inputSurface Input surface to connect to.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `CANNOT_DO` - The component does not support an input surface.
+ * - `BAD_STATE` - The component is not in running state.
+ * - `DUPLICATE` - The component is already connected to an input surface.
+ * - `REFUSED` - The input surface is already in use.
+ * - `NO_MEMORY` - Not enough memory to start the component.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return connection `IInputSurfaceConnection` object, which can be used to
+ * query and configure properties of the connection. This cannot be
+ * null.
+ */
+ connectToInputSurface(
+ IInputSurface inputSurface
+ ) generates (
+ Status status,
+ IInputSurfaceConnection connection
+ );
+
+ /**
+ * Starts using an OMX input surface.
+ *
+ * The component must be in running state.
+ *
+ * This method is similar to connectToInputSurface(), but it takes an OMX
+ * input surface (as a pair of `IGraphicBufferProducer` and
+ * `IGraphicBufferSource`) instead of Codec2's own `IInputSurface`.
+ *
+ * @param producer Producer component of an OMX input surface.
+ * @param source Source component of an OMX input surface.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `CANNOT_DO` - The component does not support an OMX input surface.
+ * - `BAD_STATE` - The component is not in running state.
+ * - `DUPLICATE` - The component is already connected to an input surface.
+ * - `REFUSED` - The input surface is already in use.
+ * - `NO_MEMORY` - Not enough memory to start the component.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return connection `IInputSurfaceConnection` object, which can be used to
+ * query and configure properties of the connection. This cannot be
+ * null.
+ */
+ connectToOmxInputSurface(
+ IGraphicBufferProducer producer,
+ IGraphicBufferSource source
+ ) generates (
+ Status status,
+ IInputSurfaceConnection connection
+ );
+
+ /**
+ * Stops using an input surface.
+ *
+ * The component must be in running state.
+ *
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `CANNOT_DO` - The component does not support an input surface.
+ * - `BAD_STATE` - The component is not in running state.
+ * - `NOT_FOUND` - The component is not connected to an input surface.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ disconnectFromInputSurface() generates (Status Status);
+
+ /**
+ * Creates a local `C2BlockPool` backed by the given allocator and returns
+ * its id.
+ *
+ * The returned @p blockPoolId is the only way the client can refer to a
+ * `C2BlockPool` object in the component. The id can be passed to
+ * setOutputSurface() or used in some C2Param objects later.
+ *
+ * The created `C2BlockPool` object can be destroyed by calling
+ * destroyBlockPool(), reset() or release(). reset() and release() must
+ * destroy all `C2BlockPool` objects that have been created.
+ *
+ * @param allocatorId Id of a `C2Allocator`.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `NO_MEMORY` - Not enough memory to create the pool.
+ * - `BAD_VALUE` - @p allocatorId is not recognized.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return blockPoolId Id of the created C2BlockPool object. This may be
+ * used in setOutputSurface() if the allocator
+ * @return configurable Configuration interface for the created pool. This
+ * must not be null.
+ */
+ createBlockPool(uint32_t allocatorId) generates (
+ Status status,
+ uint64_t blockPoolId,
+ IConfigurable configurable
+ );
+
+ /**
+ * Destroys a local block pool previously created by createBlockPool().
+ *
+ * @param blockPoolId Id of a `C2BlockPool` that was previously returned by
+ * createBlockPool().
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `NOT_FOUND` - The supplied blockPoolId is not valid.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ destroyBlockPool(uint64_t blockPoolId) generates (Status status);
+
+ // STATE CHANGE METHODS
+ // =========================================================================
+
+ /**
+ * Starts the component.
+ *
+ * This method must be supported in stopped state as well as tripped state.
+ *
+ * If the return value is `OK`, the component must be in the running state.
+ * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+ * expected as a response to this call. Otherwise, the component must be in
+ * the stopped state.
+ *
+ * If a component is in the tripped state and start() is called while the
+ * component configuration still results in a trip, start() must succeed and
+ * a new onTripped() callback must be used to communicate the configuration
+ * conflict that results in the new trip.
+ *
+ * @return status Status of the call, which may be
+ * - `OK` - The component has started successfully.
+ * - `BAD_STATE` - Component is not in stopped or tripped state.
+ * - `DUPLICATE` - When called during another start call from another
+ * thread.
+ * - `NO_MEMORY` - Not enough memory to start the component.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ start() generates (Status status);
+
+ /**
+ * Stops the component.
+ *
+ * This method must be supported in running (including tripped) state.
+ *
+ * This method must return withing 500ms.
+ *
+ * Upon this call, all pending `Work` must be abandoned.
+ *
+ * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+ * expected as a response to this call. For all other return values, the
+ * component must be in the stopped state.
+ *
+ * This does not alter any settings and tunings that may have resulted in a
+ * tripped state.
+ *
+ * @return status Status of the call, which may be
+ * - `OK` - The component has stopped successfully.
+ * - `BAD_STATE` - Component is not in running state.
+ * - `DUPLICATE` - When called during another stop call from another
+ * thread.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ stop() generates (Status status);
+
+ /**
+ * Resets the component.
+ *
+ * This method must be supported in all (including tripped) states other
+ * than released.
+ *
+ * This method must be supported during any other blocking call.
+ *
+ * This method must return withing 500ms.
+ *
+ * When this call returns, if @p status is `OK`, all `Work` items must
+ * have been abandoned, and all resources (including `C2BlockPool` objects
+ * previously created by createBlockPool()) must have been released.
+ *
+ * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+ * expected as a response to this call. For all other return values, the
+ * component must be in the stopped state.
+ *
+ * This brings settings back to their default, "guaranteeing" no tripped
+ * state.
+ *
+ * @return status Status of the call, which may be
+ * - `OK` - The component has been reset.
+ * - `BAD_STATE` - Component is in released state.
+ * - `DUPLICATE` - When called during another reset call from another
+ * thread.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ reset() generates (Status status);
+
+ /**
+ * Releases the component.
+ *
+ * This method must be supported in stopped state.
+ *
+ * This method destroys the component. Upon return, if @p status is `OK` or
+ * `DUPLICATE`, all resources must have been released.
+ *
+ * @return status Status of the call, which may be
+ * - `OK` - The component has been released.
+ * - `BAD_STATE` - The component is running.
+ * - `DUPLICATE` - The component is already released.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ release() generates (Status status);
+
+ /**
+ * Returns the @ref IComponentInterface instance associated to this
+ * component.
+ *
+ * An @p IConfigurable instance for the component can be obtained by calling
+ * IComponentInterface::getConfigurable() on the returned @p intf.
+ *
+ * @return intf `IComponentInterface` instance. This must not be null.
+ */
+ getInterface() generates (IComponentInterface intf);
+};
+
diff --git a/media/c2/1.0/IComponentInterface.hal b/media/c2/1.0/IComponentInterface.hal
new file mode 100644
index 0000000..a007d02
--- /dev/null
+++ b/media/c2/1.0/IComponentInterface.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import IConfigurable;
+
+/**
+ * Component interface object. This object contains all of the configurations of
+ * a potential or actual component. It can be created and used independently of
+ * an actual Codec2 component to query supported parameters for various
+ * component settings, and configurations for a potential component.
+ *
+ * An actual component exposes this interface via IComponent::getInterface().
+ */
+interface IComponentInterface {
+ /**
+ * Returns the @ref IConfigurable instance associated to this component
+ * interface.
+ *
+ * @return configurable `IConfigurable` instance. This must not be null.
+ */
+ getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/IComponentListener.hal b/media/c2/1.0/IComponentListener.hal
new file mode 100644
index 0000000..70d5fb2
--- /dev/null
+++ b/media/c2/1.0/IComponentListener.hal
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+/**
+ * Callback interface for handling notifications from @ref IComponent.
+ */
+interface IComponentListener {
+
+ /**
+ * Notify the listener that some `Work` items have been completed.
+ *
+ * All the input buffers in the returned `Work` objects must not be used by
+ * the component after onWorkDone() is called.
+ *
+ * @param workBundle List of completed `Work` objects.
+ */
+ oneway onWorkDone(WorkBundle workBundle);
+
+ /**
+ * Notify the listener that the component is tripped.
+ *
+ * @param settingResults List of failures.
+ */
+ oneway onTripped(vec<SettingResult> settingResults);
+
+ /**
+ * Notify the listener of an error.
+ *
+ * @param status Error type. @p status may be `OK`, which means that an
+ * error has occurred, but the error type does not fit into the type
+ * `Status`. In this case, additional information is provided by
+ * @p errorCode.
+ * @param errorCode Additional error information. The framework may not
+ * recognize the meaning of this value.
+ */
+ oneway onError(Status status, uint32_t errorCode);
+
+ /**
+ * Information about rendering of a frame to a `Surface`.
+ */
+ struct RenderedFrame {
+ /**
+ * Id of the `BufferQueue` containing the rendered buffer.
+ *
+ * This value must have been obtained by an earlier call to
+ * IGraphicBufferProducer::getUniqueId().
+ */
+ uint64_t bufferQueueId;
+ /**
+ * Id of the slot of the rendered buffer.
+ *
+ * This value must have been obtained by an earlier call to
+ * IGraphicBufferProducer::dequeueBuffer() or
+ * IGraphicBufferProducer::attachBuffer().
+ */
+ int32_t slotId;
+ /**
+ * Timestamp the rendering happened.
+ *
+ * The reference point for the timestamp is determined by the
+ * `BufferQueue` that performed the rendering.
+ */
+ int64_t timestampNs;
+ };
+
+ /**
+ * Notify the listener that frames have been rendered.
+ *
+ * @param renderedFrames List of @ref RenderedFrame objects.
+ */
+ oneway onFramesRendered(vec<RenderedFrame> renderedFrames);
+
+ /**
+ * Identifying information for an input buffer previously queued to the
+ * component via IComponent::queue().
+ */
+ struct InputBuffer {
+ /**
+ * This value comes from `Work::input.ordinal.frameIndex` in a `Work`
+ * object that was previously queued.
+ */
+ uint64_t frameIndex;
+ /**
+ * This value is an index into `Work::input.buffers` (which is an array)
+ * in a `Work` object that was previously queued.
+ */
+ uint32_t arrayIndex;
+ };
+
+ /**
+ * Notify the listener that some input buffers are no longer needed by the
+ * component, and hence can be released or reused by the client.
+ *
+ * Input buffers that are contained in a `Work` object returned by an
+ * earlier onWorkDone() call are assumed released, so they must not appear
+ * in any onInputBuffersReleased() calls. That means
+ * onInputBuffersReleased() must only report input buffers that are released
+ * before the output in the same `Work` item is produced. However, it is
+ * possible for an input buffer to be returned by onWorkDone() after it has
+ * been reported by onInputBuffersReleased().
+ *
+ * @note onWorkDone() and onInputBuffersReleased() both notify the client
+ * that input buffers are no longer needed. However, in order to minimize
+ * IPC calls, onInputBuffersReleased() should be called only when
+ * onWorkDone() cannot be called, e.g., the component needs more input
+ * before an output can be produced.
+ *
+ * @param inputBuffers List of `InputBuffer` objects, identifying input
+ * buffers that are no longer needed by the component.
+ */
+ oneway onInputBuffersReleased(vec<InputBuffer> inputBuffers);
+};
+
diff --git a/media/c2/1.0/IComponentStore.hal b/media/c2/1.0/IComponentStore.hal
new file mode 100644
index 0000000..a027afe
--- /dev/null
+++ b/media/c2/1.0/IComponentStore.hal
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.media.bufferpool@1.0::IClientManager;
+import IComponentInterface;
+import IComponentListener;
+import IComponent;
+import IConfigurable;
+import IInputSurface;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status. The only exceptions are getPoolClientManager() and getConfigurable(),
+ * which must always return immediately.
+ */
+interface IComponentStore {
+
+ /**
+ * Creates a component by name.
+ *
+ * @param name Name of the component to create. This must match one of the
+ * names returned by listComponents().
+ * @param listener Callback receiver.
+ * @param pool `IClientManager` object of the BufferPool in the client
+ * process. This may be null if the client does not own a BufferPool.
+ * @return status Status of the call, which may be
+ * - `OK` - The component was created successfully.
+ * - `NOT_FOUND` - There is no component with the given name.
+ * - `NO_MEMORY` - Not enough memory to create the component.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return comp The created component if @p status is `OK`.
+ *
+ * @sa IComponentListener.
+ */
+ createComponent(
+ string name,
+ IComponentListener listener,
+ IClientManager pool
+ ) generates (
+ Status status,
+ IComponent comp
+ );
+
+ /**
+ * Creates a component interface by name.
+ *
+ * @param name Name of the component interface to create. This should match
+ * one of the names returned by listComponents().
+ * @return status Status of the call, which may be
+ * - `OK - The component interface was created successfully.
+ * - `NOT_FOUND` - There is no component interface with the given name.
+ * - `NO_MEMORY` - Not enough memory to create the component interface.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return compIntf The created component interface if @p status is `OK`.
+ */
+ createInterface(
+ string name
+ ) generates (
+ Status status,
+ IComponentInterface compIntf
+ );
+
+ /**
+ * Component traits.
+ */
+ struct ComponentTraits {
+ /**
+ * Name of the component. This must be unique for each component.
+ *
+ * This name is use to identify the component to create in
+ * createComponent() and createComponentInterface().
+ */
+ string name;
+
+ enum Domain : uint32_t {
+ OTHER = 0,
+ VIDEO,
+ AUDIO,
+ IMAGE,
+ };
+ /**
+ * Component domain.
+ */
+ Domain domain;
+
+ enum Kind : uint32_t {
+ OTHER = 0,
+ DECODER,
+ ENCODER,
+ };
+ /**
+ * Component kind.
+ */
+ Kind kind;
+
+ /**
+ * Rank used by `MediaCodecList` to determine component ordering. Lower
+ * value means higher priority.
+ */
+ uint32_t rank;
+
+ /**
+ * MIME type.
+ */
+ string mediaType;
+
+ /**
+ * Aliases for component name for backward compatibility.
+ *
+ * Multiple components can have the same alias (but not the same
+ * component name) as long as their media types differ.
+ */
+ vec<string> aliases;
+ };
+
+ /**
+ * Returns the list of components supported by this component store.
+ *
+ * @return status Status of the call, which may be
+ * - `OK - The operation was successful.
+ * - `NO_MEMORY` - Not enough memory to complete this method.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return traits List of component traits for all components supported by
+ * this store (in no particular order).
+ */
+ listComponents() generates (
+ Status status,
+ vec<ComponentTraits> traits
+ );
+
+ /**
+ * Creates a persistent input surface that can be used as an input surface
+ * for any IComponent instance
+ *
+ * @return status Status of the call, which may be
+ * - `OK - The operation was successful.
+ * - `NO_MEMORY` - Not enough memory to complete this method.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return surface A persistent input surface. This may be null to indicate
+ * an error.
+ */
+ createInputSurface() generates (
+ Status status,
+ IInputSurface surface
+ );
+
+ /**
+ * Returns a list of `StructDescriptor` objects for a set of requested
+ * C2Param structure indices that this store is aware of.
+ *
+ * This operation must be performed at best effort, e.g. the component
+ * store must simply ignore all struct indices that it is not aware of.
+ *
+ * @param indices Indices of C2Param structures to describe.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `NOT_FOUND` - Some indices were not known.
+ * - `NO_MEMORY` - Not enough memory to complete this method.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return structs List of `StructDescriptor` objects.
+ */
+ getStructDescriptors(
+ vec<ParamIndex> indices
+ ) generates (
+ Status status,
+ vec<StructDescriptor> structs
+ );
+
+ /**
+ * Copies the contents of @p src into @p dst without changing the format of
+ * @p dst.
+ *
+ * @param src Source buffer.
+ * @param dst Destination buffer.
+ * @return status Status of the call, which may be
+ * - `OK` - The copy is successful.
+ * - `CANNOT_DO` - @p src and @p dst are not compatible.
+ * - `REFUSED` - No permission to copy.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ */
+ copyBuffer(Buffer src, Buffer dst) generates (Status status);
+
+ /**
+ * Returns the `IClientManager` object for the component's BufferPool.
+ *
+ * @return pool If the component store supports receiving buffers via
+ * BufferPool API, @p pool must be a valid `IClientManager` instance.
+ * Otherwise, @p pool must be null.
+ */
+ getPoolClientManager() generates (IClientManager pool);
+
+ /**
+ * Returns the @ref IConfigurable instance associated to this component
+ * store.
+ *
+ * @return configurable `IConfigurable` instance. This must not be null.
+ */
+ getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/IConfigurable.hal b/media/c2/1.0/IConfigurable.hal
new file mode 100644
index 0000000..31dc4d3
--- /dev/null
+++ b/media/c2/1.0/IConfigurable.hal
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+/**
+ * Generic configuration interface presented by all configurable Codec2 objects.
+ *
+ * This interface must be supported in all states of the owning object, and must
+ * not change the state of the owning object.
+ */
+interface IConfigurable {
+ /**
+ * Returns the id of the object. This must be unique among all objects of
+ * the same type hosted by the same store.
+ *
+ * @return id Id of the object.
+ */
+ getId() generates (uint32_t id);
+
+ /**
+ * Returns the name of the object.
+ *
+ * This must match the name that was supplied during the creation of the
+ * object.
+ *
+ * @return name Name of the object.
+ */
+ getName() generates (string name);
+
+ /**
+ * Queries a set of parameters from the object.
+ *
+ * Querying is performed at best effort: the object must query all supported
+ * parameters and skip unsupported ones (which may include parameters that
+ * could not be allocated). Any errors are communicated in the return value.
+ *
+ * If @p mayBlock is false, this method must not block. All parameter
+ * queries that require blocking must be skipped.
+ *
+ * If @p mayBlock is true, a query may block, but the whole method call
+ * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
+ *
+ * If @p mayBlock is false, this method must not block. Otherwise, this
+ * method is allowed to block for a certain period of time before completing
+ * the operation. If the operation is not completed in a timely manner,
+ * `status = TIMED_OUT` is returned.
+ *
+ * @note The order of C2Param objects in @p param does not depend on the
+ * order of C2Param structure indices in @p indices.
+ *
+ * \par For IComponent
+ *
+ * When the object type is @ref IComponent, this method must be supported in
+ * any state except released. This call must not change the state nor the
+ * internal configuration of the component.
+ *
+ * The blocking behavior of this method differs among states:
+ * - In the stopped state, this must be non-blocking. @p mayBlock is
+ * ignored. (The method operates as if @p mayBlock was false.)
+ * - In any of the running states, this method may block momentarily if
+ * @p mayBlock is true. However, if the call cannot be completed in a
+ * timely manner, `status = TIMED_OUT` is returned.
+ *
+ * @param indices List of C2Param structure indices to query.
+ * @param mayBlock Whether this call may block or not.
+ * @return status Status of the call, which may be
+ * - `OK` - All parameters could be queried.
+ * - `BAD_INDEX` - All supported parameters could be queried, but some
+ * parameters were not supported.
+ * - `NO_MEMORY` - Could not allocate memory for a supported parameter.
+ * - `BLOCKING` - Querying some parameters requires blocking, but
+ * @p mayBlock is false.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return params Flattened representation of C2Param objects.
+ *
+ * @sa Params.
+ */
+ query(
+ vec<ParamIndex> indices,
+ bool mayBlock
+ ) generates (
+ Status status,
+ Params params
+ );
+
+ /**
+ * Sets a set of parameters for the object.
+ *
+ * Tuning is performed at best effort: the object must update all supported
+ * configurations at best effort and skip unsupported parameters. Any errors
+ * are communicated in the return value and in @p failures.
+ *
+ * A non-strict parameter update with an unsupported value shall cause an
+ * update to the closest supported value. A strict parameter update with an
+ * unsupported value shall be skipped and a failure shall be returned.
+ *
+ * If @p mayBlock is false, this method must not block. An update that
+ * requires blocking shall be skipped and a failure shall be returned.
+ *
+ * If @p mayBlock is true, an update may block, but the whole method call
+ * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
+ *
+ * The final values for all parameters set are propagated back to the caller
+ * in @p params.
+ *
+ * \par For IComponent
+ *
+ * When the object type is @ref IComponent, this method must be supported in
+ * any state except released.
+ *
+ * The blocking behavior of this method differs among states:
+ * - In the stopped state, this must be non-blocking. @p mayBlock is
+ * ignored. (The method operates as if @p mayBlock was false.)
+ * - In any of the running states, this method may block momentarily if
+ * @p mayBlock is true. However, if the call cannot be completed in a
+ * timely manner, `status = TIMED_OUT` is returned.
+ *
+ * @note Parameter tuning @e does depend on the order of the tuning
+ * parameters, e.g., some parameter update may enable some subsequent
+ * parameter update.
+ *
+ * @param inParams Requested parameter updates.
+ * @param mayBlock Whether this call may block or not.
+ * @return status Status of the call, which may be
+ * - `OK` - All parameters could be updated successfully.
+ * - `BAD_INDEX` - All supported parameters could be updated successfully,
+ * but some parameters were not supported.
+ * - `NO_MEMORY` - Some supported parameters could not be updated
+ * successfully because they contained unsupported values.
+ * These are returned in @p failures.
+ * - `BLOCKING` - Setting some parameters requires blocking, but
+ * @p mayBlock is false.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return failures List of update failures.
+ * @return outParams Flattened representation of configured parameters. The
+ * order of parameters in @p outParams is based on the order of
+ * requested updates in @p inParams.
+ *
+ * @sa SettingResult.
+ */
+ config(
+ Params inParams,
+ bool mayBlock
+ ) generates (
+ Status status,
+ vec<SettingResult> failures,
+ Params outParams
+ );
+
+ // REFLECTION MECHANISM
+ // =========================================================================
+
+ /**
+ * Returns a list of supported parameters within a selected range of C2Param
+ * structure indices.
+ *
+ * @param start The first index of the selected range.
+ * @param count The length of the selected range.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `NO_MEMORY` - Not enough memory to complete this method.
+ * @return params List of supported parameters in the selected range. This
+ * list may have fewer than @p count elements if some indices in the
+ * range are not supported.
+ *
+ * @sa ParamDescriptor.
+ */
+ querySupportedParams(
+ uint32_t start,
+ uint32_t count
+ ) generates (
+ Status status,
+ vec<ParamDescriptor> params
+ );
+
+ /**
+ * Retrieves the supported values for the queried fields.
+ *
+ * The object must process all fields queried even if some queries fail.
+ *
+ * If @p mayBlock is false, this method must not block. Otherwise, this
+ * method is allowed to block for a certain period of time before completing
+ * the operation. If the operation cannot be completed in a timely manner,
+ * `status = TIMED_OUT` is returned.
+ *
+ * \par For IComponent
+ *
+ * When the object type is @ref IComponent, this method must be supported in
+ * any state except released.
+ *
+ * The blocking behavior of this method differs among states:
+ * - In the stopped state, this must be non-blocking. @p mayBlock is
+ * ignored. (The method operates as if @p mayBlock was false.)
+ * - In any of the running states, this method may block momentarily if
+ * @p mayBlock is true. However, if the call cannot be completed in a
+ * timely manner, `status = TIMED_OUT` is returned.
+ *
+ * @param inFields List of field queries.
+ * @param mayBlock Whether this call may block or not.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully.
+ * - `BLOCKING` - Querying some parameters requires blocking, but
+ * @p mayBlock is false.
+ * - `NO_MEMORY` - Not enough memory to complete this method.
+ * - `BAD_INDEX` - At least one field was not recognized as a component
+ * field.
+ * - `BLOCKING` - Querying some fields requires blocking, but @p mayblock
+ * is false.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return outFields List of supported values and results for the
+ * supplied queries.
+ *
+ * @sa FieldSupportedValuesQuery, FieldSupportedValuesQueryResult.
+ */
+ querySupportedValues(
+ vec<FieldSupportedValuesQuery> inFields,
+ bool mayBlock
+ ) generates (
+ Status status,
+ vec<FieldSupportedValuesQueryResult> outFields
+ );
+
+};
+
diff --git a/media/c2/1.0/IInputSurface.hal b/media/c2/1.0/IInputSurface.hal
new file mode 100644
index 0000000..25c6c8e
--- /dev/null
+++ b/media/c2/1.0/IInputSurface.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
+
+import IConfigurable;
+
+/**
+ * Input surface for a Codec2 component.
+ *
+ * An <em>input surface</em> is an instance of `IInputSurface`, which may be
+ * created by calling IComponentStore::createInputSurface(). Once created, the
+ * client may
+ * 1. write data to it via the `IGraphicBufferProducer` interface; and
+ * 2. use it as input to a Codec2 encoder.
+ *
+ * @sa IInputSurfaceConnection, IComponentStore::createInputSurface(),
+ * IComponent::connectToInputSurface().
+ */
+interface IInputSurface {
+ /**
+ * Returns the producer interface into the internal buffer queue.
+ *
+ * @return producer `IGraphicBufferProducer` instance. This must not be
+ * null.
+ */
+ getGraphicBufferProducer() generates (IGraphicBufferProducer producer);
+
+ /**
+ * Returns the @ref IConfigurable instance associated to this input surface.
+ *
+ * @return configurable `IConfigurable` instance. This must not be null.
+ */
+ getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/IInputSurfaceConnection.hal b/media/c2/1.0/IInputSurfaceConnection.hal
new file mode 100644
index 0000000..efd9c6e
--- /dev/null
+++ b/media/c2/1.0/IInputSurfaceConnection.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import IConfigurable;
+
+/**
+ * Connection between a component and an input surface.
+ *
+ * An instance of `IInputSurfaceConnection` contains an `IConfigurable`
+ * interface for querying and configuring properties of the connection.
+ */
+interface IInputSurfaceConnection {
+ /**
+ * Returns the @ref IConfigurable instance associated to this connection.
+ *
+ * This can be used to customize the connection.
+ *
+ * @return configurable `IConfigurable` instance. This must not be null.
+ */
+ getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/types.hal b/media/c2/1.0/types.hal
new file mode 100644
index 0000000..13269d2
--- /dev/null
+++ b/media/c2/1.0/types.hal
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.media.bufferpool@1.0::BufferStatusMessage;
+
+/**
+ * Common return values for Codec2 operations.
+ */
+enum Status : int32_t {
+ /** Operation completed successfully. */
+ OK = 0,
+
+ // bad input
+
+ /** Argument has invalid value (user error). */
+ BAD_VALUE = -22,
+ /** Argument uses invalid index (user error). */
+ BAD_INDEX = -75,
+ /** Argument/Index is valid but not possible. */
+ CANNOT_DO = -2147483646,
+
+ // bad sequencing of events
+
+ /** Object already exists. */
+ DUPLICATE = -17,
+ /** Object not found. */
+ NOT_FOUND = -2,
+ /** Operation is not permitted in the current state. */
+ BAD_STATE = -38,
+ /** Operation would block but blocking is not permitted. */
+ BLOCKING = -9930,
+
+ // bad environment
+
+ /** Not enough memory to complete operation. */
+ NO_MEMORY = -12,
+ /** Missing permission to complete operation. */
+ REFUSED = -1,
+
+ /** Operation did not complete within timeout. */
+ TIMED_OUT = -110,
+
+ // missing functionality
+
+ /** Operation is not implemented/supported (optional only). */
+ OMITTED = -74,
+
+ // unknown fatal
+
+ /** Some unexpected error prevented the operation. */
+ CORRUPTED = -2147483648,
+
+ // uninitialized
+
+ /** Status has not been initialized. */
+ NO_INIT = -19,
+};
+
+/**
+ * C2Param structure index.
+ *
+ * This is a number that is unique for each C2Param structure type.
+ *
+ * @sa Codec 2.0 standard.
+ */
+typedef uint32_t ParamIndex;
+
+/**
+ * Flattened representation of C2Param objects.
+ *
+ * The `Params` type is an array of bytes made up by concatenating a list of
+ * C2Param objects. The start index (offset into @ref Params) of each C2Param
+ * object in the list is divisible by 8. Up to 7 padding bytes may be added
+ * after each C2Param object to achieve this 64-bit alignment.
+ *
+ * Each C2Param object has the following layout:
+ * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the
+ * type of the C2Param object.
+ * - 4 bytes: size of the C2Param object (unsigned 4-byte integer).
+ * - (size - 8) bytes: data of the C2Param object.
+ *
+ * In order to interpret each C2Param object correctly, its structure must be
+ * described by IComponentStore::getStructDescriptors().
+ *
+ * @note Please refer to the Codec 2.0 standard for the list of standard
+ * parameter structures.
+ *
+ * @sa Codec 2.0 standard.
+ */
+typedef vec<uint8_t> Params;
+
+/**
+ * Identifying information of a field relative to a known C2Param structure.
+ *
+ * Within a given C2Param structure, each field is uniquely identified by @ref
+ * FieldId.
+ */
+struct FieldId {
+ /** Offset of the field in bytes. */
+ uint32_t offset;
+ /** Size of the field in bytes. */
+ uint32_t size;
+};
+
+/**
+ * Reference to a field in a C2Param structure.
+ */
+struct ParamField {
+ /** Index of the C2Param structure. */
+ ParamIndex index;
+ /** Identifier of the field inside the C2Param structure. */
+ FieldId fieldId;
+};
+
+/**
+ * Usage description of a C2Param structure.
+ *
+ * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
+ */
+struct ParamDescriptor {
+ /**
+ * Index of the C2Param structure being described.
+ */
+ ParamIndex index;
+
+ enum Attrib : uint32_t {
+ /**
+ * The parameter is required to be specified.
+ */
+ REQUIRED = 1u << 0,
+ /**
+ * The parameter retains its value.
+ */
+ PERSISTENT = 1u << 1,
+ /**
+ * The parameter is strict.
+ */
+ STRICT = 1u << 2,
+ /**
+ * The parameter is publicly read-only.
+ */
+ READ_ONLY = 1u << 3,
+ /**
+ * The parameter must not be visible to clients.
+ */
+ HIDDEN = 1u << 4,
+ /**
+ * The parameter must not be used by framework (other than testing).
+ */
+ INTERNAL = 1u << 5,
+ /**
+ * The parameter is publicly constant (hence read-only).
+ */
+ CONST = 1u << 6,
+ };
+ bitfield<Attrib> attrib;
+
+ /**
+ * Name of the structure. This must be unique for each structure.
+ */
+ string name;
+
+ /**
+ * Indices of other C2Param structures that this C2Param structure depends
+ * on.
+ */
+ vec<ParamIndex> dependencies;
+};
+
+// Generic way to describe supported numeric values for Codec2 interfaces.
+
+/**
+ * An untyped value that can fit in 64 bits, the type of which is communicated
+ * via a separate channel (@ref FieldSupportedValues.type).
+ */
+typedef uint64_t PrimitiveValue;
+
+/*
+ * Description of supported values for a field.
+ *
+ * This can be a continuous range or a discrete set of values.
+ */
+struct FieldSupportedValues {
+ /**
+ * Used if #type is `RANGE`.
+ *
+ * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
+ * structure represents a closed interval bounded by `min` and `max`.
+ *
+ * Otherwise, the #Range structure represents a finite sequence of numbers
+ * produced from the following recurrence relation:
+ *
+ * @code
+ * v[0] = min
+ * v[i] = v[i - 1] * num / denom + step ; i >= 1
+ * @endcode
+ *
+ * Both the ratio `num / denom` and the value `step` must be positive. The
+ * last number in the sequence described by this #Range structure is the
+ * largest number in the sequence that is smaller than or equal to `max`.
+ *
+ * @note
+ * The division in the formula may truncate the result if the data type of
+ * these values is an integral type.
+ */
+ struct Range {
+ /**
+ * Lower end of the range (inclusive).
+ */
+ PrimitiveValue min;
+ /**
+ * Upper end of the range (inclusive).
+ */
+ PrimitiveValue max;
+ /**
+ * The non-homogeneous term in the recurrence relation.
+ */
+ PrimitiveValue step;
+ /**
+ * The numerator of the scale coefficient in the recurrence relation.
+ */
+ PrimitiveValue num;
+ /**
+ * The denominator of the scale coefficient in the recurrence relation.
+ */
+ PrimitiveValue denom;
+ };
+
+ enum Type : int32_t {
+ /** No supported values */
+ EMPTY = 0,
+ /** Numeric range, described in a #Range structure */
+ RANGE,
+ /** List of values */
+ VALUES,
+ /** List of flags that can be OR-ed */
+ FLAGS,
+ };
+ /**
+ * Type of the supported values.
+ */
+ Type type;
+
+ /**
+ * When #type is #Type.RANGE, #range shall specify the range of possible
+ * values.
+ *
+ * The intended type of members of #range shall be clear in the context
+ * where `FieldSupportedValues` is used.
+ */
+ Range range;
+
+ /**
+ * When #type is #Type.VALUES or #Type.FLAGS, #value shall list supported
+ * values/flags.
+ *
+ * The intended type of components of #value shall be clear in the context
+ * where `FieldSupportedValues` is used.
+ */
+ vec<PrimitiveValue> values;
+};
+
+/**
+ * Supported values for a field.
+ *
+ * This is a pair of the field specifier together with an optional supported
+ * values object. This structure is used when reporting parameter configuration
+ * failures and conflicts.
+ */
+struct ParamFieldValues {
+ /**
+ * Reference to a field or a C2Param structure.
+ */
+ ParamField paramOrField;
+
+ /**
+ * Optional supported values for the field if #paramOrField specifies an
+ * actual field that is numeric (non struct, blob or string). Supported
+ * values for arrays (including string and blobs) describe the supported
+ * values for each element (character for string, and bytes for blobs). It
+ * is optional for read-only strings and blobs.
+ */
+ vec<FieldSupportedValues> values;
+};
+
+/**
+ * Description of a field inside a C2Param structure.
+ */
+struct FieldDescriptor {
+
+ /** Location of the field in the C2Param structure */
+ FieldId fieldId;
+
+ /**
+ * Possible types of the field.
+ */
+ enum Type : uint32_t {
+ NO_INIT = 0,
+ INT32,
+ UINT32,
+ CNTR32,
+ INT64,
+ UINT64,
+ CNTR64,
+ FLOAT,
+ /**
+ * Fixed-size string (POD).
+ */
+ STRING = 0x100,
+ /**
+ * A blob has no sub-elements and can be thought of as an array of
+ * bytes. However, bytes cannot be individually addressed by clients.
+ */
+ BLOB,
+ /**
+ * The field is a structure that may contain other fields.
+ */
+ STRUCT = 0x20000,
+ };
+ /**
+ * Type of the field.
+ */
+ bitfield<Type> type;
+
+ /**
+ * If #type is #Type.STRUCT, #structIndex is the C2Param structure index;
+ * otherwise, #structIndex is not used.
+ */
+ ParamIndex structIndex;
+
+ /**
+ * Extent of the field.
+ * - For a non-array field, #extent is 1.
+ * - For a fixed-length array field, #extent is the length. An array field
+ * of length 1 is indistinguishable from a non-array field.
+ * - For a variable-length array field, #extent is 0. This can only occur as
+ * the last member of a C2Param structure.
+ */
+ uint32_t extent;
+
+ /**
+ * Name of the field. This must be unique for each field in the same
+ * structure.
+ */
+ string name;
+
+ /**
+ * Named value type. This is used for defining an enum value for a numeric
+ * type.
+ */
+ struct NamedValue {
+ /**
+ * Name of the enum value. This must be unique for each enum value in
+ * the same field.
+ */
+ string name;
+ /**
+ * Underlying value of the enum value. Multiple enum names may have the
+ * same underlying value.
+ */
+ PrimitiveValue value;
+ };
+ /**
+ * List of enum values. This is not used when #type is not one of the
+ * numeric types.
+ */
+ vec<NamedValue> namedValues;
+};
+
+/**
+ * Description of a C2Param structure. It consists of an index and a list of
+ * `FieldDescriptor`s.
+ */
+struct StructDescriptor {
+ /**
+ * Index of the structure.
+ */
+ ParamIndex type;
+ /**
+ * List of fields in the structure.
+ *
+ * Fields are ordered by their offsets. A field that is a structure is
+ * ordered before its members.
+ */
+ vec<FieldDescriptor> fields;
+};
+
+/**
+ * Information describing the reason the parameter settings may fail, or may be
+ * overridden.
+ */
+struct SettingResult {
+ /** Failure code */
+ enum Failure : uint32_t {
+ /** Parameter is not supported. */
+ BAD_TYPE,
+ /** Parameter is not supported on the specific port. */
+ BAD_PORT,
+ /** Parameter is not supported on the specific stream. */
+ BAD_INDEX,
+ /** Parameter is read-only and cannot be set. */
+ READ_ONLY,
+ /** Parameter mismatches input data. */
+ MISMATCH,
+ /** Strict parameter does not accept value for the field at all. */
+ BAD_VALUE,
+ /**
+ * Strict parameter field value is in conflict with an/other
+ * setting(s).
+ */
+ CONFLICT,
+ /**
+ * Parameter field is out of range due to other settings. (This failure
+ * mode can only be used for strict calculated parameters.)
+ */
+ UNSUPPORTED,
+ /**
+ * Field does not access the requested parameter value at all. It has
+ * been corrected to the closest supported value. This failure mode is
+ * provided to give guidance as to what are the currently supported
+ * values for this field (which may be a subset of the at-all-potential
+ * values).
+ */
+ INFO_BAD_VALUE,
+ /**
+ * Requested parameter value is in conflict with an/other setting(s)
+ * and has been corrected to the closest supported value. This failure
+ * mode is given to provide guidance as to what are the currently
+ * supported values as well as to optionally provide suggestion to the
+ * client as to how to enable the requested parameter value.
+ */
+ INFO_CONFLICT,
+ };
+ Failure failure;
+
+ /**
+ * Failing (or corrected) field or parameter and optionally, currently
+ * supported values for the field. Values must only be set for field
+ * failures other than `BAD_VALUE`, and only if they are different from the
+ * globally supported values (e.g. due to restrictions by another parameter
+ * or input data).
+ */
+ ParamFieldValues field;
+
+ /**
+ * Conflicting parameters or fields with (optional) suggested values for any
+ * conflicting fields to avoid the conflict. Values must only be set for
+ * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code.
+ */
+ vec<ParamFieldValues> conflicts;
+};
+
+/**
+ * Ordering information of @ref FrameData objects. Each member is used for
+ * comparing urgency: a smaller difference from a reference value indicates that
+ * the associated Work object is more urgent. The reference value for each
+ * member is initialized the first time it is communicated between the client
+ * and the codec, and it may be updated to later values that are communicated.
+ *
+ * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual
+ * order it represents is derived by subtracting the reference value, then
+ * interpreting the result as a signed number with the same storage size (using
+ * two's complement).
+ *
+ * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
+ * Codec 2.0 standard.
+ */
+struct WorkOrdinal {
+ /**
+ * Timestamp in microseconds.
+ */
+ uint64_t timestampUs;
+ /**
+ * Frame index.
+ */
+ uint64_t frameIndex;
+ /**
+ * Component specific frame ordinal.
+ */
+ uint64_t customOrdinal;
+};
+
+/**
+ * Storage type for `BaseBlock`.
+ *
+ * A `BaseBlock` is a representation of a codec memory block. Coded data,
+ * decoded data, codec-specific data, and other codec-related data are all sent
+ * in the form of BaseBlocks.
+ */
+safe_union BaseBlock {
+ /**
+ * #nativeBlock is the opaque representation of a buffer.
+ */
+ handle nativeBlock;
+ /**
+ * #pooledBlock is a reference to a buffer handled by a BufferPool.
+ */
+ BufferStatusMessage pooledBlock;
+};
+
+/**
+ * Reference to a @ref BaseBlock within a @ref WorkBundle.
+ *
+ * `Block` contains additional attributes that `BaseBlock` does not. These
+ * attributes may differ among `Block` objects that refer to the same
+ * `BaseBlock` in the same `WorkBundle`.
+ */
+struct Block {
+ /**
+ * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into
+ * #WorkBundle.baseBlocks.
+ */
+ uint32_t index;
+ /**
+ * Metadata associated with this `Block`.
+ */
+ Params meta;
+ /**
+ * Fence for synchronizing `Block` access.
+ */
+ handle fence;
+};
+
+/**
+ * A codec buffer, which is a collection of @ref Block objects and metadata.
+ *
+ * This is a part of @ref FrameData.
+ */
+struct Buffer {
+ /**
+ * Metadata associated with the buffer.
+ */
+ Params info;
+ /**
+ * Blocks contained in the buffer.
+ */
+ vec<Block> blocks;
+};
+
+/**
+ * An extension of @ref Buffer that also contains a C2Param structure index.
+ *
+ * This is a part of @ref FrameData.
+ */
+struct InfoBuffer {
+ /**
+ * A C2Param structure index.
+ */
+ ParamIndex index;
+ /**
+ * Associated @ref Buffer object.
+ */
+ Buffer buffer;
+};
+
+/**
+ * Data for an input frame or an output frame.
+ *
+ * This structure represents a @e frame with its metadata. A @e frame consists
+ * of an ordered set of buffers, configuration changes, and info buffers along
+ * with some non-configuration metadata.
+ *
+ * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
+ * standard.
+ */
+struct FrameData {
+ enum Flags : uint32_t {
+ /**
+ * For input frames: no output frame shall be generated when processing
+ * this frame, but metadata must still be processed.
+ *
+ * For output frames: this frame must be discarded but metadata is still
+ * valid.
+ */
+ DROP_FRAME = (1 << 0),
+ /**
+ * This frame is the last frame of the current stream. Further frames
+ * are part of a new stream.
+ */
+ END_OF_STREAM = (1 << 1),
+ /**
+ * This frame must be discarded with its metadata.
+ *
+ * This flag is only set by components, e.g. as a response to the flush
+ * command.
+ */
+ DISCARD_FRAME = (1 << 2),
+ /**
+ * This frame is not the last frame produced for the input.
+ *
+ * This flag is normally set by the component - e.g. when an input frame
+ * results in multiple output frames, this flag is set on all but the
+ * last output frame.
+ *
+ * Also, when components are chained, this flag should be propagated
+ * down the work chain. That is, if set on an earlier frame of a
+ * work-chain, it should be propagated to all later frames in that
+ * chain. Additionally, components down the chain could set this flag
+ * even if not set earlier, e.g. if multiple output frames are generated
+ * at that component for the input frame.
+ */
+ FLAG_INCOMPLETE = (1 << 3),
+ /**
+ * This frame contains only codec-specific configuration data, and no
+ * actual access unit.
+ *
+ * @deprecated Pass codec configuration with the codec-specific
+ * configuration info together with the access unit.
+ */
+ CODEC_CONFIG = (1u << 31),
+ };
+
+ /**
+ * Frame flags, as described in #Flags.
+ */
+ bitfield<Flags> flags;
+
+ /**
+ * @ref WorkOrdinal of the frame.
+ */
+ WorkOrdinal ordinal;
+
+ /**
+ * List of frame buffers.
+ */
+ vec<Buffer> buffers;
+
+ /**
+ * List of configuration updates.
+ */
+ Params configUpdate;
+
+ /**
+ * List of info buffers.
+ */
+ vec<InfoBuffer> infoBuffers;
+};
+
+/**
+ * In/out structure containing some instructions for and results from output
+ * processing.
+ *
+ * This is a part of @ref Work. One `Worklet` corresponds to one output
+ * @ref FrameData. The client must construct an original `Worklet` object inside
+ * a @ref Work object for each expected output before calling
+ * IComponent::queue().
+ */
+struct Worklet {
+ /**
+ * Component id. (Input)
+ *
+ * This is used only when tunneling is enabled.
+ *
+ * When used, this must match the return value from IConfigurable::getId().
+ */
+ uint32_t componentId;
+
+ /**
+ * List of C2Param objects describing tunings to be applied before
+ * processing this `Worklet`. (Input)
+ */
+ Params tunings;
+
+ /**
+ * Flag determining whether this `Worklet` has output or not.
+ */
+ bool hasOutput;
+
+ /**
+ * List of failures. (Output)
+ */
+ vec<SettingResult> failures;
+
+ /**
+ * Output frame data. (Output)
+ */
+ FrameData output;
+};
+
+/**
+ * A collection of input data to and output data from the component.
+ *
+ * A `Work` object holds information about a single work item. It is created by
+ * the client and passed to the component via IComponent::queue(). The component
+ * has two ways of returning a `Work` object to the client:
+ * 1. If the queued `Work` object has been successfully processed,
+ * IComponentListener::onWorkDone() shall be called to notify the listener,
+ * and the output shall be included in the returned `Work` object.
+ * 2. If the client calls IComponent::flush(), a `Work` object that has not
+ * been processed shall be returned.
+ *
+ * `Work` is a part of @ref WorkBundle.
+ */
+struct Work {
+ /**
+ * Additional work chain info not part of this work.
+ */
+ Params chainInfo;
+
+ /**
+ * @ref FrameData for the input.
+ */
+ FrameData input;
+
+ /**
+ * The chain of `Worklet`s.
+ *
+ * The length of #worklets is 1 when tunneling is not enabled.
+ *
+ * If #worklets has more than a single element, the tunnels between
+ * successive components of the work chain must have been successfully
+ * pre-registered at the time that the `Work` is submitted. Allocating the
+ * output buffers in the `Worklet`s is the responsibility of each component
+ * in the chain.
+ *
+ * Upon `Work` submission, #worklets must be an appropriately sized vector
+ * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a
+ * successful processing, all but the final `Worklet` in the returned
+ * #worklets must have @ref Worklet.hasOutput set to `false`.
+ */
+ vec<Worklet> worklets;
+
+ /**
+ * The number of `Worklet`s successfully processed in this chain.
+ *
+ * This must be initialized to 0 by the client when the `Work` is submitted,
+ * and it must contain the number of `Worklet`s that were successfully
+ * processed when the `Work` is returned to the client.
+ *
+ * #workletsProcessed cannot exceed the length of #worklets. If
+ * #workletsProcessed is smaller than the length of #worklets, #result
+ * cannot be `OK`.
+ */
+ uint32_t workletsProcessed;
+
+ /**
+ * The final outcome of the `Work` (corresponding to #workletsProcessed).
+ *
+ * The value of @ref Status.OK implies that all `Worklet`s have been
+ * successfully processed.
+ */
+ Status result;
+};
+
+/**
+ * List of `Work` objects.
+ *
+ * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and
+ * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of
+ * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work`
+ * objects together provides two benefits:
+ * 1. Batching of `Work` objects can reduce the number of IPC calls.
+ * 2. If multiple `Work` objects contain `Block`s that refer to the same
+ * `BaseBlock`, the number of `BaseBlock`s that is sent between processes
+ * is also reduced.
+ *
+ * @note `WorkBundle` is the HIDL counterpart of the vector of `C2Work` in the
+ * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the
+ * data transferred over an IPC.
+ */
+struct WorkBundle {
+ /**
+ * A list of Work items.
+ */
+ vec<Work> works;
+ /**
+ * A list of blocks indexed by elements of #works.
+ */
+ vec<BaseBlock> baseBlocks;
+};
+
+/**
+ * Query information for supported values of a field. This is used as input to
+ * IConfigurable::querySupportedValues().
+ */
+struct FieldSupportedValuesQuery {
+ /**
+ * Identity of the field to query.
+ */
+ ParamField field;
+
+ enum Type : uint32_t {
+ /** Query all possible values regardless of other settings. */
+ POSSIBLE,
+ /** Query currently possible values given dependent settings. */
+ CURRENT,
+ };
+ /**
+ * Type of the query. See #Type for more information.
+ */
+ Type type;
+};
+
+/**
+ * This structure is used to hold the result from
+ * IConfigurable::querySupportedValues().
+ */
+struct FieldSupportedValuesQueryResult {
+ /**
+ * Result of the query. Possible values are
+ * - `OK`: The query was successful.
+ * - `BAD_STATE`: The query was requested when the `IConfigurable` instance
+ * was in a bad state.
+ * - `BAD_INDEX`: The requested field was not recognized.
+ * - `TIMED_OUT`: The query could not be completed in a timely manner.
+ * - `BLOCKING`: The query must block, but the parameter `mayBlock` in the
+ * call to `querySupportedValues()` was `false`.
+ * - `CORRUPTED`: Some unknown error occurred.
+ */
+ Status status;
+
+ /**
+ * Supported values. This is meaningful only when #status is `OK`.
+ */
+ FieldSupportedValues values;
+};
+
diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
index e851a7c..4543c01 100644
--- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
+++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
@@ -297,6 +297,7 @@
setupAACPort(omxNode, portIndex, OMX_AUDIO_AACObjectNull,
OMX_AUDIO_AACStreamFormatMP4FF, nChannels, 0,
nSampleRate);
+ break;
default:
break;
}
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 18f35c1..234527a 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -28,6 +28,7 @@
"android.hardware.neuralnetworks@1.2",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libgmock",
"libhidlmemory",
"libneuralnetworks_utils",
],
@@ -38,23 +39,21 @@
],
}
-cc_test {
- name: "VtsHalNeuralnetworksV1_0TargetTest",
+cc_defaults {
+ name: "VtsHalNeuralNetworksTargetTestDefaults",
+ defaults: ["VtsHalTargetTestDefaults"],
srcs: [
- "BasicTests.cpp",
- "GeneratedTests.cpp",
"ValidateModel.cpp",
"ValidateRequest.cpp",
- "ValidationTests.cpp",
"VtsHalNeuralnetworks.cpp",
],
- defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libgmock",
"libhidlmemory",
"libneuralnetworks_utils",
"VtsHalNeuralnetworksTest_utils",
@@ -64,4 +63,22 @@
"libneuralnetworks_generated_test_harness_headers",
"libneuralnetworks_generated_tests",
],
+ // Bug: http://b/74200014 - Disable arm32 asan since it triggers internal
+ // error in ld.gold.
+ arch: {
+ arm: {
+ sanitize: {
+ never: true,
+ },
+ },
+ },
+}
+
+cc_test {
+ name: "VtsHalNeuralnetworksV1_0TargetTest",
+ defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ srcs: [
+ "BasicTests.cpp",
+ "GeneratedTests.cpp",
+ ],
}
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index b8046c7..802d018 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -36,16 +36,18 @@
namespace generated_tests {
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::test_helper::compare;
+using ::test_helper::expectMultinomialDistributionWithinTolerance;
using ::test_helper::filter;
+using ::test_helper::Float32Operands;
using ::test_helper::for_all;
using ::test_helper::for_each;
-using ::test_helper::resize_accordingly;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExampleType;
-using ::test_helper::Float32Operands;
using ::test_helper::Int32Operands;
+using ::test_helper::MixedTyped;
+using ::test_helper::MixedTypedExample;
+using ::test_helper::MixedTypedIndex;
using ::test_helper::Quant8Operands;
-using ::test_helper::compare;
+using ::test_helper::resize_accordingly;
template <typename T>
void copy_back_(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) {
@@ -61,12 +63,17 @@
copy_back_<float>(dst, ra, src);
copy_back_<int32_t>(dst, ra, src);
copy_back_<uint8_t>(dst, ra, src);
+ copy_back_<int16_t>(dst, ra, src);
+ copy_back_<_Float16>(dst, ra, src);
+ static_assert(5 == std::tuple_size<MixedTyped>::value,
+ "Number of types in MixedTyped changed, but copy_back function wasn't updated");
}
// Top level driver for models and examples generated by test_generator.py
// Test driver for those generated from ml/nn/runtime/test/spec
void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExampleType>& examples, float fpAtol = 1e-5f,
+ const std::vector<MixedTypedExample>& examples,
+ bool hasRelaxedFloat32Model = false, float fpAtol = 1e-5f,
float fpRtol = 1e-5f) {
const uint32_t INPUT = 0;
const uint32_t OUTPUT = 1;
@@ -74,13 +81,20 @@
int example_no = 1;
for (auto& example : examples) {
SCOPED_TRACE(example_no++);
+ const MixedTyped& inputs = example.operands.first;
+ const MixedTyped& golden = example.operands.second;
- const MixedTyped& inputs = example.first;
- const MixedTyped& golden = example.second;
+ const bool hasFloat16Inputs = !std::get<MixedTypedIndex<_Float16>::index>(inputs).empty();
+ if (hasRelaxedFloat32Model || hasFloat16Inputs) {
+ // TODO: Adjust the error limit based on testing.
+ // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
+ fpAtol = 5.0f * 0.0009765625f;
+ // Set the relative tolerance to be 5ULP of the corresponding FP precision.
+ fpRtol = 5.0f * 0.0009765625f;
+ }
std::vector<RequestArgument> inputs_info, outputs_info;
uint32_t inputSize = 0, outputSize = 0;
-
// This function only partially specifies the metadata (vector of RequestArguments).
// The contents are copied over below.
for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
@@ -176,12 +190,15 @@
// We want "close-enough" results for float
compare(filtered_golden, filtered_test, fpAtol, fpRtol);
+
+ if (example.expectedMultinomialDistributionTolerance > 0) {
+ expectMultinomialDistributionWithinTolerance(test, example);
+ }
}
}
void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
- std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExampleType>& examples) {
+ std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
V1_0::Model model = create_model();
// see if service can handle model
@@ -221,12 +238,12 @@
ASSERT_NE(nullptr, preparedModel.get());
float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f;
- EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples,
+ /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol);
}
void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
- std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExampleType>& examples) {
+ std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
V1_1::Model model = create_model();
// see if service can handle model
@@ -266,19 +283,13 @@
EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
ASSERT_NE(nullptr, preparedModel.get());
- // TODO: Adjust the error limit based on testing.
- // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
- float fpAtol = !model.relaxComputationFloat32toFloat16 ? 1e-5f : 5.0f * 0.0009765625f;
- // Set the relative tolerance to be 5ULP of the corresponding FP precision.
- float fpRtol = !model.relaxComputationFloat32toFloat16 ? 5.0f * 1.1920928955078125e-7f
- : 5.0f * 0.0009765625f;
- EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples,
+ model.relaxComputationFloat32toFloat16);
}
// TODO: Reduce code duplication.
void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
- std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExampleType>& examples) {
+ std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
V1_2::Model model = create_model();
// see if service can handle model
@@ -318,13 +329,8 @@
EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
ASSERT_NE(nullptr, preparedModel.get());
- // TODO: Adjust the error limit based on testing.
- // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
- float fpAtol = !model.relaxComputationFloat32toFloat16 ? 1e-5f : 5.0f * 0.0009765625f;
- // Set the relative tolerance to be 5ULP of the corresponding FP precision.
- float fpRtol = !model.relaxComputationFloat32toFloat16 ? 5.0f * 1.1920928955078125e-7f
- : 5.0f * 0.0009765625f;
- EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples,
+ model.relaxComputationFloat32toFloat16);
}
} // namespace generated_tests
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
index d84479c..26b4d8b 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
@@ -31,9 +31,9 @@
namespace neuralnetworks {
namespace generated_tests {
-using ::test_helper::MixedTypedExampleType;
+using ::test_helper::MixedTypedExample;
extern void Execute(const sp<V1_0::IDevice>&, std::function<V1_0::Model(void)>,
- std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
+ std::function<bool(int)>, const std::vector<MixedTypedExample>&);
} // namespace generated_tests
namespace V1_0 {
@@ -43,9 +43,9 @@
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
using ::android::nn::allocateSharedMemory;
+using ::test_helper::MixedTypedExample;
-// Mixed-typed examples
-typedef test_helper::MixedTypedExampleType MixedTypedExample;
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
// in frameworks/ml/nn/runtime/tests/generated/
#include "all_generated_V1_0_vts_tests.cpp"
diff --git a/neuralnetworks/1.0/vts/functional/Models.h b/neuralnetworks/1.0/vts/functional/Models.h
deleted file mode 100644
index 751ab32..0000000
--- a/neuralnetworks/1.0/vts/functional/Models.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
-#define VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "TestHarness.h"
-
-#include <android/hardware/neuralnetworks/1.0/types.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-
-using MixedTypedExample = test_helper::MixedTypedExampleType;
-
-#define FOR_EACH_TEST_MODEL(FN) \
- FN(add_broadcast_quant8) \
- FN(add) \
- FN(add_quant8) \
- FN(avg_pool_float_1) \
- FN(avg_pool_float_2) \
- FN(avg_pool_float_3) \
- FN(avg_pool_float_4) \
- FN(avg_pool_float_5) \
- FN(avg_pool_quant8_1) \
- FN(avg_pool_quant8_2) \
- FN(avg_pool_quant8_3) \
- FN(avg_pool_quant8_4) \
- FN(avg_pool_quant8_5) \
- FN(concat_float_1) \
- FN(concat_float_2) \
- FN(concat_float_3) \
- FN(concat_quant8_1) \
- FN(concat_quant8_2) \
- FN(concat_quant8_3) \
- FN(conv_1_h3_w2_SAME) \
- FN(conv_1_h3_w2_VALID) \
- FN(conv_3_h3_w2_SAME) \
- FN(conv_3_h3_w2_VALID) \
- FN(conv_float_2) \
- FN(conv_float_channels) \
- FN(conv_float_channels_weights_as_inputs) \
- FN(conv_float_large) \
- FN(conv_float_large_weights_as_inputs) \
- FN(conv_float) \
- FN(conv_float_weights_as_inputs) \
- FN(conv_quant8_2) \
- FN(conv_quant8_channels) \
- FN(conv_quant8_channels_weights_as_inputs) \
- FN(conv_quant8_large) \
- FN(conv_quant8_large_weights_as_inputs) \
- FN(conv_quant8) \
- FN(conv_quant8_overflow) \
- FN(conv_quant8_overflow_weights_as_inputs) \
- FN(conv_quant8_weights_as_inputs) \
- FN(depth_to_space_float_1) \
- FN(depth_to_space_float_2) \
- FN(depth_to_space_float_3) \
- FN(depth_to_space_quant8_1) \
- FN(depth_to_space_quant8_2) \
- FN(depthwise_conv2d_float_2) \
- FN(depthwise_conv2d_float_large_2) \
- FN(depthwise_conv2d_float_large_2_weights_as_inputs) \
- FN(depthwise_conv2d_float_large) \
- FN(depthwise_conv2d_float_large_weights_as_inputs) \
- FN(depthwise_conv2d_float) \
- FN(depthwise_conv2d_float_weights_as_inputs) \
- FN(depthwise_conv2d_quant8_2) \
- FN(depthwise_conv2d_quant8_large) \
- FN(depthwise_conv2d_quant8_large_weights_as_inputs) \
- FN(depthwise_conv2d_quant8) \
- FN(depthwise_conv2d_quant8_weights_as_inputs) \
- FN(depthwise_conv) \
- FN(dequantize) \
- FN(embedding_lookup) \
- FN(floor) \
- FN(fully_connected_float_2) \
- FN(fully_connected_float_large) \
- FN(fully_connected_float_large_weights_as_inputs) \
- FN(fully_connected_float) \
- FN(fully_connected_float_weights_as_inputs) \
- FN(fully_connected_quant8_2) \
- FN(fully_connected_quant8_large) \
- FN(fully_connected_quant8_large_weights_as_inputs) \
- FN(fully_connected_quant8) \
- FN(fully_connected_quant8_weights_as_inputs) \
- FN(hashtable_lookup_float) \
- FN(hashtable_lookup_quant8) \
- FN(l2_normalization_2) \
- FN(l2_normalization_large) \
- FN(l2_normalization) \
- FN(l2_pool_float_2) \
- FN(l2_pool_float_large) \
- FN(l2_pool_float) \
- FN(local_response_norm_float_1) \
- FN(local_response_norm_float_2) \
- FN(local_response_norm_float_3) \
- FN(local_response_norm_float_4) \
- FN(logistic_float_1) \
- FN(logistic_float_2) \
- FN(logistic_quant8_1) \
- FN(logistic_quant8_2) \
- FN(lsh_projection_2) \
- FN(lsh_projection) \
- FN(lsh_projection_weights_as_inputs) \
- FN(lstm2) \
- FN(lstm2_state2) \
- FN(lstm2_state) \
- FN(lstm3) \
- FN(lstm3_state2) \
- FN(lstm3_state3) \
- FN(lstm3_state) \
- FN(lstm) \
- FN(lstm_state2) \
- FN(lstm_state) \
- FN(max_pool_float_1) \
- FN(max_pool_float_2) \
- FN(max_pool_float_3) \
- FN(max_pool_float_4) \
- FN(max_pool_quant8_1) \
- FN(max_pool_quant8_2) \
- FN(max_pool_quant8_3) \
- FN(max_pool_quant8_4) \
- FN(mobilenet_224_gender_basic_fixed) \
- FN(mobilenet_quantized) \
- FN(mul_broadcast_quant8) \
- FN(mul) \
- FN(mul_quant8) \
- FN(mul_relu) \
- FN(relu1_float_1) \
- FN(relu1_float_2) \
- FN(relu1_quant8_1) \
- FN(relu1_quant8_2) \
- FN(relu6_float_1) \
- FN(relu6_float_2) \
- FN(relu6_quant8_1) \
- FN(relu6_quant8_2) \
- FN(relu_float_1) \
- FN(relu_float_2) \
- FN(relu_quant8_1) \
- FN(relu_quant8_2) \
- FN(reshape) \
- FN(reshape_quant8) \
- FN(reshape_quant8_weights_as_inputs) \
- FN(reshape_weights_as_inputs) \
- FN(resize_bilinear_2) \
- FN(resize_bilinear) \
- FN(rnn) \
- FN(rnn_state) \
- FN(softmax_float_1) \
- FN(softmax_float_2) \
- FN(softmax_quant8_1) \
- FN(softmax_quant8_2) \
- FN(space_to_depth_float_1) \
- FN(space_to_depth_float_2) \
- FN(space_to_depth_float_3) \
- FN(space_to_depth_quant8_1) \
- FN(space_to_depth_quant8_2) \
- FN(svdf2) \
- FN(svdf) \
- FN(svdf_state) \
- FN(tanh)
-
-#define FORWARD_DECLARE_GENERATED_OBJECTS(function) \
- namespace function { \
- extern std::vector<MixedTypedExample> examples; \
- Model createTestModel(); \
- }
-
-FOR_EACH_TEST_MODEL(FORWARD_DECLARE_GENERATED_OBJECTS)
-
-#undef FORWARD_DECLARE_GENERATED_OBJECTS
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_0
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
-
-#endif // VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
index 09c1878..1d3dee3 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -36,9 +36,9 @@
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExampleType;
using test_helper::for_all;
+using test_helper::MixedTyped;
+using test_helper::MixedTypedExample;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -151,15 +151,15 @@
///////////////////////////// ENTRY POINT //////////////////////////////////
-std::vector<Request> createRequests(const std::vector<MixedTypedExampleType>& examples) {
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
const uint32_t INPUT = 0;
const uint32_t OUTPUT = 1;
std::vector<Request> requests;
- for (auto& example : examples) {
- const MixedTyped& inputs = example.first;
- const MixedTyped& outputs = example.second;
+ for (const MixedTypedExample& example : examples) {
+ const MixedTyped& inputs = example.operands.first;
+ const MixedTyped& outputs = example.operands.second;
std::vector<RequestArgument> inputs_info, outputs_info;
uint32_t inputSize = 0, outputSize = 0;
diff --git a/neuralnetworks/1.0/vts/functional/ValidationTests.cpp b/neuralnetworks/1.0/vts/functional/ValidationTests.cpp
deleted file mode 100644
index 98fc1c5..0000000
--- a/neuralnetworks/1.0/vts/functional/ValidationTests.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "Models.h"
-#include "VtsHalNeuralnetworks.h"
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-
-// forward declarations
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// generate validation tests
-#define VTS_CURRENT_TEST_CASE(TestName) \
- TEST_F(ValidationTest, TestName) { \
- const Model model = TestName::createTestModel(); \
- const std::vector<Request> requests = createRequests(TestName::examples); \
- validateModel(model); \
- validateRequests(model, requests); \
- }
-
-FOR_EACH_TEST_MODEL(VTS_CURRENT_TEST_CASE)
-
-#undef VTS_CURRENT_TEST_CASE
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_0
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 52a804a..07c9b6e 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -14,39 +14,21 @@
// limitations under the License.
//
+// Tests for V1_0 models using the V1_1 HAL.
+cc_test {
+ name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest",
+ defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ srcs: [
+ "GeneratedTestsV1_0.cpp",
+ ],
+}
+
+// Tests for V1_1 models.
cc_test {
name: "VtsHalNeuralnetworksV1_1TargetTest",
+ defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
srcs: [
"BasicTests.cpp",
"GeneratedTests.cpp",
- "ValidateModel.cpp",
- "ValidateRequest.cpp",
- "ValidationTests.cpp",
- "VtsHalNeuralnetworks.cpp",
],
- defaults: ["VtsHalTargetTestDefaults"],
- static_libs: [
- "android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- "android.hardware.neuralnetworks@1.2",
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
- "libhidlmemory",
- "libneuralnetworks_utils",
- "VtsHalNeuralnetworksTest_utils",
- ],
- header_libs: [
- "libneuralnetworks_headers",
- "libneuralnetworks_generated_test_harness_headers",
- "libneuralnetworks_generated_tests",
- ],
- // Bug: http://b/74200014 - Disable arm32 asan since it triggers internal
- // error in ld.gold.
- arch: {
- arm: {
- sanitize: {
- never: true,
- },
- },
- },
}
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
index 95c2b1a..290a9d3 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
@@ -31,9 +31,9 @@
namespace neuralnetworks {
namespace generated_tests {
-using ::test_helper::MixedTypedExampleType;
+using ::test_helper::MixedTypedExample;
extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>,
- std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
+ std::function<bool(int)>, const std::vector<MixedTypedExample>&);
} // namespace generated_tests
namespace V1_1 {
@@ -43,12 +43,11 @@
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
using ::android::nn::allocateSharedMemory;
+using ::test_helper::MixedTypedExample;
-// Mixed-typed examples
-typedef generated_tests::MixedTypedExampleType MixedTypedExample;
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
#include "all_generated_V1_1_vts_tests.cpp"
} // namespace functional
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp
new file mode 100644
index 0000000..a36b24c
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+namespace generated_tests {
+using ::test_helper::MixedTypedExample;
+extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>,
+ std::function<bool(int)>, const std::vector<MixedTypedExample>&);
+} // namespace generated_tests
+
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
+using ::test_helper::MixedTypedExample;
+
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
+
+// in frameworks/ml/nn/runtime/tests/generated/
+#include "all_generated_V1_0_vts_tests.cpp"
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/Models.h b/neuralnetworks/1.1/vts/functional/Models.h
deleted file mode 100644
index cc0fac1..0000000
--- a/neuralnetworks/1.1/vts/functional/Models.h
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
-#define VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "TestHarness.h"
-
-#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-
-using MixedTypedExample = test_helper::MixedTypedExampleType;
-
-#define FOR_EACH_TEST_MODEL(FN) \
- FN(add) \
- FN(add_broadcast_quant8) \
- FN(add_quant8) \
- FN(add_relaxed) \
- FN(avg_pool_float_1) \
- FN(avg_pool_float_1_relaxed) \
- FN(avg_pool_float_2) \
- FN(avg_pool_float_2_relaxed) \
- FN(avg_pool_float_3) \
- FN(avg_pool_float_3_relaxed) \
- FN(avg_pool_float_4) \
- FN(avg_pool_float_4_relaxed) \
- FN(avg_pool_float_5) \
- FN(avg_pool_float_5_relaxed) \
- FN(avg_pool_quant8_1) \
- FN(avg_pool_quant8_2) \
- FN(avg_pool_quant8_3) \
- FN(avg_pool_quant8_4) \
- FN(avg_pool_quant8_5) \
- FN(batch_to_space) \
- FN(batch_to_space_float_1) \
- FN(batch_to_space_float_1_relaxed) \
- FN(batch_to_space_quant8_1) \
- FN(batch_to_space_relaxed) \
- FN(concat_float_1) \
- FN(concat_float_1_relaxed) \
- FN(concat_float_2) \
- FN(concat_float_2_relaxed) \
- FN(concat_float_3) \
- FN(concat_float_3_relaxed) \
- FN(concat_quant8_1) \
- FN(concat_quant8_2) \
- FN(concat_quant8_3) \
- FN(conv_1_h3_w2_SAME) \
- FN(conv_1_h3_w2_SAME_relaxed) \
- FN(conv_1_h3_w2_VALID) \
- FN(conv_1_h3_w2_VALID_relaxed) \
- FN(conv_3_h3_w2_SAME) \
- FN(conv_3_h3_w2_SAME_relaxed) \
- FN(conv_3_h3_w2_VALID) \
- FN(conv_3_h3_w2_VALID_relaxed) \
- FN(conv_float) \
- FN(conv_float_2) \
- FN(conv_float_2_relaxed) \
- FN(conv_float_channels) \
- FN(conv_float_channels_relaxed) \
- FN(conv_float_channels_weights_as_inputs) \
- FN(conv_float_channels_weights_as_inputs_relaxed) \
- FN(conv_float_large) \
- FN(conv_float_large_relaxed) \
- FN(conv_float_large_weights_as_inputs) \
- FN(conv_float_large_weights_as_inputs_relaxed) \
- FN(conv_float_relaxed) \
- FN(conv_float_weights_as_inputs) \
- FN(conv_float_weights_as_inputs_relaxed) \
- FN(conv_quant8) \
- FN(conv_quant8_2) \
- FN(conv_quant8_channels) \
- FN(conv_quant8_channels_weights_as_inputs) \
- FN(conv_quant8_large) \
- FN(conv_quant8_large_weights_as_inputs) \
- FN(conv_quant8_overflow) \
- FN(conv_quant8_overflow_weights_as_inputs) \
- FN(conv_quant8_weights_as_inputs) \
- FN(depth_to_space_float_1) \
- FN(depth_to_space_float_1_relaxed) \
- FN(depth_to_space_float_2) \
- FN(depth_to_space_float_2_relaxed) \
- FN(depth_to_space_float_3) \
- FN(depth_to_space_float_3_relaxed) \
- FN(depth_to_space_quant8_1) \
- FN(depth_to_space_quant8_2) \
- FN(depthwise_conv) \
- FN(depthwise_conv2d_float) \
- FN(depthwise_conv2d_float_2) \
- FN(depthwise_conv2d_float_2_relaxed) \
- FN(depthwise_conv2d_float_large) \
- FN(depthwise_conv2d_float_large_2) \
- FN(depthwise_conv2d_float_large_2_relaxed) \
- FN(depthwise_conv2d_float_large_2_weights_as_inputs) \
- FN(depthwise_conv2d_float_large_2_weights_as_inputs_relaxed) \
- FN(depthwise_conv2d_float_large_relaxed) \
- FN(depthwise_conv2d_float_large_weights_as_inputs) \
- FN(depthwise_conv2d_float_large_weights_as_inputs_relaxed) \
- FN(depthwise_conv2d_float_relaxed) \
- FN(depthwise_conv2d_float_weights_as_inputs) \
- FN(depthwise_conv2d_float_weights_as_inputs_relaxed) \
- FN(depthwise_conv2d_quant8) \
- FN(depthwise_conv2d_quant8_2) \
- FN(depthwise_conv2d_quant8_large) \
- FN(depthwise_conv2d_quant8_large_weights_as_inputs) \
- FN(depthwise_conv2d_quant8_weights_as_inputs) \
- FN(depthwise_conv_relaxed) \
- FN(dequantize) \
- FN(dequantize_relaxed) \
- FN(div) \
- FN(div_broadcast_float) \
- FN(div_broadcast_float_relaxed) \
- FN(div_relaxed) \
- FN(embedding_lookup) \
- FN(embedding_lookup_relaxed) \
- FN(floor) \
- FN(floor_relaxed) \
- FN(fully_connected_float) \
- FN(fully_connected_float_2) \
- FN(fully_connected_float_2_relaxed) \
- FN(fully_connected_float_4d_simple) \
- FN(fully_connected_float_4d_simple_relaxed) \
- FN(fully_connected_float_large) \
- FN(fully_connected_float_large_relaxed) \
- FN(fully_connected_float_large_weights_as_inputs) \
- FN(fully_connected_float_large_weights_as_inputs_relaxed) \
- FN(fully_connected_float_relaxed) \
- FN(fully_connected_float_weights_as_inputs) \
- FN(fully_connected_float_weights_as_inputs_relaxed) \
- FN(fully_connected_quant8) \
- FN(fully_connected_quant8_2) \
- FN(fully_connected_quant8_large) \
- FN(fully_connected_quant8_large_weights_as_inputs) \
- FN(fully_connected_quant8_weights_as_inputs) \
- FN(hashtable_lookup_float) \
- FN(hashtable_lookup_float_relaxed) \
- FN(hashtable_lookup_quant8) \
- FN(l2_normalization) \
- FN(l2_normalization_2) \
- FN(l2_normalization_2_relaxed) \
- FN(l2_normalization_large) \
- FN(l2_normalization_large_relaxed) \
- FN(l2_normalization_relaxed) \
- FN(l2_pool_float) \
- FN(l2_pool_float_2) \
- FN(l2_pool_float_2_relaxed) \
- FN(l2_pool_float_large) \
- FN(l2_pool_float_large_relaxed) \
- FN(l2_pool_float_relaxed) \
- FN(local_response_norm_float_1) \
- FN(local_response_norm_float_1_relaxed) \
- FN(local_response_norm_float_2) \
- FN(local_response_norm_float_2_relaxed) \
- FN(local_response_norm_float_3) \
- FN(local_response_norm_float_3_relaxed) \
- FN(local_response_norm_float_4) \
- FN(local_response_norm_float_4_relaxed) \
- FN(logistic_float_1) \
- FN(logistic_float_1_relaxed) \
- FN(logistic_float_2) \
- FN(logistic_float_2_relaxed) \
- FN(logistic_quant8_1) \
- FN(logistic_quant8_2) \
- FN(lsh_projection) \
- FN(lsh_projection_2) \
- FN(lsh_projection_2_relaxed) \
- FN(lsh_projection_relaxed) \
- FN(lsh_projection_weights_as_inputs) \
- FN(lsh_projection_weights_as_inputs_relaxed) \
- FN(lstm) \
- FN(lstm2) \
- FN(lstm2_relaxed) \
- FN(lstm2_state) \
- FN(lstm2_state2) \
- FN(lstm2_state2_relaxed) \
- FN(lstm2_state_relaxed) \
- FN(lstm3) \
- FN(lstm3_relaxed) \
- FN(lstm3_state) \
- FN(lstm3_state2) \
- FN(lstm3_state2_relaxed) \
- FN(lstm3_state3) \
- FN(lstm3_state3_relaxed) \
- FN(lstm3_state_relaxed) \
- FN(lstm_relaxed) \
- FN(lstm_state) \
- FN(lstm_state2) \
- FN(lstm_state2_relaxed) \
- FN(lstm_state_relaxed) \
- FN(max_pool_float_1) \
- FN(max_pool_float_1_relaxed) \
- FN(max_pool_float_2) \
- FN(max_pool_float_2_relaxed) \
- FN(max_pool_float_3) \
- FN(max_pool_float_3_relaxed) \
- FN(max_pool_float_4) \
- FN(max_pool_float_4_relaxed) \
- FN(max_pool_quant8_1) \
- FN(max_pool_quant8_2) \
- FN(max_pool_quant8_3) \
- FN(max_pool_quant8_4) \
- FN(mean) \
- FN(mean_float_1) \
- FN(mean_float_1_relaxed) \
- FN(mean_float_2) \
- FN(mean_float_2_relaxed) \
- FN(mean_quant8_1) \
- FN(mean_quant8_2) \
- FN(mean_relaxed) \
- FN(mobilenet_224_gender_basic_fixed) \
- FN(mobilenet_224_gender_basic_fixed_relaxed) \
- FN(mobilenet_quantized) \
- FN(mul) \
- FN(mul_broadcast_quant8) \
- FN(mul_quant8) \
- FN(mul_relaxed) \
- FN(mul_relu) \
- FN(mul_relu_relaxed) \
- FN(pad) \
- FN(pad_float_1) \
- FN(pad_float_1_relaxed) \
- FN(pad_relaxed) \
- FN(relu1_float_1) \
- FN(relu1_float_1_relaxed) \
- FN(relu1_float_2) \
- FN(relu1_float_2_relaxed) \
- FN(relu1_quant8_1) \
- FN(relu1_quant8_2) \
- FN(relu6_float_1) \
- FN(relu6_float_1_relaxed) \
- FN(relu6_float_2) \
- FN(relu6_float_2_relaxed) \
- FN(relu6_quant8_1) \
- FN(relu6_quant8_2) \
- FN(relu_float_1) \
- FN(relu_float_1_relaxed) \
- FN(relu_float_2) \
- FN(relu_float_2_relaxed) \
- FN(relu_quant8_1) \
- FN(relu_quant8_2) \
- FN(reshape) \
- FN(reshape_quant8) \
- FN(reshape_quant8_weights_as_inputs) \
- FN(reshape_relaxed) \
- FN(reshape_weights_as_inputs) \
- FN(reshape_weights_as_inputs_relaxed) \
- FN(resize_bilinear) \
- FN(resize_bilinear_2) \
- FN(resize_bilinear_2_relaxed) \
- FN(resize_bilinear_relaxed) \
- FN(rnn) \
- FN(rnn_relaxed) \
- FN(rnn_state) \
- FN(rnn_state_relaxed) \
- FN(softmax_float_1) \
- FN(softmax_float_1_relaxed) \
- FN(softmax_float_2) \
- FN(softmax_float_2_relaxed) \
- FN(softmax_quant8_1) \
- FN(softmax_quant8_2) \
- FN(space_to_batch) \
- FN(space_to_batch_float_1) \
- FN(space_to_batch_float_1_relaxed) \
- FN(space_to_batch_float_2) \
- FN(space_to_batch_float_2_relaxed) \
- FN(space_to_batch_float_3) \
- FN(space_to_batch_float_3_relaxed) \
- FN(space_to_batch_quant8_1) \
- FN(space_to_batch_quant8_2) \
- FN(space_to_batch_quant8_3) \
- FN(space_to_batch_relaxed) \
- FN(space_to_depth_float_1) \
- FN(space_to_depth_float_1_relaxed) \
- FN(space_to_depth_float_2) \
- FN(space_to_depth_float_2_relaxed) \
- FN(space_to_depth_float_3) \
- FN(space_to_depth_float_3_relaxed) \
- FN(space_to_depth_quant8_1) \
- FN(space_to_depth_quant8_2) \
- FN(squeeze) \
- FN(squeeze_float_1) \
- FN(squeeze_float_1_relaxed) \
- FN(squeeze_quant8_1) \
- FN(squeeze_relaxed) \
- FN(strided_slice) \
- FN(strided_slice_float_1) \
- FN(strided_slice_float_10) \
- FN(strided_slice_float_10_relaxed) \
- FN(strided_slice_float_11) \
- FN(strided_slice_float_11_relaxed) \
- FN(strided_slice_float_1_relaxed) \
- FN(strided_slice_float_2) \
- FN(strided_slice_float_2_relaxed) \
- FN(strided_slice_float_3) \
- FN(strided_slice_float_3_relaxed) \
- FN(strided_slice_float_4) \
- FN(strided_slice_float_4_relaxed) \
- FN(strided_slice_float_5) \
- FN(strided_slice_float_5_relaxed) \
- FN(strided_slice_float_6) \
- FN(strided_slice_float_6_relaxed) \
- FN(strided_slice_float_7) \
- FN(strided_slice_float_7_relaxed) \
- FN(strided_slice_float_8) \
- FN(strided_slice_float_8_relaxed) \
- FN(strided_slice_float_9) \
- FN(strided_slice_float_9_relaxed) \
- FN(strided_slice_qaunt8_10) \
- FN(strided_slice_qaunt8_11) \
- FN(strided_slice_quant8_1) \
- FN(strided_slice_quant8_2) \
- FN(strided_slice_quant8_3) \
- FN(strided_slice_quant8_4) \
- FN(strided_slice_quant8_5) \
- FN(strided_slice_quant8_6) \
- FN(strided_slice_quant8_7) \
- FN(strided_slice_quant8_8) \
- FN(strided_slice_quant8_9) \
- FN(strided_slice_relaxed) \
- FN(sub) \
- FN(sub_broadcast_float) \
- FN(sub_broadcast_float_relaxed) \
- FN(sub_relaxed) \
- FN(svdf) \
- FN(svdf2) \
- FN(svdf2_relaxed) \
- FN(svdf_relaxed) \
- FN(svdf_state) \
- FN(svdf_state_relaxed) \
- FN(tanh) \
- FN(tanh_relaxed) \
- FN(transpose) \
- FN(transpose_float_1) \
- FN(transpose_float_1_relaxed) \
- FN(transpose_quant8_1) \
- FN(transpose_relaxed)
-
-#define FORWARD_DECLARE_GENERATED_OBJECTS(function) \
- namespace function { \
- extern std::vector<MixedTypedExample> examples; \
- Model createTestModel(); \
- }
-
-FOR_EACH_TEST_MODEL(FORWARD_DECLARE_GENERATED_OBJECTS)
-
-#undef FORWARD_DECLARE_GENERATED_OBJECTS
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_1
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
-
-#endif // VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index 687b760..e7d96c7 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -36,9 +36,9 @@
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExampleType;
using test_helper::for_all;
+using test_helper::MixedTyped;
+using test_helper::MixedTypedExample;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -152,15 +152,15 @@
///////////////////////////// ENTRY POINT //////////////////////////////////
-std::vector<Request> createRequests(const std::vector<MixedTypedExampleType>& examples) {
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
const uint32_t INPUT = 0;
const uint32_t OUTPUT = 1;
std::vector<Request> requests;
for (auto& example : examples) {
- const MixedTyped& inputs = example.first;
- const MixedTyped& outputs = example.second;
+ const MixedTyped& inputs = example.operands.first;
+ const MixedTyped& outputs = example.operands.second;
std::vector<RequestArgument> inputs_info, outputs_info;
uint32_t inputSize = 0, outputSize = 0;
diff --git a/neuralnetworks/1.1/vts/functional/ValidationTests.cpp b/neuralnetworks/1.1/vts/functional/ValidationTests.cpp
deleted file mode 100644
index 1c35ba8..0000000
--- a/neuralnetworks/1.1/vts/functional/ValidationTests.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "Models.h"
-#include "VtsHalNeuralnetworks.h"
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-
-// forward declarations
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// generate validation tests
-#define VTS_CURRENT_TEST_CASE(TestName) \
- TEST_F(ValidationTest, TestName) { \
- const Model model = TestName::createTestModel(); \
- const std::vector<Request> requests = createRequests(TestName::examples); \
- validateModel(model); \
- validateRequests(model, requests); \
- }
-
-FOR_EACH_TEST_MODEL(VTS_CURRENT_TEST_CASE)
-
-#undef VTS_CURRENT_TEST_CASE
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_1
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 0050e52..a64268f 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -34,9 +34,11 @@
namespace neuralnetworks {
namespace V1_1 {
-using V1_0::Request;
using V1_0::DeviceStatus;
using V1_0::ErrorStatus;
+using V1_0::Operand;
+using V1_0::OperandType;
+using V1_0::Request;
namespace vts {
namespace functional {
diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp
index e183a26..5a661e0 100644
--- a/neuralnetworks/1.2/Android.bp
+++ b/neuralnetworks/1.2/Android.bp
@@ -17,8 +17,11 @@
],
types: [
"Model",
+ "Operand",
+ "OperandType",
"Operation",
"OperationType",
],
gen_java: false,
}
+
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index bed1d5c..fe9b312 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -16,10 +16,46 @@
package android.hardware.neuralnetworks@1.2;
-import @1.0::Operand;
+import @1.0::DataLocation;
+import @1.0::OperandLifeTime;
+import @1.0::OperandType;
import @1.0::PerformanceInfo;
import @1.1::OperationType;
+enum OperandType : @1.0::OperandType {
+ /**
+ * An 8 bit boolean scalar value.
+ *
+ * Values of this operand type are either true or false. A zero value
+ * represents false; any other value represents true.
+ */
+ BOOL = 6,
+ /**
+ * A tensor of 16 bit signed integers that represent real numbers.
+ *
+ * Attached to this tensor is a number representing real value scale that is
+ * used to convert the 16 bit number to a real value in the following way:
+ * realValue = integerValue * scale.
+ *
+ * scale is a 32 bit floating point with value greater then zero.
+ */
+ TENSOR_QUANT16_SYMM = 7,
+ /** A tensor of 16 bit floating point values. */
+ TENSOR_FLOAT16 = 8,
+};
+
+/**
+ * The range of values in the OperandType enum.
+ *
+ * THE MAX VALUES MUST BE UPDATED WHEN ADDING NEW TYPES to the OperandType enum.
+ */
+enum OperandTypeRange : uint32_t {
+ OPERAND_FUNDAMENTAL_MIN = 0,
+ OPERAND_FUNDAMENTAL_MAX = 8,
+ OPERAND_OEM_MIN = 10000,
+ OPERAND_OEM_MAX = 10001,
+};
+
/**
* Operation types.
*
@@ -77,6 +113,20 @@
UNIDIRECTIONAL_SEQUENCE_LSTM = 85,
UNIDIRECTIONAL_SEQUENCE_RNN = 86,
ROTATED_BBOX_TRANSFORM = 87,
+ ABS = 88,
+ ROI_POOLING = 89,
+};
+
+/**
+ * The range of values in the OperationType enum.
+ *
+ * THE MAX VALUES MUST BE UPDATED WHEN ADDING NEW TYPES to the OperationType enum.
+ */
+enum OperationTypeRange : uint32_t {
+ OPERATION_FUNDAMENTAL_MIN = 0,
+ OPERATION_FUNDAMENTAL_MAX = 87,
+ OPERATION_OEM_MIN = 10000,
+ OPERATION_OEM_MAX = 10000,
};
/**
@@ -102,6 +152,101 @@
};
/**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+ /**
+ * Data type of the operand.
+ */
+ OperandType type;
+
+ /**
+ * Dimensions of the operand.
+ *
+ * For a scalar operand, dimensions.size() must be 0.
+ *
+ * For a tensor operand, dimensions.size() must be at least 1;
+ * however, any of the dimensions may be unspecified.
+ *
+ * A tensor operand with all dimensions specified has "fully
+ * specified" dimensions. Whenever possible (i.e., whenever the
+ * dimensions are known at model construction time), a tensor
+ * operand should have (but is not required to have) fully
+ * specified dimensions, in order to enable the best possible
+ * performance.
+ *
+ * If a tensor operand's dimensions are not fully specified, the
+ * dimensions of the operand are deduced from the operand
+ * dimensions and values of the operation for which that operand
+ * is an output.
+ *
+ * In the following situations, a tensor operand's dimensions must
+ * be fully specified:
+ *
+ * . The operand has lifetime CONSTANT_COPY or
+ * CONSTANT_REFERENCE.
+ *
+ * . The operand has lifetime MODEL_INPUT or MODEL_OUTPUT. Fully
+ * specified dimensions must either be present in the
+ * Operand or they must be provided in the corresponding
+ * RequestArgument.
+ * EXCEPTION: If the input or output is optional and omitted
+ * (by setting the hasNoValue field of the corresponding
+ * RequestArgument to true) then it need not have fully
+ * specified dimensions.
+ *
+ * A tensor operand with some number of unspecified dimensions is
+ * represented by setting each unspecified dimension to 0.
+ */
+ vec<uint32_t> dimensions;
+
+ /**
+ * The number of times this operand appears as an operation input.
+ *
+ * (For example, if this operand appears once in one operation's
+ * input list, and three times in another operation's input list,
+ * then numberOfConsumers = 4.)
+ */
+ uint32_t numberOfConsumers;
+
+ /**
+ * Quantized scale of the operand.
+ *
+ * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+ * TENSOR_INT32.
+ */
+ float scale;
+
+ /**
+ * Quantized zero-point offset of the operand.
+ *
+ * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+ */
+ int32_t zeroPoint;
+
+ /**
+ * How the operand is used.
+ */
+ OperandLifeTime lifetime;
+
+ /**
+ * Where to find the data for this operand.
+ * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+ * NO_VALUE:
+ * - All the fields must be 0.
+ * If the lifetime is CONSTANT_COPY:
+ * - location.poolIndex is 0.
+ * - location.offset is the offset in bytes into Model.operandValues.
+ * - location.length is set.
+ * If the lifetime is CONSTANT_REFERENCE:
+ * - location.poolIndex is set.
+ * - location.offset is the offset in bytes into the specified pool.
+ * - location.length is set.
+ */
+ DataLocation location;
+};
+
+/**
* A Neural Network Model.
*
* This includes not only the execution graph, but also constant data such as
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 2dc19cc..085d5db 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -14,39 +14,30 @@
// limitations under the License.
//
+// Tests for V1_0 models using the V1_2 HAL.
+cc_test {
+ name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest",
+ defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ srcs: [
+ "GeneratedTestsV1_0.cpp",
+ ]
+}
+
+// Tests for V1_1 models using the V1_2 HAL.
+cc_test {
+ name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest",
+ defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ srcs: [
+ "GeneratedTestsV1_1.cpp",
+ ],
+}
+
+// Tests for V1_2 models.
cc_test {
name: "VtsHalNeuralnetworksV1_2TargetTest",
+ defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
srcs: [
"BasicTests.cpp",
"GeneratedTests.cpp",
- "ValidateModel.cpp",
- "ValidateRequest.cpp",
- "ValidationTests.cpp",
- "VtsHalNeuralnetworks.cpp",
],
- defaults: ["VtsHalTargetTestDefaults"],
- static_libs: [
- "android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- "android.hardware.neuralnetworks@1.2",
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
- "libhidlmemory",
- "libneuralnetworks_utils",
- "VtsHalNeuralnetworksTest_utils",
- ],
- header_libs: [
- "libneuralnetworks_headers",
- "libneuralnetworks_generated_test_harness_headers",
- "libneuralnetworks_generated_tests",
- ],
- // Bug: http://b/74200014 - Disable arm32 asan since it triggers internal
- // error in ld.gold.
- arch: {
- arm: {
- sanitize: {
- never: true,
- },
- },
- },
}
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
index 662c531..79d5a60 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
@@ -31,9 +31,9 @@
namespace neuralnetworks {
namespace generated_tests {
-using ::test_helper::MixedTypedExampleType;
+using ::test_helper::MixedTypedExample;
extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>,
- std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
+ std::function<bool(int)>, const std::vector<MixedTypedExample>&);
} // namespace generated_tests
namespace V1_2 {
@@ -43,13 +43,11 @@
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
using ::android::nn::allocateSharedMemory;
+using ::test_helper::MixedTypedExample;
-// Mixed-typed examples
-typedef generated_tests::MixedTypedExampleType MixedTypedExample;
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-#include "all_generated_V1_1_vts_tests.cpp"
#include "all_generated_V1_2_vts_tests.cpp"
} // namespace functional
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp
new file mode 100644
index 0000000..42e22b0
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+namespace generated_tests {
+using ::test_helper::MixedTypedExample;
+extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>,
+ std::function<bool(int)>, const std::vector<MixedTypedExample>&);
+} // namespace generated_tests
+
+namespace V1_2 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
+using ::test_helper::MixedTypedExample;
+
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
+
+// in frameworks/ml/nn/runtime/tests/generated/
+#include "all_generated_V1_0_vts_tests.cpp"
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp
new file mode 100644
index 0000000..aab5cb6
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+namespace generated_tests {
+using ::test_helper::MixedTypedExample;
+extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>,
+ std::function<bool(int)>, const std::vector<MixedTypedExample>&);
+} // namespace generated_tests
+
+namespace V1_2 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
+using ::test_helper::MixedTypedExample;
+
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
+
+// in frameworks/ml/nn/runtime/tests/generated/
+#include "all_generated_V1_1_vts_tests.cpp"
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/Models.h b/neuralnetworks/1.2/vts/functional/Models.h
deleted file mode 100644
index f3769bc..0000000
--- a/neuralnetworks/1.2/vts/functional/Models.h
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef VTS_HAL_NEURALNETWORKS_V1_2_VTS_FUNCTIONAL_MODELS_H
-#define VTS_HAL_NEURALNETWORKS_V1_2_VTS_FUNCTIONAL_MODELS_H
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "TestHarness.h"
-
-#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hardware/neuralnetworks/1.2/types.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using MixedTypedExample = test_helper::MixedTypedExampleType;
-
-#define FOR_EACH_TEST_MODEL(FN) \
- FN(add) \
- FN(add_broadcast_quant8) \
- FN(add_quant8) \
- FN(add_relaxed) \
- FN(avg_pool_float_1) \
- FN(avg_pool_float_1_relaxed) \
- FN(avg_pool_float_2) \
- FN(avg_pool_float_2_relaxed) \
- FN(avg_pool_float_3) \
- FN(avg_pool_float_3_relaxed) \
- FN(avg_pool_float_4) \
- FN(avg_pool_float_4_relaxed) \
- FN(avg_pool_float_5) \
- FN(avg_pool_float_5_relaxed) \
- FN(avg_pool_quant8_1) \
- FN(avg_pool_quant8_2) \
- FN(avg_pool_quant8_3) \
- FN(avg_pool_quant8_4) \
- FN(avg_pool_quant8_5) \
- FN(batch_to_space) \
- FN(batch_to_space_float_1) \
- FN(batch_to_space_float_1_relaxed) \
- FN(batch_to_space_quant8_1) \
- FN(batch_to_space_relaxed) \
- FN(concat_float_1) \
- FN(concat_float_1_relaxed) \
- FN(concat_float_2) \
- FN(concat_float_2_relaxed) \
- FN(concat_float_3) \
- FN(concat_float_3_relaxed) \
- FN(concat_quant8_1) \
- FN(concat_quant8_2) \
- FN(concat_quant8_3) \
- FN(conv_1_h3_w2_SAME) \
- FN(conv_1_h3_w2_SAME_relaxed) \
- FN(conv_1_h3_w2_VALID) \
- FN(conv_1_h3_w2_VALID_relaxed) \
- FN(conv_3_h3_w2_SAME) \
- FN(conv_3_h3_w2_SAME_relaxed) \
- FN(conv_3_h3_w2_VALID) \
- FN(conv_3_h3_w2_VALID_relaxed) \
- FN(conv_float) \
- FN(conv_float_2) \
- FN(conv_float_2_relaxed) \
- FN(conv_float_channels) \
- FN(conv_float_channels_relaxed) \
- FN(conv_float_channels_weights_as_inputs) \
- FN(conv_float_channels_weights_as_inputs_relaxed) \
- FN(conv_float_large) \
- FN(conv_float_large_relaxed) \
- FN(conv_float_large_weights_as_inputs) \
- FN(conv_float_large_weights_as_inputs_relaxed) \
- FN(conv_float_relaxed) \
- FN(conv_float_weights_as_inputs) \
- FN(conv_float_weights_as_inputs_relaxed) \
- FN(conv_quant8) \
- FN(conv_quant8_2) \
- FN(conv_quant8_channels) \
- FN(conv_quant8_channels_weights_as_inputs) \
- FN(conv_quant8_large) \
- FN(conv_quant8_large_weights_as_inputs) \
- FN(conv_quant8_overflow) \
- FN(conv_quant8_overflow_weights_as_inputs) \
- FN(conv_quant8_weights_as_inputs) \
- FN(depth_to_space_float_1) \
- FN(depth_to_space_float_1_relaxed) \
- FN(depth_to_space_float_2) \
- FN(depth_to_space_float_2_relaxed) \
- FN(depth_to_space_float_3) \
- FN(depth_to_space_float_3_relaxed) \
- FN(depth_to_space_quant8_1) \
- FN(depth_to_space_quant8_2) \
- FN(depthwise_conv) \
- FN(depthwise_conv2d_float) \
- FN(depthwise_conv2d_float_2) \
- FN(depthwise_conv2d_float_2_relaxed) \
- FN(depthwise_conv2d_float_large) \
- FN(depthwise_conv2d_float_large_2) \
- FN(depthwise_conv2d_float_large_2_relaxed) \
- FN(depthwise_conv2d_float_large_2_weights_as_inputs) \
- FN(depthwise_conv2d_float_large_2_weights_as_inputs_relaxed) \
- FN(depthwise_conv2d_float_large_relaxed) \
- FN(depthwise_conv2d_float_large_weights_as_inputs) \
- FN(depthwise_conv2d_float_large_weights_as_inputs_relaxed) \
- FN(depthwise_conv2d_float_relaxed) \
- FN(depthwise_conv2d_float_weights_as_inputs) \
- FN(depthwise_conv2d_float_weights_as_inputs_relaxed) \
- FN(depthwise_conv2d_quant8) \
- FN(depthwise_conv2d_quant8_2) \
- FN(depthwise_conv2d_quant8_large) \
- FN(depthwise_conv2d_quant8_large_weights_as_inputs) \
- FN(depthwise_conv2d_quant8_weights_as_inputs) \
- FN(depthwise_conv_relaxed) \
- FN(dequantize) \
- FN(dequantize_relaxed) \
- FN(div) \
- FN(div_broadcast_float) \
- FN(div_broadcast_float_relaxed) \
- FN(div_relaxed) \
- FN(embedding_lookup) \
- FN(embedding_lookup_relaxed) \
- FN(floor) \
- FN(floor_relaxed) \
- FN(fully_connected_float) \
- FN(fully_connected_float_2) \
- FN(fully_connected_float_2_relaxed) \
- FN(fully_connected_float_4d_simple) \
- FN(fully_connected_float_4d_simple_relaxed) \
- FN(fully_connected_float_large) \
- FN(fully_connected_float_large_relaxed) \
- FN(fully_connected_float_large_weights_as_inputs) \
- FN(fully_connected_float_large_weights_as_inputs_relaxed) \
- FN(fully_connected_float_relaxed) \
- FN(fully_connected_float_weights_as_inputs) \
- FN(fully_connected_float_weights_as_inputs_relaxed) \
- FN(fully_connected_quant8) \
- FN(fully_connected_quant8_2) \
- FN(fully_connected_quant8_large) \
- FN(fully_connected_quant8_large_weights_as_inputs) \
- FN(fully_connected_quant8_weights_as_inputs) \
- FN(hashtable_lookup_float) \
- FN(hashtable_lookup_float_relaxed) \
- FN(hashtable_lookup_quant8) \
- FN(l2_normalization) \
- FN(l2_normalization_2) \
- FN(l2_normalization_2_relaxed) \
- FN(l2_normalization_large) \
- FN(l2_normalization_large_relaxed) \
- FN(l2_normalization_relaxed) \
- FN(l2_pool_float) \
- FN(l2_pool_float_2) \
- FN(l2_pool_float_2_relaxed) \
- FN(l2_pool_float_large) \
- FN(l2_pool_float_large_relaxed) \
- FN(l2_pool_float_relaxed) \
- FN(local_response_norm_float_1) \
- FN(local_response_norm_float_1_relaxed) \
- FN(local_response_norm_float_2) \
- FN(local_response_norm_float_2_relaxed) \
- FN(local_response_norm_float_3) \
- FN(local_response_norm_float_3_relaxed) \
- FN(local_response_norm_float_4) \
- FN(local_response_norm_float_4_relaxed) \
- FN(logistic_float_1) \
- FN(logistic_float_1_relaxed) \
- FN(logistic_float_2) \
- FN(logistic_float_2_relaxed) \
- FN(logistic_quant8_1) \
- FN(logistic_quant8_2) \
- FN(lsh_projection) \
- FN(lsh_projection_2) \
- FN(lsh_projection_2_relaxed) \
- FN(lsh_projection_relaxed) \
- FN(lsh_projection_weights_as_inputs) \
- FN(lsh_projection_weights_as_inputs_relaxed) \
- FN(lstm) \
- FN(lstm2) \
- FN(lstm2_relaxed) \
- FN(lstm2_state) \
- FN(lstm2_state2) \
- FN(lstm2_state2_relaxed) \
- FN(lstm2_state_relaxed) \
- FN(lstm3) \
- FN(lstm3_relaxed) \
- FN(lstm3_state) \
- FN(lstm3_state2) \
- FN(lstm3_state2_relaxed) \
- FN(lstm3_state3) \
- FN(lstm3_state3_relaxed) \
- FN(lstm3_state_relaxed) \
- FN(lstm_relaxed) \
- FN(lstm_state) \
- FN(lstm_state2) \
- FN(lstm_state2_relaxed) \
- FN(lstm_state_relaxed) \
- FN(max_pool_float_1) \
- FN(max_pool_float_1_relaxed) \
- FN(max_pool_float_2) \
- FN(max_pool_float_2_relaxed) \
- FN(max_pool_float_3) \
- FN(max_pool_float_3_relaxed) \
- FN(max_pool_float_4) \
- FN(max_pool_float_4_relaxed) \
- FN(max_pool_quant8_1) \
- FN(max_pool_quant8_2) \
- FN(max_pool_quant8_3) \
- FN(max_pool_quant8_4) \
- FN(mean) \
- FN(mean_float_1) \
- FN(mean_float_1_relaxed) \
- FN(mean_float_2) \
- FN(mean_float_2_relaxed) \
- FN(mean_quant8_1) \
- FN(mean_quant8_2) \
- FN(mean_relaxed) \
- FN(mobilenet_224_gender_basic_fixed) \
- FN(mobilenet_224_gender_basic_fixed_relaxed) \
- FN(mobilenet_quantized) \
- FN(mul) \
- FN(mul_broadcast_quant8) \
- FN(mul_quant8) \
- FN(mul_relaxed) \
- FN(mul_relu) \
- FN(mul_relu_relaxed) \
- FN(pad) \
- FN(pad_float_1) \
- FN(pad_float_1_relaxed) \
- FN(pad_relaxed) \
- FN(relu1_float_1) \
- FN(relu1_float_1_relaxed) \
- FN(relu1_float_2) \
- FN(relu1_float_2_relaxed) \
- FN(relu1_quant8_1) \
- FN(relu1_quant8_2) \
- FN(relu6_float_1) \
- FN(relu6_float_1_relaxed) \
- FN(relu6_float_2) \
- FN(relu6_float_2_relaxed) \
- FN(relu6_quant8_1) \
- FN(relu6_quant8_2) \
- FN(relu_float_1) \
- FN(relu_float_1_relaxed) \
- FN(relu_float_2) \
- FN(relu_float_2_relaxed) \
- FN(relu_quant8_1) \
- FN(relu_quant8_2) \
- FN(reshape) \
- FN(reshape_quant8) \
- FN(reshape_quant8_weights_as_inputs) \
- FN(reshape_relaxed) \
- FN(reshape_weights_as_inputs) \
- FN(reshape_weights_as_inputs_relaxed) \
- FN(resize_bilinear) \
- FN(resize_bilinear_2) \
- FN(resize_bilinear_2_relaxed) \
- FN(resize_bilinear_relaxed) \
- FN(rnn) \
- FN(rnn_relaxed) \
- FN(rnn_state) \
- FN(rnn_state_relaxed) \
- FN(softmax_float_1) \
- FN(softmax_float_1_relaxed) \
- FN(softmax_float_2) \
- FN(softmax_float_2_relaxed) \
- FN(softmax_quant8_1) \
- FN(softmax_quant8_2) \
- FN(space_to_batch) \
- FN(space_to_batch_float_1) \
- FN(space_to_batch_float_1_relaxed) \
- FN(space_to_batch_float_2) \
- FN(space_to_batch_float_2_relaxed) \
- FN(space_to_batch_float_3) \
- FN(space_to_batch_float_3_relaxed) \
- FN(space_to_batch_quant8_1) \
- FN(space_to_batch_quant8_2) \
- FN(space_to_batch_quant8_3) \
- FN(space_to_batch_relaxed) \
- FN(space_to_depth_float_1) \
- FN(space_to_depth_float_1_relaxed) \
- FN(space_to_depth_float_2) \
- FN(space_to_depth_float_2_relaxed) \
- FN(space_to_depth_float_3) \
- FN(space_to_depth_float_3_relaxed) \
- FN(space_to_depth_quant8_1) \
- FN(space_to_depth_quant8_2) \
- FN(squeeze) \
- FN(squeeze_float_1) \
- FN(squeeze_float_1_relaxed) \
- FN(squeeze_quant8_1) \
- FN(squeeze_relaxed) \
- FN(strided_slice) \
- FN(strided_slice_float_1) \
- FN(strided_slice_float_10) \
- FN(strided_slice_float_10_relaxed) \
- FN(strided_slice_float_11) \
- FN(strided_slice_float_11_relaxed) \
- FN(strided_slice_float_1_relaxed) \
- FN(strided_slice_float_2) \
- FN(strided_slice_float_2_relaxed) \
- FN(strided_slice_float_3) \
- FN(strided_slice_float_3_relaxed) \
- FN(strided_slice_float_4) \
- FN(strided_slice_float_4_relaxed) \
- FN(strided_slice_float_5) \
- FN(strided_slice_float_5_relaxed) \
- FN(strided_slice_float_6) \
- FN(strided_slice_float_6_relaxed) \
- FN(strided_slice_float_7) \
- FN(strided_slice_float_7_relaxed) \
- FN(strided_slice_float_8) \
- FN(strided_slice_float_8_relaxed) \
- FN(strided_slice_float_9) \
- FN(strided_slice_float_9_relaxed) \
- FN(strided_slice_qaunt8_10) \
- FN(strided_slice_qaunt8_11) \
- FN(strided_slice_quant8_1) \
- FN(strided_slice_quant8_2) \
- FN(strided_slice_quant8_3) \
- FN(strided_slice_quant8_4) \
- FN(strided_slice_quant8_5) \
- FN(strided_slice_quant8_6) \
- FN(strided_slice_quant8_7) \
- FN(strided_slice_quant8_8) \
- FN(strided_slice_quant8_9) \
- FN(strided_slice_relaxed) \
- FN(sub) \
- FN(sub_broadcast_float) \
- FN(sub_broadcast_float_relaxed) \
- FN(sub_relaxed) \
- FN(svdf) \
- FN(svdf2) \
- FN(svdf2_relaxed) \
- FN(svdf_relaxed) \
- FN(svdf_state) \
- FN(svdf_state_relaxed) \
- FN(tanh) \
- FN(tanh_relaxed) \
- FN(transpose) \
- FN(transpose_float_1) \
- FN(transpose_float_1_relaxed) \
- FN(transpose_quant8_1) \
- FN(transpose_relaxed)
-
-#define FORWARD_DECLARE_GENERATED_OBJECTS(function) \
- namespace function { \
- extern std::vector<MixedTypedExample> examples; \
- Model createTestModel(); \
- }
-
-FOR_EACH_TEST_MODEL(FORWARD_DECLARE_GENERATED_OBJECTS)
-
-#undef FORWARD_DECLARE_GENERATED_OBJECTS
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
-
-#endif // VTS_HAL_NEURALNETWORKS_V1_2_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 7ec6ff1..c4f1b5e 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -26,9 +26,7 @@
namespace V1_2 {
using V1_0::IPreparedModel;
-using V1_0::Operand;
using V1_0::OperandLifeTime;
-using V1_0::OperandType;
using V1_1::ExecutionPreference;
namespace vts {
@@ -130,16 +128,16 @@
///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
-static const int32_t invalidOperandTypes[] = {
- static_cast<int32_t>(OperandType::FLOAT32) - 1, // lower bound fundamental
- static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental
- static_cast<int32_t>(OperandType::OEM) - 1, // lower bound OEM
- static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM
+static const uint32_t invalidOperandTypes[] = {
+ static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MIN) - 1,
+ static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MAX) + 1,
+ static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MIN) - 1,
+ static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MAX) + 1,
};
static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- for (int32_t invalidOperandType : invalidOperandTypes) {
+ for (uint32_t invalidOperandType : invalidOperandTypes) {
const std::string message = "mutateOperandTypeTest: operand " +
std::to_string(operand) + " set to value " +
std::to_string(invalidOperandType);
@@ -157,10 +155,13 @@
case OperandType::FLOAT32:
case OperandType::INT32:
case OperandType::UINT32:
+ case OperandType::BOOL:
return 1;
+ case OperandType::TENSOR_FLOAT16:
case OperandType::TENSOR_FLOAT32:
case OperandType::TENSOR_INT32:
case OperandType::TENSOR_QUANT8_ASYMM:
+ case OperandType::TENSOR_QUANT16_SYMM:
return 0;
default:
return 0;
@@ -185,11 +186,14 @@
case OperandType::FLOAT32:
case OperandType::INT32:
case OperandType::UINT32:
+ case OperandType::BOOL:
+ case OperandType::TENSOR_FLOAT16:
case OperandType::TENSOR_FLOAT32:
return 1.0f;
case OperandType::TENSOR_INT32:
return -1.0f;
case OperandType::TENSOR_QUANT8_ASYMM:
+ case OperandType::TENSOR_QUANT16_SYMM:
return 0.0f;
default:
return 0.0f;
@@ -214,11 +218,15 @@
case OperandType::FLOAT32:
case OperandType::INT32:
case OperandType::UINT32:
+ case OperandType::BOOL:
+ case OperandType::TENSOR_FLOAT16:
case OperandType::TENSOR_FLOAT32:
case OperandType::TENSOR_INT32:
return {1};
case OperandType::TENSOR_QUANT8_ASYMM:
return {-1, 256};
+ case OperandType::TENSOR_QUANT16_SYMM:
+ return {-32769, -1, 1, 32768};
default:
return {};
}
@@ -253,10 +261,12 @@
case OperandType::FLOAT32:
case OperandType::INT32:
case OperandType::UINT32:
+ case OperandType::BOOL:
newOperand.dimensions = hidl_vec<uint32_t>();
newOperand.scale = 0.0f;
newOperand.zeroPoint = 0;
break;
+ case OperandType::TENSOR_FLOAT16:
case OperandType::TENSOR_FLOAT32:
newOperand.dimensions =
operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
@@ -269,6 +279,7 @@
newOperand.zeroPoint = 0;
break;
case OperandType::TENSOR_QUANT8_ASYMM:
+ case OperandType::TENSOR_QUANT16_SYMM:
newOperand.dimensions =
operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
@@ -281,15 +292,33 @@
*operand = newOperand;
}
-static bool mutateOperationOperandTypeSkip(size_t operand, const Model& model) {
- // LSH_PROJECTION's second argument is allowed to have any type. This is the
- // only operation that currently has a type that can be anything independent
- // from any other type. Changing the operand type to any other type will
- // result in a valid model for LSH_PROJECTION. If this is the case, skip the
- // test.
+static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) {
+ // Do not test OEM types
+ if (type == model.operands[operand].type || type == OperandType::OEM ||
+ type == OperandType::TENSOR_OEM_BYTE) {
+ return true;
+ }
for (const Operation& operation : model.operations) {
- if (operation.type == OperationType::LSH_PROJECTION && operand == operation.inputs[1]) {
- return true;
+ // Skip mutateOperationOperandTypeTest for the following operations.
+ // - LSH_PROJECTION's second argument is allowed to have any type.
+ // - ARGMIN and ARGMAX's first argument can be any of TENSOR_(FLOAT32|INT32|QUANT8_ASYMM).
+ // - CAST's argument can be any of TENSOR_(FLOAT32|INT32|QUANT8_ASYMM).
+ switch (operation.type) {
+ case OperationType::LSH_PROJECTION: {
+ if (operand == operation.inputs[1]) {
+ return true;
+ }
+ } break;
+ case OperationType::CAST:
+ case OperationType::ARGMAX:
+ case OperationType::ARGMIN: {
+ if (type == OperandType::TENSOR_FLOAT32 || type == OperandType::TENSOR_INT32 ||
+ type == OperandType::TENSOR_QUANT8_ASYMM) {
+ return true;
+ }
+ } break;
+ default:
+ break;
}
}
return false;
@@ -297,14 +326,8 @@
static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- if (mutateOperationOperandTypeSkip(operand, model)) {
- continue;
- }
for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
- // Do not test OEM types
- if (invalidOperandType == model.operands[operand].type ||
- invalidOperandType == OperandType::OEM ||
- invalidOperandType == OperandType::TENSOR_OEM_BYTE) {
+ if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) {
continue;
}
const std::string message = "mutateOperationOperandTypeTest: operand " +
@@ -319,16 +342,16 @@
///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
-static const int32_t invalidOperationTypes[] = {
- static_cast<int32_t>(OperationType::ADD) - 1, // lower bound fundamental
- static_cast<int32_t>(OperationType::TRANSPOSE) + 1, // upper bound fundamental
- static_cast<int32_t>(OperationType::OEM_OPERATION) - 1, // lower bound OEM
- static_cast<int32_t>(OperationType::OEM_OPERATION) + 1, // upper bound OEM
+static const uint32_t invalidOperationTypes[] = {
+ static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MIN) - 1,
+ static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MAX) + 1,
+ static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MIN) - 1,
+ static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MAX) + 1,
};
static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- for (int32_t invalidOperationType : invalidOperationTypes) {
+ for (uint32_t invalidOperationType : invalidOperationTypes) {
const std::string message = "mutateOperationTypeTest: operation " +
std::to_string(operation) + " set to value " +
std::to_string(invalidOperationType);
@@ -396,8 +419,26 @@
removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
}
+static bool removeOperandSkip(size_t operand, const Model& model) {
+ for (const Operation& operation : model.operations) {
+ // Skip removeOperandTest for the following operations.
+ // - SPLIT's outputs are not checked during prepareModel.
+ if (operation.type == OperationType::SPLIT) {
+ for (const size_t outOprand : operation.outputs) {
+ if (operand == outOprand) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ if (removeOperandSkip(operand, model)) {
+ continue;
+ }
const std::string message = "removeOperandTest: operand " + std::to_string(operand);
validate(device, message, model,
[operand](Model* model) { removeOperand(model, operand); });
@@ -423,15 +464,76 @@
///////////////////////// REMOVE OPERATION INPUT /////////////////////////
+static bool removeOperationInputSkip(const Operation& op, size_t input) {
+ // Skip removeOperationInputTest for the following operations.
+ // - CONCATENATION has at least 2 inputs, with the last element being INT32.
+ // - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR,
+ // SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional
+ // layout parameter.
+ // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis
+ // parameter.
+ switch (op.type) {
+ case OperationType::CONCATENATION: {
+ if (op.inputs.size() > 2 && input != op.inputs.size() - 1) {
+ return true;
+ }
+ } break;
+ case OperationType::DEPTHWISE_CONV_2D: {
+ if ((op.inputs.size() == 12 && input == 11) || (op.inputs.size() == 9 && input == 8)) {
+ return true;
+ }
+ } break;
+ case OperationType::CONV_2D:
+ case OperationType::AVERAGE_POOL_2D:
+ case OperationType::MAX_POOL_2D:
+ case OperationType::L2_POOL_2D: {
+ if ((op.inputs.size() == 11 && input == 10) || (op.inputs.size() == 8 && input == 7)) {
+ return true;
+ }
+ } break;
+ case OperationType::RESIZE_BILINEAR: {
+ if (op.inputs.size() == 4 && input == 3) {
+ return true;
+ }
+ } break;
+ case OperationType::SPACE_TO_DEPTH:
+ case OperationType::DEPTH_TO_SPACE:
+ case OperationType::BATCH_TO_SPACE_ND: {
+ if (op.inputs.size() == 3 && input == 2) {
+ return true;
+ }
+ } break;
+ case OperationType::SPACE_TO_BATCH_ND: {
+ if (op.inputs.size() == 4 && input == 3) {
+ return true;
+ }
+ } break;
+ case OperationType::L2_NORMALIZATION: {
+ if (op.inputs.size() == 2 && input == 1) {
+ return true;
+ }
+ } break;
+ case OperationType::LOCAL_RESPONSE_NORMALIZATION: {
+ if (op.inputs.size() == 6 && input == 5) {
+ return true;
+ }
+ } break;
+ case OperationType::SOFTMAX: {
+ if (op.inputs.size() == 3 && input == 2) {
+ return true;
+ }
+ } break;
+ default:
+ break;
+ }
+ return false;
+}
+
static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
const Operation& op = model.operations[operation];
- // CONCATENATION has at least 2 inputs, with the last element being
- // INT32. Skip this test if removing one of CONCATENATION's
- // inputs still produces a valid model.
- if (op.type == OperationType::CONCATENATION && op.inputs.size() > 2 &&
- input != op.inputs.size() - 1) {
+ if (removeOperationInputSkip(op, input)) {
continue;
}
const std::string message = "removeOperationInputTest: operation " +
@@ -469,8 +571,23 @@
///////////////////////// ADD OPERATION INPUT /////////////////////////
+static bool addOperationInputSkip(const Operation& op) {
+ // Skip addOperationInputTest for the following operations.
+ // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional INT32 axis
+ // parameter.
+ if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) ||
+ (op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) ||
+ (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) {
+ return true;
+ }
+ return false;
+}
+
static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ if (addOperationInputSkip(model.operations[operation])) {
+ continue;
+ }
const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index f4476fa..b663535 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -38,7 +38,7 @@
using ::android::hidl::memory::V1_0::IMemory;
using test_helper::for_all;
using test_helper::MixedTyped;
-using test_helper::MixedTypedExampleType;
+using test_helper::MixedTypedExample;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -152,15 +152,15 @@
///////////////////////////// ENTRY POINT //////////////////////////////////
-std::vector<Request> createRequests(const std::vector<MixedTypedExampleType>& examples) {
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
const uint32_t INPUT = 0;
const uint32_t OUTPUT = 1;
std::vector<Request> requests;
for (auto& example : examples) {
- const MixedTyped& inputs = example.first;
- const MixedTyped& outputs = example.second;
+ const MixedTyped& inputs = example.operands.first;
+ const MixedTyped& outputs = example.operands.second;
std::vector<RequestArgument> inputs_info, outputs_info;
uint32_t inputSize = 0, outputSize = 0;
diff --git a/neuralnetworks/1.2/vts/functional/ValidationTests.cpp b/neuralnetworks/1.2/vts/functional/ValidationTests.cpp
deleted file mode 100644
index 3bdc5cd..0000000
--- a/neuralnetworks/1.2/vts/functional/ValidationTests.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "neuralnetworks_hidl_hal_test"
-
-#include "Models.h"
-#include "VtsHalNeuralnetworks.h"
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-// forward declarations
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// generate validation tests
-#define VTS_CURRENT_TEST_CASE(TestName) \
- TEST_F(ValidationTest, TestName) { \
- const Model model = TestName::createTestModel(); \
- const std::vector<Request> requests = createRequests(TestName::examples); \
- validateModel(model); \
- validateRequests(model, requests); \
- }
-
-FOR_EACH_TEST_MODEL(VTS_CURRENT_TEST_CASE)
-
-#undef VTS_CURRENT_TEST_CASE
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/power/stats/1.0/Android.bp b/power/stats/1.0/Android.bp
new file mode 100644
index 0000000..9a956e4
--- /dev/null
+++ b/power/stats/1.0/Android.bp
@@ -0,0 +1,29 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.power.stats@1.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IPowerStats.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "EnergyData",
+ "PowerEntityInfo",
+ "PowerEntityStateInfo",
+ "PowerEntityStateResidencyData",
+ "PowerEntityStateResidencyResult",
+ "PowerEntityStateSpace",
+ "PowerEntityType",
+ "RailInfo",
+ "Status",
+ ],
+ gen_java: false,
+}
+
diff --git a/power/stats/1.0/IPowerStats.hal b/power/stats/1.0/IPowerStats.hal
new file mode 100644
index 0000000..75c6a72
--- /dev/null
+++ b/power/stats/1.0/IPowerStats.hal
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 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.
+ */
+package android.hardware.power.stats@1.0;
+
+interface IPowerStats {
+
+ /**
+ * Rail information:
+ * Reports information related to the rails being monitored.
+ *
+ * @return rails Information about monitored rails.
+ * @return status SUCCESS on success or NOT_SUPPORTED if
+ * feature is not enabled or FILESYSTEM_ERROR on filesystem nodes
+ * access error.
+ */
+ getRailInfo()
+ generates(vec<RailInfo> rails, Status status);
+
+ /**
+ * Rail level energy measurements for low frequency clients:
+ * Reports accumulated energy since boot on each rail.
+ *
+ * @param railIndices Indices of rails for which data is required.
+ * To get data for all rails pass an empty vector. Rail name to
+ * index mapping can be queried from getRailInfo() API.
+ * @return data Energy values since boot for all requested rails.
+ * @return status SUCCESS on success or NOT_SUPPORTED if
+ * feature is not enabled or FILESYSTEM_ERROR on filesystem nodes
+ * access error.
+ */
+ getEnergyData(vec<uint32_t> railIndices)
+ generates(vec<EnergyData> data, Status status);
+
+ /**
+ * Stream rail level power measurements for high frequency clients:
+ * Streams accumulated energy since boot on each rail. This API is
+ * asynchronous.
+ *
+ * @param timeMs Time(in ms) for which energyData should be streamed
+ * @param samplingRate Frequency(in Hz) at which samples should be
+ * captured. If the requested sampling rate is not supported then
+ * SUCCESS is returned and numSamples are reported back according
+ * to the supported sampling rate.
+ * @return mqDesc Blocking Synchronous Fast Message Queue descriptor - One
+ * writer(power.stats HAL) and one reader are supported. Data is
+ * present in the following format in the queue:
+ * +-----------------------+ <--
+ * | EnergyData for rail 1 | |
+ * +-----------------------+ |
+ * | EnergyData for rail 2 | |
+ * +-----------------------+ |
+ * | . | |-- 1st Sample
+ * | . | |
+ * | . | |
+ * +-----------------------+ |
+ * | EnergyData for rail n | |
+ * +-----------------------+ <--
+ * | . |
+ * | . |
+ * | . |
+ * +-----------------------+ <--
+ * | EnergyData for rail 1 | |
+ * +-----------------------+ |
+ * | EnergyData for rail 2 | |
+ * +-----------------------+ |
+ * | . | |-- kth Sample
+ * | . | |
+ * | . | |
+ * +-----------------------+ |
+ * | EnergyData for rail n | |
+ * +-----------------------+ <--
+ *
+ * where,
+ * n = railsPerSample
+ * k = numSamples
+ *
+ * @return numSamples Number of samples which will be generated in timeMs.
+ * @return railsPerSample Number of rails measured per sample.
+ * @return status SUCCESS on success or FILESYSTEM_ERROR on filesystem
+ * nodes access or NOT_SUPPORTED if feature is not enabled or
+ * INSUFFICIENT_RESOURCES if there are not enough resources.
+ */
+ streamEnergyData(uint32_t timeMs, uint32_t samplingRate)
+ generates(fmq_sync<EnergyData> mqDesc, uint32_t numSamples,
+ uint32_t railsPerSample, Status status);
+
+ /**
+ * PowerEntity information:
+ * Reports information related to all supported PowerEntity(s) for which
+ * data is available. A PowerEntity is defined as a platform subsystem,
+ * peripheral, or power domain that impacts the total device power
+ * consumption.
+ *
+ * @return powerEntityInfos List of information on each PowerEntity
+ * @return status SUCCESS on success or NOT_SUPPORTED if
+ * feature is not enabled or FILESYSTEM_ERROR on filesystem nodes
+ * access error.
+ */
+ getPowerEntityInfo()
+ generates(vec<PowerEntityInfo> powerEntityInfos, Status status);
+
+ /**
+ * PowerEntity state information:
+ * Reports the set of power states for which the specified
+ * PowerEntity(s) provide residency data.
+ *
+ * @param powerEntityIds collection of IDs of PowerEntity(s) for which
+ * state information is requested. PowerEntity name to ID mapping may
+ * be queried from getPowerEntityInfo(). To get state space
+ * information for all PowerEntity(s) pass an empty vector.
+ *
+ * @return powerEntityStateSpaces PowerEntity state space information for
+ * each specified PowerEntity.
+ * @return status SUCCESS if powerEntityStateInfos contains state space
+ * information for at least one PowerEntity, NOT_SUPPORTED if feature
+ * is not enabled, INVALID_INPUT if no requested PowerEntity(s)
+ * provide state space information, FILESYSTEM_ERROR if no state space
+ * information is returned due to filesystem errors.
+ */
+ getPowerEntityStateInfo(vec<uint32_t> powerEntityIds)
+ generates(vec<PowerEntityStateSpace> powerEntityStateSpaces,
+ Status status);
+
+ /**
+ * PowerEntity residencies for low frequency clients:
+ * Reports accumulated residency data for each specified PowerEntity.
+ * Each PowerEntity may reside in one of multiple states. It may also
+ * transition to another state. Residency data is an accumulation of time
+ * that a specified PowerEntity resided in each of its possible states,
+ * the number of times that each state was entered, and a timestamp
+ * corresponding to the last time that state was entered. Data is
+ * accumulated starting from the last time the PowerEntity was reset.
+ *
+ * @param powerEntityId collection of IDs of PowerEntity(s) for which
+ * residency data is requested. PowerEntity name to ID mapping may
+ * be queried from getPowerEntityInfo(). To get state residency
+ * data for all PowerEntity(s) pass an empty vector.
+ * @return stateResidencyResults state residency data for the
+ * specified powerEntity(s)
+ * @return status SUCCESS if stateResidencyResults contains residency
+ * data for at least one PowerEntity, NOT_SUPPORTED if
+ * feature is not enabled, INVALID_INPUT if no requested
+ * PowerEntity(s) provide state residency data, FILESYSTEM_ERROR
+ * if no data is returned due to filesystem errors.
+ */
+ getPowerEntityStateResidencyData(vec<uint32_t> powerEntityIds)
+ generates(vec<PowerEntityStateResidencyResult> stateResidencyResults,
+ Status status);
+};
diff --git a/power/stats/1.0/default/Android.bp b/power/stats/1.0/default/Android.bp
new file mode 100644
index 0000000..04270c1
--- /dev/null
+++ b/power/stats/1.0/default/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 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
+
+cc_library_shared {
+ name: "android.hardware.power.stats@1.0-service",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.power.stats@1.0-service.rc"],
+ srcs: ["service.cpp", "PowerStats.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.power.stats@1.0",
+ ],
+ vendor: true,
+}
diff --git a/power/stats/1.0/default/PowerStats.cpp b/power/stats/1.0/default/PowerStats.cpp
new file mode 100644
index 0000000..810c575
--- /dev/null
+++ b/power/stats/1.0/default/PowerStats.cpp
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "PowerStats.h"
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <exception>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+namespace V1_0 {
+namespace implementation {
+
+#define MAX_FILE_PATH_LEN 128
+#define MAX_DEVICE_NAME_LEN 64
+#define MAX_QUEUE_SIZE 8192
+
+constexpr char kIioDirRoot[] = "/sys/bus/iio/devices/";
+constexpr char kDeviceName[] = "pm_device_name";
+constexpr char kDeviceType[] = "iio:device";
+constexpr uint32_t MAX_SAMPLING_RATE = 10;
+constexpr uint64_t WRITE_TIMEOUT_NS = 1000000000;
+
+void PowerStats::findIioPowerMonitorNodes() {
+ struct dirent* ent;
+ int fd;
+ char devName[MAX_DEVICE_NAME_LEN];
+ char filePath[MAX_FILE_PATH_LEN];
+ DIR* iioDir = opendir(kIioDirRoot);
+ if (!iioDir) {
+ ALOGE("Error opening directory: %s", kIioDirRoot);
+ return;
+ }
+ while (ent = readdir(iioDir), ent) {
+ if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0 &&
+ strlen(ent->d_name) > strlen(kDeviceType) &&
+ strncmp(ent->d_name, kDeviceType, strlen(kDeviceType)) == 0) {
+ snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", ent->d_name, "name");
+ fd = openat(dirfd(iioDir), filePath, O_RDONLY);
+ if (fd < 0) {
+ ALOGW("Failed to open directory: %s", filePath);
+ continue;
+ }
+ if (read(fd, devName, MAX_DEVICE_NAME_LEN) < 0) {
+ ALOGW("Failed to read device name from file: %s(%d)", filePath, fd);
+ close(fd);
+ continue;
+ }
+
+ if (strncmp(devName, kDeviceName, strlen(kDeviceName)) == 0) {
+ snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", kIioDirRoot, ent->d_name);
+ mPm.devicePaths.push_back(filePath);
+ }
+ close(fd);
+ }
+ }
+ closedir(iioDir);
+ return;
+}
+
+size_t PowerStats::parsePowerRails() {
+ std::string data;
+ std::string railFileName;
+ std::string spsFileName;
+ uint32_t index = 0;
+ uint32_t samplingRate;
+ for (const auto& path : mPm.devicePaths) {
+ railFileName = path + "/enabled_rails";
+ spsFileName = path + "/sampling_rate";
+ if (!android::base::ReadFileToString(spsFileName, &data)) {
+ ALOGW("Error reading file: %s", spsFileName.c_str());
+ continue;
+ }
+ samplingRate = strtoul(data.c_str(), NULL, 10);
+ if (!samplingRate || samplingRate == ULONG_MAX) {
+ ALOGE("Error parsing: %s", spsFileName.c_str());
+ break;
+ }
+ if (!android::base::ReadFileToString(railFileName, &data)) {
+ ALOGW("Error reading file: %s", railFileName.c_str());
+ continue;
+ }
+ std::istringstream railNames(data);
+ std::string line;
+ while (std::getline(railNames, line)) {
+ std::vector<std::string> words = android::base::Split(line, ":");
+ if (words.size() == 2) {
+ mPm.railsInfo.emplace(words[0], RailData{.devicePath = path,
+ .index = index,
+ .subsysName = words[1],
+ .samplingRate = samplingRate});
+ index++;
+ } else {
+ ALOGW("Unexpected format in file: %s", railFileName.c_str());
+ }
+ }
+ }
+ return index;
+}
+
+int PowerStats::parseIioEnergyNode(std::string devName) {
+ int ret = 0;
+ std::string data;
+ std::string fileName = devName + "/energy_value";
+ if (!android::base::ReadFileToString(fileName, &data)) {
+ ALOGE("Error reading file: %s", fileName.c_str());
+ return -1;
+ }
+
+ std::istringstream energyData(data);
+ std::string line;
+ uint64_t timestamp = 0;
+ bool timestampRead = false;
+ while (std::getline(energyData, line)) {
+ std::vector<std::string> words = android::base::Split(line, ",");
+ if (timestampRead == false) {
+ if (words.size() == 1) {
+ timestamp = strtoull(words[0].c_str(), NULL, 10);
+ if (timestamp == 0 || timestamp == ULLONG_MAX) {
+ ALOGW("Potentially wrong timestamp: %" PRIu64, timestamp);
+ }
+ timestampRead = true;
+ }
+ } else if (words.size() == 2) {
+ std::string railName = words[0];
+ if (mPm.railsInfo.count(railName) != 0) {
+ size_t index = mPm.railsInfo[railName].index;
+ mPm.reading[index].index = index;
+ mPm.reading[index].timestamp = timestamp;
+ mPm.reading[index].energy = strtoull(words[1].c_str(), NULL, 10);
+ if (mPm.reading[index].energy == ULLONG_MAX) {
+ ALOGW("Potentially wrong energy value: %" PRIu64, mPm.reading[index].energy);
+ }
+ }
+ } else {
+ ALOGW("Unexpected format in file: %s", fileName.c_str());
+ ret = -1;
+ break;
+ }
+ }
+ return ret;
+}
+
+Status PowerStats::parseIioEnergyNodes() {
+ Status ret = Status::SUCCESS;
+ if (mPm.hwEnabled == false) {
+ return Status::NOT_SUPPORTED;
+ }
+
+ for (const auto& devicePath : mPm.devicePaths) {
+ if (parseIioEnergyNode(devicePath) < 0) {
+ ALOGE("Error in parsing power stats");
+ ret = Status::FILESYSTEM_ERROR;
+ break;
+ }
+ }
+ return ret;
+}
+
+PowerStats::PowerStats() {
+ findIioPowerMonitorNodes();
+ size_t numRails = parsePowerRails();
+ if (mPm.devicePaths.empty() || numRails == 0) {
+ mPm.hwEnabled = false;
+ } else {
+ mPm.hwEnabled = true;
+ mPm.reading.resize(numRails);
+ }
+}
+
+Return<void> PowerStats::getRailInfo(getRailInfo_cb _hidl_cb) {
+ hidl_vec<RailInfo> rInfo;
+ Status ret = Status::SUCCESS;
+ size_t index;
+ std::lock_guard<std::mutex> _lock(mPm.mLock);
+ if (mPm.hwEnabled == false) {
+ _hidl_cb(rInfo, Status::NOT_SUPPORTED);
+ return Void();
+ }
+ rInfo.resize(mPm.railsInfo.size());
+ for (const auto& railData : mPm.railsInfo) {
+ index = railData.second.index;
+ rInfo[index].railName = railData.first;
+ rInfo[index].subsysName = railData.second.subsysName;
+ rInfo[index].index = index;
+ rInfo[index].samplingRate = railData.second.samplingRate;
+ }
+ _hidl_cb(rInfo, ret);
+ return Void();
+}
+
+Return<void> PowerStats::getEnergyData(const hidl_vec<uint32_t>& railIndices,
+ getEnergyData_cb _hidl_cb) {
+ hidl_vec<EnergyData> eVal;
+ std::lock_guard<std::mutex> _lock(mPm.mLock);
+ Status ret = parseIioEnergyNodes();
+
+ if (ret != Status::SUCCESS) {
+ ALOGE("Failed to getEnergyData");
+ _hidl_cb(eVal, ret);
+ return Void();
+ }
+
+ if (railIndices.size() == 0) {
+ eVal.resize(mPm.railsInfo.size());
+ memcpy(&eVal[0], &mPm.reading[0], mPm.reading.size() * sizeof(EnergyData));
+ } else {
+ eVal.resize(railIndices.size());
+ int i = 0;
+ for (const auto& railIndex : railIndices) {
+ if (railIndex >= mPm.reading.size()) {
+ ret = Status::INVALID_INPUT;
+ eVal.resize(0);
+ break;
+ }
+ memcpy(&eVal[i], &mPm.reading[railIndex], sizeof(EnergyData));
+ i++;
+ }
+ }
+ _hidl_cb(eVal, ret);
+ return Void();
+}
+
+Return<void> PowerStats::streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
+ streamEnergyData_cb _hidl_cb) {
+ std::lock_guard<std::mutex> _lock(mPm.mLock);
+ if (mPm.fmqSynchronized != nullptr) {
+ _hidl_cb(MessageQueueSync::Descriptor(), 0, 0, Status::INSUFFICIENT_RESOURCES);
+ return Void();
+ }
+ uint32_t sps = std::min(samplingRate, MAX_SAMPLING_RATE);
+ uint32_t numSamples = timeMs * sps / 1000;
+ mPm.fmqSynchronized.reset(new (std::nothrow) MessageQueueSync(MAX_QUEUE_SIZE, true));
+ if (mPm.fmqSynchronized == nullptr || mPm.fmqSynchronized->isValid() == false) {
+ mPm.fmqSynchronized = nullptr;
+ _hidl_cb(MessageQueueSync::Descriptor(), 0, 0, Status::INSUFFICIENT_RESOURCES);
+ return Void();
+ }
+ std::thread pollThread = std::thread([this, sps, numSamples]() {
+ uint64_t sleepTimeUs = 1000000 / sps;
+ uint32_t currSamples = 0;
+ while (currSamples < numSamples) {
+ mPm.mLock.lock();
+ if (parseIioEnergyNodes() == Status::SUCCESS) {
+ mPm.fmqSynchronized->writeBlocking(&mPm.reading[0], mPm.reading.size(),
+ WRITE_TIMEOUT_NS);
+ mPm.mLock.unlock();
+ currSamples++;
+ if (usleep(sleepTimeUs) < 0) {
+ ALOGW("Sleep interrupted");
+ break;
+ }
+ } else {
+ mPm.mLock.unlock();
+ break;
+ }
+ }
+ mPm.mLock.lock();
+ mPm.fmqSynchronized = nullptr;
+ mPm.mLock.unlock();
+ return;
+ });
+ pollThread.detach();
+ _hidl_cb(*(mPm.fmqSynchronized)->getDesc(), numSamples, mPm.reading.size(), Status::SUCCESS);
+ return Void();
+}
+
+Return<void> PowerStats::getPowerEntityInfo(getPowerEntityInfo_cb _hidl_cb) {
+ hidl_vec<PowerEntityInfo> eInfo;
+ _hidl_cb(eInfo, Status::NOT_SUPPORTED);
+ return Void();
+}
+
+Return<void> PowerStats::getPowerEntityStateInfo(const hidl_vec<uint32_t>& powerEntityIds,
+ getPowerEntityStateInfo_cb _hidl_cb) {
+ (void)powerEntityIds;
+ hidl_vec<PowerEntityStateSpace> powerEntityStateSpaces;
+ _hidl_cb(powerEntityStateSpaces, Status::NOT_SUPPORTED);
+ return Void();
+}
+
+Return<void> PowerStats::getPowerEntityStateResidencyData(
+ const hidl_vec<uint32_t>& powerEntityIds, getPowerEntityStateResidencyData_cb _hidl_cb) {
+ (void)powerEntityIds;
+ hidl_vec<PowerEntityStateResidencyResult> results;
+ _hidl_cb(results, Status::NOT_SUPPORTED);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
diff --git a/power/stats/1.0/default/PowerStats.h b/power/stats/1.0/default/PowerStats.h
new file mode 100644
index 0000000..fb2c6a8
--- /dev/null
+++ b/power/stats/1.0/default/PowerStats.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_HARDWARE_POWERSTATS_V1_0_POWERSTATS_H
+#define ANDROID_HARDWARE_POWERSTATS_V1_0_POWERSTATS_H
+
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace stats {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::power::stats::V1_0::EnergyData;
+using ::android::hardware::power::stats::V1_0::PowerEntityInfo;
+using ::android::hardware::power::stats::V1_0::PowerEntityStateInfo;
+using ::android::hardware::power::stats::V1_0::PowerEntityStateResidencyData;
+using ::android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+using ::android::hardware::power::stats::V1_0::PowerEntityStateSpace;
+using ::android::hardware::power::stats::V1_0::PowerEntityType;
+using ::android::hardware::power::stats::V1_0::RailInfo;
+using ::android::hardware::power::stats::V1_0::Status;
+
+typedef MessageQueue<EnergyData, kSynchronizedReadWrite> MessageQueueSync;
+struct RailData {
+ std::string devicePath;
+ uint32_t index;
+ std::string subsysName;
+ uint32_t samplingRate;
+};
+
+struct OnDeviceMmt {
+ std::mutex mLock;
+ bool hwEnabled;
+ std::vector<std::string> devicePaths;
+ std::map<std::string, RailData> railsInfo;
+ std::vector<EnergyData> reading;
+ std::unique_ptr<MessageQueueSync> fmqSynchronized;
+};
+
+struct PowerStats : public IPowerStats {
+ PowerStats();
+ // Methods from ::android::hardware::power::stats::V1_0::IPowerStats follow.
+ Return<void> getRailInfo(getRailInfo_cb _hidl_cb) override;
+ Return<void> getEnergyData(const hidl_vec<uint32_t>& railIndices,
+ getEnergyData_cb _hidl_cb) override;
+ Return<void> streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
+ streamEnergyData_cb _hidl_cb) override;
+ Return<void> getPowerEntityInfo(getPowerEntityInfo_cb _hidl_cb) override;
+ Return<void> getPowerEntityStateInfo(const hidl_vec<uint32_t>& powerEntityIds,
+ getPowerEntityStateInfo_cb _hidl_cb) override;
+ Return<void> getPowerEntityStateResidencyData(
+ const hidl_vec<uint32_t>& powerEntityIds,
+ getPowerEntityStateResidencyData_cb _hidl_cb) override;
+
+ private:
+ OnDeviceMmt mPm;
+ void findIioPowerMonitorNodes();
+ size_t parsePowerRails();
+ int parseIioEnergyNode(std::string devName);
+ Status parseIioEnergyNodes();
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace stats
+} // namespace power
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_POWERSTATS_V1_0_POWERSTATS_H
diff --git a/power/stats/1.0/default/android.hardware.power.stats@1.0-service.rc b/power/stats/1.0/default/android.hardware.power.stats@1.0-service.rc
new file mode 100644
index 0000000..d7e546b
--- /dev/null
+++ b/power/stats/1.0/default/android.hardware.power.stats@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.power.stats-hal-1-0 /vendor/bin/hw/android.hardware.power.stats@1.0-service
+ class hal
+ user system
+ group system
diff --git a/power/stats/1.0/default/service.cpp b/power/stats/1.0/default/service.cpp
new file mode 100644
index 0000000..80649f5
--- /dev/null
+++ b/power/stats/1.0/default/service.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "android.hardware.power.stats@1.0-service"
+
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "PowerStats.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::stats::V1_0::IPowerStats;
+using android::hardware::power::stats::V1_0::implementation::PowerStats;
+
+int main(int /* argc */, char** /* argv */) {
+ ALOGI("power.stats service 1.0 is starting.");
+
+ android::sp<IPowerStats> service = new PowerStats();
+ if (service == nullptr) {
+ ALOGE("Can not create an instance of power.stats HAL Iface, exiting.");
+ return 1;
+ }
+
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ status_t status = service->registerAsService();
+ if (status != OK) {
+ ALOGE("Could not register service for power.stats HAL Iface (%d), exiting.", status);
+ return 1;
+ }
+
+ ALOGI("power.stats service is ready");
+ joinRpcThreadpool();
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("power.stats service is shutting down");
+ return 1;
+}
diff --git a/power/stats/1.0/types.hal b/power/stats/1.0/types.hal
new file mode 100644
index 0000000..986a6bb
--- /dev/null
+++ b/power/stats/1.0/types.hal
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 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.
+ */
+package android.hardware.power.stats@1.0;
+
+enum Status : uint32_t {
+ SUCCESS = 0,
+ NOT_SUPPORTED = 1,
+ INVALID_INPUT = 2,
+ FILESYSTEM_ERROR = 3,
+ INSUFFICIENT_RESOURCES = 4,
+};
+
+struct RailInfo {
+ /** Index corresponding to the rail */
+ uint32_t index;
+ /** Name of the rail */
+ string railName;
+ /** Name of the subsystem to which this rail belongs */
+ string subsysName;
+ /** Hardware sampling rate */
+ uint32_t samplingRate;
+};
+
+struct EnergyData {
+ /**
+ * Index corresponding to the rail. This index matches
+ * the index returned in RailInfo
+ */
+ uint32_t index;
+ /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */
+ uint64_t timestamp;
+ /** Accumulated energy since device boot in microwatt-seconds (uWs) */
+ uint64_t energy;
+};
+
+enum PowerEntityType : uint32_t {
+ /**
+ * A subsystem is a self-contained compute unit. Some examples include
+ * application processor, DSP, GPU.
+ */
+ SUBSYSTEM = 0,
+ /**
+ * A peripheral is an auxiliary device that connects to and works with a
+ * compute unit. Some examples include simple sensors, camera, display.
+ */
+ PERIPHERAL = 1,
+ /**
+ * A power domain is a single subsystem or a collection of subsystems
+ * that is controlled by a single voltage rail.
+ */
+ POWER_DOMAIN = 2,
+};
+
+/**
+ * PowerEntityInfo contains information, such as the ID, name, and type of a
+ * given PowerEntity.
+ */
+struct PowerEntityInfo {
+ /** ID corresponding to the PowerEntity */
+ uint32_t powerEntityId;
+ /**
+ * Name of the PowerEntity. This is unique and opaque to the
+ * Android framework
+ */
+ string powerEntityName;
+ /** Type of the PowerEntity */
+ PowerEntityType type;
+};
+
+struct PowerEntityStateInfo {
+ /** ID corresponding to the state */
+ uint32_t powerEntityStateId;
+ /** Name of the state */
+ string powerEntityStateName;
+};
+
+/**
+ * PowerEntityStateSpace contains the state space information of a given
+ * PowerEntity. The state space, is the set of possible states that a given
+ * PowerEntity provides residency data for.
+ */
+struct PowerEntityStateSpace {
+ /** ID of the corresponding PowerEntity */
+ uint32_t powerEntityId;
+
+ /** List of states that the PowerEntity may reside in */
+ vec<PowerEntityStateInfo> states;
+};
+
+/** Contains residency data for a single state */
+struct PowerEntityStateResidencyData {
+ /** ID of the corresponding PowerEntityStateInfo */
+ uint32_t powerEntityStateId;
+ /**
+ * Total time in milliseconds that the corresponding PowerEntity resided
+ * in this state since the PowerEntity was reset
+ */
+ uint64_t totalTimeInStateMs;
+ /**
+ * Total number of times that the state was entered since the corresponding
+ * PowerEntity was reset
+ */
+ uint64_t totalStateEntryCount;
+ /**
+ * Last time this state was entered. Time in milliseconds since the
+ * corresponding PowerEntity was reset
+ */
+ uint64_t lastEntryTimestampMs;
+};
+
+struct PowerEntityStateResidencyResult {
+ /** ID of the corresponding PowerEntity */
+ uint32_t powerEntityId;
+ /** Residency data for each state the PowerEntity's state space */
+ vec<PowerEntityStateResidencyData> stateResidencyData;
+};
diff --git a/prebuilt_hashes/26.txt b/prebuilt_hashes/26.txt
new file mode 100644
index 0000000..f2feb4c
--- /dev/null
+++ b/prebuilt_hashes/26.txt
@@ -0,0 +1,186 @@
+# Do not change this file except to add new interfaces. Changing
+# pre-existing interfaces will fail VTS and break framework-only OTAs
+
+# HALs released in Android O
+
+f219c3b5b8c6cb1d659d4c7328f67246abfe1a8613f469826fd3b9ad090417a2 android.hardware.audio@2.0::IDevice
+4d579cae1cd87a783fd49233e10ce720ba183cfd1d5ccd80149e69de5c1c7362 android.hardware.audio@2.0::IDevicesFactory
+203e23f18011390b8cd10c303e0c16c4eebc8fa187e80e40d6be4624c2b0848a android.hardware.audio@2.0::IPrimaryDevice
+aaf93123deec336eb247ad8099849469a541ca0cf7c28c5f5336cebe1ee86748 android.hardware.audio@2.0::IStream
+0468c5723b0d44c5b451bdfa06153000c6f352fd3336e0ad2697127b04b766df android.hardware.audio@2.0::IStreamIn
+7296f7064fd3ab24082b43a1da34cc876268065310b785499fba5178d063680a android.hardware.audio@2.0::IStreamOut
+19d241d71c3e1140afba8140dcb57448446025a5fc03739788c4c25e9a98b6c2 android.hardware.audio@2.0::IStreamOutCallback
+c84da9f586087227daa3b96d42b4575326bccfd5bc8a2a5acf86d774f8ea2648 android.hardware.audio@2.0::types
+1305786c06e22b9b24ebde136054cc827b63c86d8bf4a136d6f7f54752b8566b android.hardware.audio.common@2.0::types
+fa8fbae3d1da3c264e4f3110728076abc09b4e65f12af6ae136367328de988ab android.hardware.audio.effect@2.0::IAcousticEchoCancelerEffect
+ca4752545d54547ff069eae161af7550cb5f5a7e8b60316ddd132a30906a68e7 android.hardware.audio.effect@2.0::IAutomaticGainControlEffect
+d2b8af988dc66f514d886bcee44b440d8034bc2a762f7161717ef3c956073067 android.hardware.audio.effect@2.0::IBassBoostEffect
+611bc09c75e796f3512b1ca6be508b0a9ba996759b8a2c60507784ff58076229 android.hardware.audio.effect@2.0::IDownmixEffect
+36a57369dfdc75180e8b64ae80b1970db8f6d9085dbff6ca931715038cc056e1 android.hardware.audio.effect@2.0::IEffect
+d2aa2df6d189c580f5be8460fa0ff4134d9c05a383f3204659baee426a6f0edf android.hardware.audio.effect@2.0::IEffectBufferProviderCallback
+217f9161983a48d3bf3faeb158f868aa8bf0ce25889e4ee3d2bab1a2e8d33e77 android.hardware.audio.effect@2.0::IEffectsFactory
+c2b38bc07991e880c83ca8cb88181411eeef708b8b936aedd2f2e0acade7df69 android.hardware.audio.effect@2.0::IEnvironmentalReverbEffect
+2ff9f9704be5f167745b4de790e9dafc3cc4719e2f6e2e5497085e679853cfe7 android.hardware.audio.effect@2.0::IEqualizerEffect
+c31447fb02dbc8b56c359941dad22f416511860173c5c5fd278d1bf2312b13de android.hardware.audio.effect@2.0::ILoudnessEnhancerEffect
+804831ca258802eb3eb65a0a7b5d5e3d37d4a15ba8c2836b4276eda98b47e1d0 android.hardware.audio.effect@2.0::INoiseSuppressionEffect
+778fd5b9837f481d8e47425b3e2a3bd0c6362a0b6870291518e2d863530fdb61 android.hardware.audio.effect@2.0::IPresetReverbEffect
+c93cb25a1a92d07aa80a617c01e8d22fc97bf8cefd3962b6a5be386ad4704d89 android.hardware.audio.effect@2.0::IVirtualizerEffect
+918f331780c9c7b04f2151a2e563aab088198ede8e6f865302ebaa13905bd9ce android.hardware.audio.effect@2.0::IVisualizerEffect
+4caad099f8fc00262b6c03ba41271808b37cea90ac98b534299bbf4ee823af02 android.hardware.audio.effect@2.0::types
+# android.hardware.automotive.* are unfrozen
+1fbdc1f852f8bd2e4a6c5cb30ac2b78668c98dce118a61762d4034ae859f43d8 android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint
+aabb5c3c585592d71ee57b77298c14993d77914ddeaa64b2c5109a602b02ea47 android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprintClientCallback
+1ec60d4efddae9a7b2469278a576967b4751e88de5b8d7e9df6eff6bc0da7bc9 android.hardware.biometrics.fingerprint@2.1::types
+347ce746815607567f5f3b53e4800998ca5ab9355141f0880fc0cf0c1fc5c355 android.hardware.bluetooth@1.0::IBluetoothHci
+835f41be2281bfb22f3e33c6fa870bde7bc21e37e5cfbaf9a36fff170632f754 android.hardware.bluetooth@1.0::IBluetoothHciCallbacks
+a8dfd0dbe463a3cdbcf1d985b38a28b3d93ba2ae5a1d1db4aaef4c38a5781b91 android.hardware.bluetooth@1.0::types
+7192d756aeba00aba32f4504981df8172ffca83e210c4838dabf295e53e93590 android.hardware.boot@1.0::IBootControl
+cebaa803b8e33807a0d69f46652b650ccb549e8f9b19d6becbbf26690e828b49 android.hardware.boot@1.0::types
+a98d49f23712a7cc327d1e0602d05f6f3ad32cfb5c74711d009c726611ee1c93 android.hardware.broadcastradio@1.0::IBroadcastRadio
+ed82579c0c165feaa12d0e33c06b3342ab41ec0a439247f202775e8369e46ef6 android.hardware.broadcastradio@1.0::IBroadcastRadioFactory
+da6ab32ee2793d2c86d3b603075d5383852b89d7eaa201861aa0473d418f3c7f android.hardware.broadcastradio@1.0::ITuner
+04d3ca022e25c308d9efd2e7eb77b3a7a206907cdc1b9ea9326340b377868172 android.hardware.broadcastradio@1.0::ITunerCallback
+bd42c8d7838cfed1998b49c39745dec116d2d6edc2c11a4c0399b8f3a1d1655a android.hardware.broadcastradio@1.0::types
+81164323115d6588e259e8319fddf7487adfa1f49ce60f7e80ba74e0783392a4 android.hardware.camera.common@1.0::types
+c1705e9d62438a1d955269965af915ae28e692bd480a3b1ce67056fef992d62f android.hardware.camera.device@1.0::ICameraDevice
+78e9b44cf8660bdc1e98dca07451804153824efcd28db208a62f5ad728f44076 android.hardware.camera.device@1.0::ICameraDeviceCallback
+28f0386ba86ddf41e53a8117b48a0328d7a4d2574213e89f4a1062398a244566 android.hardware.camera.device@1.0::ICameraDevicePreviewCallback
+4db48439ce9dde97f1cfb3d7408f6c737f621ac0f7494aeea35ed599bc2352a3 android.hardware.camera.device@1.0::types
+b32f9aeaf1c442195eb06ffc7600968c919d005b2718874f09c57287fae55918 android.hardware.camera.device@3.2::ICameraDevice
+63bfc3da0f2d2301f7a0508c7c2b9ffc521d4d545ee03718da70e9d6273b3b21 android.hardware.camera.device@3.2::ICameraDeviceCallback
+0fa3e1e64819283b8737fc4e5ab759f0cb4ac1a996e8a51cc4aa8025a457208e android.hardware.camera.device@3.2::ICameraDeviceSession
+030be3d2b159cbde7920485807140f6b6064ef4a5de4a40a6c4bc8d2c72f7cd3 android.hardware.camera.device@3.2::types
+5ba7947cee515d7a2359bfcbfb9678c1c3a768c288471919ac095b96ae6f3d40 android.hardware.camera.metadata@3.2::types
+f7e299d85033ac52d1095a35784fcfeaff43603f58c751e4153c85bbade3b330 android.hardware.camera.provider@2.4::ICameraProvider
+a501ca1aecd09f1b9fd70a9af84205430dbd49a808e8fa395d363b9902e6f58c android.hardware.camera.provider@2.4::ICameraProviderCallback
+7f5fe8f4f8a24037153c504d8b4d3313c2ce33d81c8c69fe5194ddd2d4080e72 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
+87beacc481897cf02fb1628d75e68133de6d74d4cffe582cda2f5e16bdd74516 android.hardware.configstore@1.0::types
+a5ae0fe8667f0b1af09b13e72d29600f4eb3853b257079c45a99b6f4a3360649 android.hardware.contexthub@1.0::IContexthub
+2ab3054c2d9302d8417ee7495353a2887fe338f913276f2eb41e80f11395ec2e android.hardware.contexthub@1.0::IContexthubCallback
+c3b2b37d561d31ea094411f251bf73bea334f4fe849a4390aef5e20bca6cadba android.hardware.contexthub@1.0::types
+df174c1871c864b4c79ca9f64aae7936d24a272eca3191a30458ca2b706dec79 android.hardware.drm@1.0::ICryptoFactory
+83639e90caeb996b0274e420de3cd556779de1ca48464b68eee799bef32b34cd android.hardware.drm@1.0::ICryptoPlugin
+1440cffdfaeb12830ac10ee6ffdb0f1083e701057b806df11fb4787b4c91e718 android.hardware.drm@1.0::IDrmFactory
+78ba33b108f620e6a0eec01ef654547e69a85754578ea4c9ef03ec205f16121c android.hardware.drm@1.0::IDrmPlugin
+701d9e51952172364e4ea70db9c397f08c3b4577ba33051f050a6cdd532de1b4 android.hardware.drm@1.0::IDrmPluginListener
+4238d62ad90df63aa338c6f1b6264c09c5a3706945d5c49d1189c0be1dc9e942 android.hardware.drm@1.0::types
+f07b1ee3ba11a2fc9f200421b2e1afb7c1854ee987000e45c987fb9507795055 android.hardware.dumpstate@1.0::IDumpstateDevice
+c9d318df7922bde3b265927b521ff5a965002826fc0cabfcaef52a56760f2d34 android.hardware.gatekeeper@1.0::IGatekeeper
+da13bd69282fb275767abb18704c57ff8038e6c139ad17157dc702810f70d06a android.hardware.gatekeeper@1.0::types
+37c7da4f823ec958dfa9c960e2d341c48f877e0bfa758f3fa9e2d9c1e1bd66d9 android.hardware.gnss@1.0::IAGnss
+7ec9afdb964bfb8369866913caf018f2636592885bcb558a65de2c5436ab4f60 android.hardware.gnss@1.0::IAGnssCallback
+d16e6a359be6963ea753d7138e84ecf2b93052097938938c4d36d7a47ea2e2ae android.hardware.gnss@1.0::IAGnssRil
+2f907708d74d94b1e121ed27651c9c72af65952d347b58ff07dac5d5d7a7f678 android.hardware.gnss@1.0::IAGnssRilCallback
+5ac7edad06d76064b882be161f3f9d9692a997ec72e9f36addb7fe8918f49992 android.hardware.gnss@1.0::IGnss
+b05c983c87c3376e145223688c3b541b5e11b827f211e38d5a31af1ca3a2e222 android.hardware.gnss@1.0::IGnssBatching
+4981d2d2c4e725c7544be0956099a91fc7bbc8048c563394158083fe924e651e android.hardware.gnss@1.0::IGnssBatchingCallback
+3cd22d92cc1f935150c5048310e84886f14eed2556e8f00636733d204045cc4f android.hardware.gnss@1.0::IGnssCallback
+175185a5eda87476193ca5461df75dd16d36664591e8130530dd8ef0eb2ddf6a android.hardware.gnss@1.0::IGnssConfiguration
+4542122b96fbf27101cb8222bafb76e7c8d032d977dd1058edd8e5881ca5752f android.hardware.gnss@1.0::IGnssDebug
+e6dd0c8416e523ab9cbd14d56ab6f016481a8aef3bc8a750051122d31075f6c7 android.hardware.gnss@1.0::IGnssGeofenceCallback
+f90e4ddc652706299d8e3d8ba18e0745c3bae9bf4d1be6bd06d9c1f50ec8d28a android.hardware.gnss@1.0::IGnssGeofencing
+9ea8987bb1089c8c5d7b67866575b866ef516045021d9efcc37c6352bce072a3 android.hardware.gnss@1.0::IGnssMeasurement
+cf20492673d6a423e4c2e87fdfb5a4c4a602431721978db852e246f258e25edb android.hardware.gnss@1.0::IGnssMeasurementCallback
+af85aa0f48ae99a39f4688c344e4419304f681f9af818a5c8d759286fc4418de android.hardware.gnss@1.0::IGnssNavigationMessage
+76b0874ea4c06b29f66418c59820f4286b3be9629cd872923d0dfbb602cd432d android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+248bcf51da4273d64f367bf6877baef2feeaca365459842fd3c214a2dc6e0224 android.hardware.gnss@1.0::IGnssNi
+c781b7b125f68be5db8a8c3d412d526acdbdf77dcc592a4c0ed70b8ce4fe6c49 android.hardware.gnss@1.0::IGnssNiCallback
+c1142657de16fdb292a502372fe938614d65270ab8359217d6e13604fe4dbca4 android.hardware.gnss@1.0::IGnssXtra
+bd366b83d8d565d0e8bfabff3adfcab0259d75b4e2a9f8e1b91e11d1593a2ffb android.hardware.gnss@1.0::IGnssXtraCallback
+881bc2f94026784d194cffbff166c6e8bf911de4e02abe96fc7d89ec75b0574a android.hardware.gnss@1.0::types
+17971eb8a482893dadcfc16e0583f492d42a034ef95d9b0b709417af30838396 android.hardware.graphics.allocator@2.0::IAllocator
+60bf42a4898e4fb70dbd720b263aeafd7f35f5e1a5effeabb4d5d659878a5f18 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer
+b8a75617b9ec12bea641f3a73d4025a33e8b9a2f9169dd46094af56adf9249c5 android.hardware.graphics.bufferqueue@1.0::IProducerListener
+4f6dedbcdd21c309dfc650acea81a096d6b242493ffe49c8d61bd3c43aad354e android.hardware.graphics.common@1.0::types
+b3aac6c3817f039964fcd62268274b3039e17bd7d0d5b40b4d1d1c7b19a1f866 android.hardware.graphics.composer@2.1::IComposer
+b19d00eb8a8b3b0034a0321f22e8f32162bf4c2aebbce6da22c025f56e459ea2 android.hardware.graphics.composer@2.1::IComposerCallback
+61ee43ffe6fb6dbe8b22dc17c51ff3d5ba703fc6029cba211f901f3d79c8a72d android.hardware.graphics.composer@2.1::IComposerClient
+1c98c2f5154345312ec054871792a2982ec5f3e2bc2abfb61a10c0b517978e20 android.hardware.graphics.composer@2.1::types
+a695898589e1ef15b2b2510f11edd6aafac9918d9cf8d74b4b6143b309dee542 android.hardware.graphics.mapper@2.0::IMapper
+28507d385a3dd224bf3c32f1bfd9f96092c4701b9c1cc66caa578fc3efc97877 android.hardware.graphics.mapper@2.0::types
+91e2ba3805c923f01fc1231ec9ff838942aee3346f2d7614ecc0caeadbe57ed4 android.hardware.health@1.0::IHealth
+1275aa2e8732909101b26aec49ed2285489e89d97b8610a8908b7868e35a3cc5 android.hardware.health@1.0::types
+3a8d3922e06e6d4f8e0befc6be78d0e9e07aed1585b3da6521bed406d25a9483 android.hardware.ir@1.0::IConsumerIr
+7090bd37912fcf723a12f4bc17783e3527577c4944805a028c296fd7a95bd682 android.hardware.ir@1.0::types
+cc7925a78c0ab022515f48840d3dae76f384ed3a1287abadcb461a5cd5396163 android.hardware.keymaster@3.0::IKeymasterDevice
+822998d7bb76f0cd719a409291434fcb56e6d50bc4780788bb157a3374d63b8c android.hardware.keymaster@3.0::types
+d4ed2f0e14f9e914d0b1275d2e0363192fe30aca9059c84edb5fad15995f9ec4 android.hardware.light@2.0::ILight
+d9584bfcaedd6e62cf337881748246b23e36cbc2bc3aa84c01b6a1e622061400 android.hardware.light@2.0::types
+16c0cf0f73de1e5208a95020c6c6474903e7094f76b2d782651afaca0e5fd86f android.hardware.media@1.0::types
+8bc2f5fdcad68856eb61a62fe4cc043fa064bb7f1dab95a71d1918ec1eef7b55 android.hardware.media.omx@1.0::IGraphicBufferSource
+0d3de9cd89d4718ea3b772f2d8b93be004feb3abb7e7dc5402e37047cc730d05 android.hardware.media.omx@1.0::IOmx
+32002e1c358c64de106c977a6dc6af7da27be4803a5bb66fd6f891a5ba0a1617 android.hardware.media.omx@1.0::IOmxBufferSource
+81ad8d8bb1cf6f41923cf11dd39354a8fe433db284a234cc675de7e75a82224c android.hardware.media.omx@1.0::IOmxNode
+494c0c8bf6065edc82ec127228ed19dd2243dc1c2f7d601c7c6be7b7015c1713 android.hardware.media.omx@1.0::IOmxObserver
+252c2fc50c78fd6de8365e5b60e5115119ace107db0b94b0b26815cbf3d2b64a android.hardware.media.omx@1.0::IOmxStore
+148c1b50b0958988373145ffdf5fa0e1b6534e0a2034a570e74b15c127cf7c5e android.hardware.media.omx@1.0::types
+c66902fe48d687ac6740a3e32ae55fb75532c48c36c6386461c2b4416ad2e0f1 android.hardware.memtrack@1.0::IMemtrack
+860bacd8b11a269c40567542b613fe4ca448d5cb4326d0058899e608e89dfca1 android.hardware.memtrack@1.0::types
+07ac2dc95270321ec7d4c33cd25e5085a057f47fe350d645af6f7a7a11e3cf57 android.hardware.nfc@1.0::INfc
+f2fe54426c07d67388d4774a60641ad4c0538f22eb6e1111722f231772655de6 android.hardware.nfc@1.0::INfcClientCallback
+9626fd18db113d709faf593a70caf19bd0980294d23c468c80c30186f9d298a6 android.hardware.nfc@1.0::types
+deee1dc4948f33af207e1008aba0f6cc07afb7900eab53f33192c8cac137eefc android.hardware.power@1.0::IPower
+efc83df3f962b93c7c0290d691d7d300dabe12683e2cde3591fb3c0beedce20f android.hardware.power@1.0::types
+9b5aa499ec3b4226f15f48f5ed08896e2fc0676f978c9e199c1da21daaf002a6 android.hardware.radio@1.0::IRadio
+5c8efbb9c451a59737ed2c6c20230aae4745839ca01d8088d6dcc9020e52d2c5 android.hardware.radio@1.0::IRadioIndication
+69f6b4b8ec40ca02ccc7bb8227a097135c20c00bd94c822e421cd9af1267252c android.hardware.radio@1.0::IRadioResponse
+de3ab9f73b1073cd677b19d886fb927e9381b30161a704712d2b30f875873f5c android.hardware.radio@1.0::ISap
+d183e406ef0897df2117a9dde384e8e6ea4fa6ab1c7f6f28e65b87011218c9ea android.hardware.radio@1.0::ISapCallback
+96986fbd22f0e6ca752e1fcdc0a64bda213995a81f5f36bc4faf3532d9306b97 android.hardware.radio@1.0::types
+00f70085d6fae1d482fb700a3fd42ed475384c95b51c9269b9ae5037b74ad4dd android.hardware.radio.deprecated@1.0::IOemHook
+06837b6d7e843cfa9cd20fed4070feca7a9b5c81a9ed643bf7d06803455a9816 android.hardware.radio.deprecated@1.0::IOemHookIndication
+6fd4874f0eddd4626a27658fd94fad526c317f3563439e79718bdb1a3a2309d5 android.hardware.radio.deprecated@1.0::IOemHookResponse
+6983a2cafe39d5c57dfdc1743055fb0f757a0df8c78e00423d5e1810836927e1 android.hardware.renderscript@1.0::IContext
+7f9417a0ccf78ea042ec7a8ac8e3750346d4d9d7e5ae01b1b35fde303f47c24d android.hardware.renderscript@1.0::IDevice
+fc6f325b266b32353f7d1534fbe58e0d368265a12b77fa396fb556e8c443f739 android.hardware.renderscript@1.0::types
+89585ff541c319de4091a5a0b687dd526ac81c6382ffd7b979a4164b3d7419a6 android.hardware.sensors@1.0::ISensors
+e04ab978fc28f4c515f4a75617dfda8607733a64f13666beeb0e604a07a39333 android.hardware.sensors@1.0::types
+5befc019cbe94953661e2cdb95e3cf64f5e565c29403e1c2daecc2be44e0a55c android.hardware.soundtrigger@2.0::ISoundTriggerHw
+d7ec5f612a5e0a59ea4f2b61317e208ff56dd50920fd4eb441e0cbc8f97e4f49 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
+5bee9e70f7e5ec7ee252883b28f98f12b59960f4c2a0b4cc9a4526e4669ebcd4 android.hardware.soundtrigger@2.0::types
+97f1ec446043bc5a6645b74529a6276496bdb35e0aee41eda55cb92d51eb7802 android.hardware.thermal@1.0::IThermal
+84965a6908bceb4ef51546bf8731f309f1ea9d09a0177dcc7974132e523dd6d2 android.hardware.thermal@1.0::types
+938850621c3c5ef426a4b88e752ba99b3559037e782a3d938604f3aef5cc0f1b android.hardware.tv.cec@1.0::IHdmiCec
+e75b6eea711d36fac678bce072b3cec6544b27fa9f4cd903999404e5c110ca10 android.hardware.tv.cec@1.0::IHdmiCecCallback
+6e25f8dbfadb668e1d4ec80eb9acd95d8bc9e0a240c36d27e662adb440314b95 android.hardware.tv.cec@1.0::types
+0cafa3c8388e9631916d2d800f78decbcec2904f11415b32c71a31d9a51ebf79 android.hardware.tv.input@1.0::ITvInput
+dee83e5c864fbbee8f02448d0800be32f06856386b9f907bc5d952208c9434f9 android.hardware.tv.input@1.0::ITvInputCallback
+07aab30410b612381234dca6d453d4ab96f2e536368715717c6e28101b9851b5 android.hardware.tv.input@1.0::types
+4ef57499273f38bdbdd0c15e56ee7a4bc5f18a5644092170a531df3541d9e015 android.hardware.usb@1.0::IUsb
+4be7881e411ba42784bf5b7354c14ae0cf161004d39433aaecaab0d19ea99354 android.hardware.usb@1.0::IUsbCallback
+f7e6e747910a3cd0a35846141e3b990a6a612a297b2b70ccd5740b646a450a8c android.hardware.usb@1.0::types
+06ea64cc3565777f3b259e400ffa7100d07f3827ad9357b0c5d3c651384e5553 android.hardware.vibrator@1.0::IVibrator
+0fecd34ae64f32eff6aa615fd662349242c0b8b6e303ef05a7cb5776c732f413 android.hardware.vibrator@1.0::types
+4b962968a7df4ab104d1315d66a0a7348a713fecbb5d2c1b23688494458f37ce android.hardware.vr@1.0::IVr
+b9be36719a8ad534000a51ea07be91be94c405bf1e038ae825acf65087ffd378 android.hardware.wifi@1.0::IWifi
+ee0224ee18813506d9d6f13d8c8e4679f053c290a443a52a7c52a5d3c852262b android.hardware.wifi@1.0::IWifiApIface
+f3eecc489deb4c74892f59eb7adb769063bd5c354ac132b626a5f42b363d36bc android.hardware.wifi@1.0::IWifiChip
+a1b988377645a58e5e2542ca2bad4e17c21a4a389213d05de2f0e32d57b7d339 android.hardware.wifi@1.0::IWifiChipEventCallback
+5ed6760ce77e84bc6c49d1acb3f7d8117c9176b3f06514bc44ad3af84c80dcfe android.hardware.wifi@1.0::IWifiEventCallback
+6b9ad43a5efbe6ca214f751e22ce43cf5cd4d5d5f2cba80f24ccd3755a72401c android.hardware.wifi@1.0::IWifiIface
+ba5aa74f1ba714f0093864227923492808795bda6199c4ea0891322d27f8c931 android.hardware.wifi@1.0::IWifiNanIface
+325c94f3e1a565b56bbc74faddbd0ba7cb824f263dccf9dfff2daf62b86ed774 android.hardware.wifi@1.0::IWifiNanIfaceEventCallback
+c2c3f0372b41780fb6dfe83c022296806c2024d7046682fd201de5aa9b791c7a android.hardware.wifi@1.0::IWifiP2pIface
+766e9765f5c9c759b2a763c2288353fb5deff3389c2cc28f81d79c939704ce8b android.hardware.wifi@1.0::IWifiRttController
+72ab6f3e120cbf07aa6f8e87ca89112bdeb36b7fbb96bce5af3712323ab8b8e6 android.hardware.wifi@1.0::IWifiRttControllerEventCallback
+3b8093d39ef1e10e43c5538afbf5ff6e39b8d8168ebbe1998d993e89e25f14a5 android.hardware.wifi@1.0::IWifiStaIface
+7fbfc551c3e23c8b4398c3e16e452b516457e6921424a53474cbf373ca306fa9 android.hardware.wifi@1.0::IWifiStaIfaceEventCallback
+e20d5132d6d23e072c15de065b5e2aa13ff965031246a2c82581732bae56bf6d android.hardware.wifi@1.0::types
+f7e55c08187d8c855068a1ee3d0c8daeee7570292d96509c21a8756d4f5cfb9b android.hardware.wifi.supplicant@1.0::ISupplicant
+56b5c7267cb3d3337f44eb8b0b38ff4c6260dcc70e07687fcab94b1ccea8d159 android.hardware.wifi.supplicant@1.0::ISupplicantCallback
+35ba7bcdf18f24a866a7e5429548f06768bb20a257f75b10a397c4d825ef8438 android.hardware.wifi.supplicant@1.0::ISupplicantIface
+cda01008c06922fa37c1213e9bb831a109b3174532805616fb7161edc403866f android.hardware.wifi.supplicant@1.0::ISupplicantNetwork
+4907410338c5e8dbeec4b5edc2608ea323f5561945f8810af81810c47b019184 android.hardware.wifi.supplicant@1.0::ISupplicantP2pIface
+8b63f5efa2e3be3a7cb8a428760d82285a4ab79bcbdea6ef90aa547555e582d4 android.hardware.wifi.supplicant@1.0::ISupplicantP2pIfaceCallback
+56128f74560571b6777d59453f35c6b35693ee377e2a23c807708906928f09de android.hardware.wifi.supplicant@1.0::ISupplicantP2pNetwork
+2067c22197bca9743dab66a6f561a8a8375c67b4f76aed05f776839499bd4c8f android.hardware.wifi.supplicant@1.0::ISupplicantP2pNetworkCallback
+7752e1de93aaf5fed37011c219ac247069f6af320b0810daa98510584a10e7b4 android.hardware.wifi.supplicant@1.0::ISupplicantStaIface
+d781c8d7e7b3fe5cca8cf6e1d8806e770982ae5358c7816ed51b0f0ec272e70d android.hardware.wifi.supplicant@1.0::ISupplicantStaIfaceCallback
+b12ef0bdd8a4d247a8a6e960b227ed32383f2b0241f55d67fcea6eff6a6737fa android.hardware.wifi.supplicant@1.0::ISupplicantStaNetwork
+d8f0877ae1d321c1d884c7631dfe36cab0ec8a4b2863d4b687f85d3549a63bcc android.hardware.wifi.supplicant@1.0::ISupplicantStaNetworkCallback
+fe3c3c2f572b72f15f8594c538b0577bd5c28722c31879cfe6231330cddb6747 android.hardware.wifi.supplicant@1.0::types
+
+# ABI preserving changes to HALs released in Android O
+
+78589343d8ee2e1b155acad3fbdc7fcbb6af94491aee968b2383c21627264f8b android.hardware.radio@1.0::IRadioResponse
+c2c50ec74c87a583c683b4493f8f9f2e454a8d41c57af5b3eb88823a999f0ea4 android.hardware.radio@1.0::IRadioResponse
diff --git a/prebuilt_hashes/27.txt b/prebuilt_hashes/27.txt
new file mode 100644
index 0000000..23f2004
--- /dev/null
+++ b/prebuilt_hashes/27.txt
@@ -0,0 +1,249 @@
+# Do not change this file except to add new interfaces. Changing
+# pre-existing interfaces will fail VTS and break framework-only OTAs
+
+# HALs released in Android O
+
+f219c3b5b8c6cb1d659d4c7328f67246abfe1a8613f469826fd3b9ad090417a2 android.hardware.audio@2.0::IDevice
+4d579cae1cd87a783fd49233e10ce720ba183cfd1d5ccd80149e69de5c1c7362 android.hardware.audio@2.0::IDevicesFactory
+203e23f18011390b8cd10c303e0c16c4eebc8fa187e80e40d6be4624c2b0848a android.hardware.audio@2.0::IPrimaryDevice
+aaf93123deec336eb247ad8099849469a541ca0cf7c28c5f5336cebe1ee86748 android.hardware.audio@2.0::IStream
+0468c5723b0d44c5b451bdfa06153000c6f352fd3336e0ad2697127b04b766df android.hardware.audio@2.0::IStreamIn
+7296f7064fd3ab24082b43a1da34cc876268065310b785499fba5178d063680a android.hardware.audio@2.0::IStreamOut
+19d241d71c3e1140afba8140dcb57448446025a5fc03739788c4c25e9a98b6c2 android.hardware.audio@2.0::IStreamOutCallback
+c84da9f586087227daa3b96d42b4575326bccfd5bc8a2a5acf86d774f8ea2648 android.hardware.audio@2.0::types
+1305786c06e22b9b24ebde136054cc827b63c86d8bf4a136d6f7f54752b8566b android.hardware.audio.common@2.0::types
+fa8fbae3d1da3c264e4f3110728076abc09b4e65f12af6ae136367328de988ab android.hardware.audio.effect@2.0::IAcousticEchoCancelerEffect
+ca4752545d54547ff069eae161af7550cb5f5a7e8b60316ddd132a30906a68e7 android.hardware.audio.effect@2.0::IAutomaticGainControlEffect
+d2b8af988dc66f514d886bcee44b440d8034bc2a762f7161717ef3c956073067 android.hardware.audio.effect@2.0::IBassBoostEffect
+611bc09c75e796f3512b1ca6be508b0a9ba996759b8a2c60507784ff58076229 android.hardware.audio.effect@2.0::IDownmixEffect
+36a57369dfdc75180e8b64ae80b1970db8f6d9085dbff6ca931715038cc056e1 android.hardware.audio.effect@2.0::IEffect
+d2aa2df6d189c580f5be8460fa0ff4134d9c05a383f3204659baee426a6f0edf android.hardware.audio.effect@2.0::IEffectBufferProviderCallback
+217f9161983a48d3bf3faeb158f868aa8bf0ce25889e4ee3d2bab1a2e8d33e77 android.hardware.audio.effect@2.0::IEffectsFactory
+c2b38bc07991e880c83ca8cb88181411eeef708b8b936aedd2f2e0acade7df69 android.hardware.audio.effect@2.0::IEnvironmentalReverbEffect
+2ff9f9704be5f167745b4de790e9dafc3cc4719e2f6e2e5497085e679853cfe7 android.hardware.audio.effect@2.0::IEqualizerEffect
+c31447fb02dbc8b56c359941dad22f416511860173c5c5fd278d1bf2312b13de android.hardware.audio.effect@2.0::ILoudnessEnhancerEffect
+804831ca258802eb3eb65a0a7b5d5e3d37d4a15ba8c2836b4276eda98b47e1d0 android.hardware.audio.effect@2.0::INoiseSuppressionEffect
+778fd5b9837f481d8e47425b3e2a3bd0c6362a0b6870291518e2d863530fdb61 android.hardware.audio.effect@2.0::IPresetReverbEffect
+c93cb25a1a92d07aa80a617c01e8d22fc97bf8cefd3962b6a5be386ad4704d89 android.hardware.audio.effect@2.0::IVirtualizerEffect
+918f331780c9c7b04f2151a2e563aab088198ede8e6f865302ebaa13905bd9ce android.hardware.audio.effect@2.0::IVisualizerEffect
+4caad099f8fc00262b6c03ba41271808b37cea90ac98b534299bbf4ee823af02 android.hardware.audio.effect@2.0::types
+# android.hardware.automotive.* are unfrozen
+1fbdc1f852f8bd2e4a6c5cb30ac2b78668c98dce118a61762d4034ae859f43d8 android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint
+aabb5c3c585592d71ee57b77298c14993d77914ddeaa64b2c5109a602b02ea47 android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprintClientCallback
+1ec60d4efddae9a7b2469278a576967b4751e88de5b8d7e9df6eff6bc0da7bc9 android.hardware.biometrics.fingerprint@2.1::types
+347ce746815607567f5f3b53e4800998ca5ab9355141f0880fc0cf0c1fc5c355 android.hardware.bluetooth@1.0::IBluetoothHci
+835f41be2281bfb22f3e33c6fa870bde7bc21e37e5cfbaf9a36fff170632f754 android.hardware.bluetooth@1.0::IBluetoothHciCallbacks
+a8dfd0dbe463a3cdbcf1d985b38a28b3d93ba2ae5a1d1db4aaef4c38a5781b91 android.hardware.bluetooth@1.0::types
+7192d756aeba00aba32f4504981df8172ffca83e210c4838dabf295e53e93590 android.hardware.boot@1.0::IBootControl
+cebaa803b8e33807a0d69f46652b650ccb549e8f9b19d6becbbf26690e828b49 android.hardware.boot@1.0::types
+a98d49f23712a7cc327d1e0602d05f6f3ad32cfb5c74711d009c726611ee1c93 android.hardware.broadcastradio@1.0::IBroadcastRadio
+ed82579c0c165feaa12d0e33c06b3342ab41ec0a439247f202775e8369e46ef6 android.hardware.broadcastradio@1.0::IBroadcastRadioFactory
+da6ab32ee2793d2c86d3b603075d5383852b89d7eaa201861aa0473d418f3c7f android.hardware.broadcastradio@1.0::ITuner
+04d3ca022e25c308d9efd2e7eb77b3a7a206907cdc1b9ea9326340b377868172 android.hardware.broadcastradio@1.0::ITunerCallback
+bd42c8d7838cfed1998b49c39745dec116d2d6edc2c11a4c0399b8f3a1d1655a android.hardware.broadcastradio@1.0::types
+81164323115d6588e259e8319fddf7487adfa1f49ce60f7e80ba74e0783392a4 android.hardware.camera.common@1.0::types
+c1705e9d62438a1d955269965af915ae28e692bd480a3b1ce67056fef992d62f android.hardware.camera.device@1.0::ICameraDevice
+78e9b44cf8660bdc1e98dca07451804153824efcd28db208a62f5ad728f44076 android.hardware.camera.device@1.0::ICameraDeviceCallback
+28f0386ba86ddf41e53a8117b48a0328d7a4d2574213e89f4a1062398a244566 android.hardware.camera.device@1.0::ICameraDevicePreviewCallback
+4db48439ce9dde97f1cfb3d7408f6c737f621ac0f7494aeea35ed599bc2352a3 android.hardware.camera.device@1.0::types
+b32f9aeaf1c442195eb06ffc7600968c919d005b2718874f09c57287fae55918 android.hardware.camera.device@3.2::ICameraDevice
+63bfc3da0f2d2301f7a0508c7c2b9ffc521d4d545ee03718da70e9d6273b3b21 android.hardware.camera.device@3.2::ICameraDeviceCallback
+0fa3e1e64819283b8737fc4e5ab759f0cb4ac1a996e8a51cc4aa8025a457208e android.hardware.camera.device@3.2::ICameraDeviceSession
+030be3d2b159cbde7920485807140f6b6064ef4a5de4a40a6c4bc8d2c72f7cd3 android.hardware.camera.device@3.2::types
+5ba7947cee515d7a2359bfcbfb9678c1c3a768c288471919ac095b96ae6f3d40 android.hardware.camera.metadata@3.2::types
+f7e299d85033ac52d1095a35784fcfeaff43603f58c751e4153c85bbade3b330 android.hardware.camera.provider@2.4::ICameraProvider
+a501ca1aecd09f1b9fd70a9af84205430dbd49a808e8fa395d363b9902e6f58c android.hardware.camera.provider@2.4::ICameraProviderCallback
+7f5fe8f4f8a24037153c504d8b4d3313c2ce33d81c8c69fe5194ddd2d4080e72 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
+87beacc481897cf02fb1628d75e68133de6d74d4cffe582cda2f5e16bdd74516 android.hardware.configstore@1.0::types
+a5ae0fe8667f0b1af09b13e72d29600f4eb3853b257079c45a99b6f4a3360649 android.hardware.contexthub@1.0::IContexthub
+2ab3054c2d9302d8417ee7495353a2887fe338f913276f2eb41e80f11395ec2e android.hardware.contexthub@1.0::IContexthubCallback
+c3b2b37d561d31ea094411f251bf73bea334f4fe849a4390aef5e20bca6cadba android.hardware.contexthub@1.0::types
+df174c1871c864b4c79ca9f64aae7936d24a272eca3191a30458ca2b706dec79 android.hardware.drm@1.0::ICryptoFactory
+83639e90caeb996b0274e420de3cd556779de1ca48464b68eee799bef32b34cd android.hardware.drm@1.0::ICryptoPlugin
+1440cffdfaeb12830ac10ee6ffdb0f1083e701057b806df11fb4787b4c91e718 android.hardware.drm@1.0::IDrmFactory
+78ba33b108f620e6a0eec01ef654547e69a85754578ea4c9ef03ec205f16121c android.hardware.drm@1.0::IDrmPlugin
+701d9e51952172364e4ea70db9c397f08c3b4577ba33051f050a6cdd532de1b4 android.hardware.drm@1.0::IDrmPluginListener
+4238d62ad90df63aa338c6f1b6264c09c5a3706945d5c49d1189c0be1dc9e942 android.hardware.drm@1.0::types
+f07b1ee3ba11a2fc9f200421b2e1afb7c1854ee987000e45c987fb9507795055 android.hardware.dumpstate@1.0::IDumpstateDevice
+c9d318df7922bde3b265927b521ff5a965002826fc0cabfcaef52a56760f2d34 android.hardware.gatekeeper@1.0::IGatekeeper
+da13bd69282fb275767abb18704c57ff8038e6c139ad17157dc702810f70d06a android.hardware.gatekeeper@1.0::types
+37c7da4f823ec958dfa9c960e2d341c48f877e0bfa758f3fa9e2d9c1e1bd66d9 android.hardware.gnss@1.0::IAGnss
+7ec9afdb964bfb8369866913caf018f2636592885bcb558a65de2c5436ab4f60 android.hardware.gnss@1.0::IAGnssCallback
+d16e6a359be6963ea753d7138e84ecf2b93052097938938c4d36d7a47ea2e2ae android.hardware.gnss@1.0::IAGnssRil
+2f907708d74d94b1e121ed27651c9c72af65952d347b58ff07dac5d5d7a7f678 android.hardware.gnss@1.0::IAGnssRilCallback
+5ac7edad06d76064b882be161f3f9d9692a997ec72e9f36addb7fe8918f49992 android.hardware.gnss@1.0::IGnss
+b05c983c87c3376e145223688c3b541b5e11b827f211e38d5a31af1ca3a2e222 android.hardware.gnss@1.0::IGnssBatching
+4981d2d2c4e725c7544be0956099a91fc7bbc8048c563394158083fe924e651e android.hardware.gnss@1.0::IGnssBatchingCallback
+3cd22d92cc1f935150c5048310e84886f14eed2556e8f00636733d204045cc4f android.hardware.gnss@1.0::IGnssCallback
+175185a5eda87476193ca5461df75dd16d36664591e8130530dd8ef0eb2ddf6a android.hardware.gnss@1.0::IGnssConfiguration
+4542122b96fbf27101cb8222bafb76e7c8d032d977dd1058edd8e5881ca5752f android.hardware.gnss@1.0::IGnssDebug
+e6dd0c8416e523ab9cbd14d56ab6f016481a8aef3bc8a750051122d31075f6c7 android.hardware.gnss@1.0::IGnssGeofenceCallback
+f90e4ddc652706299d8e3d8ba18e0745c3bae9bf4d1be6bd06d9c1f50ec8d28a android.hardware.gnss@1.0::IGnssGeofencing
+9ea8987bb1089c8c5d7b67866575b866ef516045021d9efcc37c6352bce072a3 android.hardware.gnss@1.0::IGnssMeasurement
+cf20492673d6a423e4c2e87fdfb5a4c4a602431721978db852e246f258e25edb android.hardware.gnss@1.0::IGnssMeasurementCallback
+af85aa0f48ae99a39f4688c344e4419304f681f9af818a5c8d759286fc4418de android.hardware.gnss@1.0::IGnssNavigationMessage
+76b0874ea4c06b29f66418c59820f4286b3be9629cd872923d0dfbb602cd432d android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+248bcf51da4273d64f367bf6877baef2feeaca365459842fd3c214a2dc6e0224 android.hardware.gnss@1.0::IGnssNi
+c781b7b125f68be5db8a8c3d412d526acdbdf77dcc592a4c0ed70b8ce4fe6c49 android.hardware.gnss@1.0::IGnssNiCallback
+c1142657de16fdb292a502372fe938614d65270ab8359217d6e13604fe4dbca4 android.hardware.gnss@1.0::IGnssXtra
+bd366b83d8d565d0e8bfabff3adfcab0259d75b4e2a9f8e1b91e11d1593a2ffb android.hardware.gnss@1.0::IGnssXtraCallback
+881bc2f94026784d194cffbff166c6e8bf911de4e02abe96fc7d89ec75b0574a android.hardware.gnss@1.0::types
+17971eb8a482893dadcfc16e0583f492d42a034ef95d9b0b709417af30838396 android.hardware.graphics.allocator@2.0::IAllocator
+60bf42a4898e4fb70dbd720b263aeafd7f35f5e1a5effeabb4d5d659878a5f18 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer
+b8a75617b9ec12bea641f3a73d4025a33e8b9a2f9169dd46094af56adf9249c5 android.hardware.graphics.bufferqueue@1.0::IProducerListener
+4f6dedbcdd21c309dfc650acea81a096d6b242493ffe49c8d61bd3c43aad354e android.hardware.graphics.common@1.0::types
+b3aac6c3817f039964fcd62268274b3039e17bd7d0d5b40b4d1d1c7b19a1f866 android.hardware.graphics.composer@2.1::IComposer
+b19d00eb8a8b3b0034a0321f22e8f32162bf4c2aebbce6da22c025f56e459ea2 android.hardware.graphics.composer@2.1::IComposerCallback
+61ee43ffe6fb6dbe8b22dc17c51ff3d5ba703fc6029cba211f901f3d79c8a72d android.hardware.graphics.composer@2.1::IComposerClient
+1c98c2f5154345312ec054871792a2982ec5f3e2bc2abfb61a10c0b517978e20 android.hardware.graphics.composer@2.1::types
+a695898589e1ef15b2b2510f11edd6aafac9918d9cf8d74b4b6143b309dee542 android.hardware.graphics.mapper@2.0::IMapper
+28507d385a3dd224bf3c32f1bfd9f96092c4701b9c1cc66caa578fc3efc97877 android.hardware.graphics.mapper@2.0::types
+91e2ba3805c923f01fc1231ec9ff838942aee3346f2d7614ecc0caeadbe57ed4 android.hardware.health@1.0::IHealth
+1275aa2e8732909101b26aec49ed2285489e89d97b8610a8908b7868e35a3cc5 android.hardware.health@1.0::types
+3a8d3922e06e6d4f8e0befc6be78d0e9e07aed1585b3da6521bed406d25a9483 android.hardware.ir@1.0::IConsumerIr
+7090bd37912fcf723a12f4bc17783e3527577c4944805a028c296fd7a95bd682 android.hardware.ir@1.0::types
+cc7925a78c0ab022515f48840d3dae76f384ed3a1287abadcb461a5cd5396163 android.hardware.keymaster@3.0::IKeymasterDevice
+822998d7bb76f0cd719a409291434fcb56e6d50bc4780788bb157a3374d63b8c android.hardware.keymaster@3.0::types
+d4ed2f0e14f9e914d0b1275d2e0363192fe30aca9059c84edb5fad15995f9ec4 android.hardware.light@2.0::ILight
+d9584bfcaedd6e62cf337881748246b23e36cbc2bc3aa84c01b6a1e622061400 android.hardware.light@2.0::types
+16c0cf0f73de1e5208a95020c6c6474903e7094f76b2d782651afaca0e5fd86f android.hardware.media@1.0::types
+8bc2f5fdcad68856eb61a62fe4cc043fa064bb7f1dab95a71d1918ec1eef7b55 android.hardware.media.omx@1.0::IGraphicBufferSource
+0d3de9cd89d4718ea3b772f2d8b93be004feb3abb7e7dc5402e37047cc730d05 android.hardware.media.omx@1.0::IOmx
+32002e1c358c64de106c977a6dc6af7da27be4803a5bb66fd6f891a5ba0a1617 android.hardware.media.omx@1.0::IOmxBufferSource
+81ad8d8bb1cf6f41923cf11dd39354a8fe433db284a234cc675de7e75a82224c android.hardware.media.omx@1.0::IOmxNode
+494c0c8bf6065edc82ec127228ed19dd2243dc1c2f7d601c7c6be7b7015c1713 android.hardware.media.omx@1.0::IOmxObserver
+252c2fc50c78fd6de8365e5b60e5115119ace107db0b94b0b26815cbf3d2b64a android.hardware.media.omx@1.0::IOmxStore
+148c1b50b0958988373145ffdf5fa0e1b6534e0a2034a570e74b15c127cf7c5e android.hardware.media.omx@1.0::types
+c66902fe48d687ac6740a3e32ae55fb75532c48c36c6386461c2b4416ad2e0f1 android.hardware.memtrack@1.0::IMemtrack
+860bacd8b11a269c40567542b613fe4ca448d5cb4326d0058899e608e89dfca1 android.hardware.memtrack@1.0::types
+07ac2dc95270321ec7d4c33cd25e5085a057f47fe350d645af6f7a7a11e3cf57 android.hardware.nfc@1.0::INfc
+f2fe54426c07d67388d4774a60641ad4c0538f22eb6e1111722f231772655de6 android.hardware.nfc@1.0::INfcClientCallback
+9626fd18db113d709faf593a70caf19bd0980294d23c468c80c30186f9d298a6 android.hardware.nfc@1.0::types
+deee1dc4948f33af207e1008aba0f6cc07afb7900eab53f33192c8cac137eefc android.hardware.power@1.0::IPower
+efc83df3f962b93c7c0290d691d7d300dabe12683e2cde3591fb3c0beedce20f android.hardware.power@1.0::types
+9b5aa499ec3b4226f15f48f5ed08896e2fc0676f978c9e199c1da21daaf002a6 android.hardware.radio@1.0::IRadio
+5c8efbb9c451a59737ed2c6c20230aae4745839ca01d8088d6dcc9020e52d2c5 android.hardware.radio@1.0::IRadioIndication
+69f6b4b8ec40ca02ccc7bb8227a097135c20c00bd94c822e421cd9af1267252c android.hardware.radio@1.0::IRadioResponse
+de3ab9f73b1073cd677b19d886fb927e9381b30161a704712d2b30f875873f5c android.hardware.radio@1.0::ISap
+d183e406ef0897df2117a9dde384e8e6ea4fa6ab1c7f6f28e65b87011218c9ea android.hardware.radio@1.0::ISapCallback
+96986fbd22f0e6ca752e1fcdc0a64bda213995a81f5f36bc4faf3532d9306b97 android.hardware.radio@1.0::types
+00f70085d6fae1d482fb700a3fd42ed475384c95b51c9269b9ae5037b74ad4dd android.hardware.radio.deprecated@1.0::IOemHook
+06837b6d7e843cfa9cd20fed4070feca7a9b5c81a9ed643bf7d06803455a9816 android.hardware.radio.deprecated@1.0::IOemHookIndication
+6fd4874f0eddd4626a27658fd94fad526c317f3563439e79718bdb1a3a2309d5 android.hardware.radio.deprecated@1.0::IOemHookResponse
+6983a2cafe39d5c57dfdc1743055fb0f757a0df8c78e00423d5e1810836927e1 android.hardware.renderscript@1.0::IContext
+7f9417a0ccf78ea042ec7a8ac8e3750346d4d9d7e5ae01b1b35fde303f47c24d android.hardware.renderscript@1.0::IDevice
+fc6f325b266b32353f7d1534fbe58e0d368265a12b77fa396fb556e8c443f739 android.hardware.renderscript@1.0::types
+89585ff541c319de4091a5a0b687dd526ac81c6382ffd7b979a4164b3d7419a6 android.hardware.sensors@1.0::ISensors
+e04ab978fc28f4c515f4a75617dfda8607733a64f13666beeb0e604a07a39333 android.hardware.sensors@1.0::types
+5befc019cbe94953661e2cdb95e3cf64f5e565c29403e1c2daecc2be44e0a55c android.hardware.soundtrigger@2.0::ISoundTriggerHw
+d7ec5f612a5e0a59ea4f2b61317e208ff56dd50920fd4eb441e0cbc8f97e4f49 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
+5bee9e70f7e5ec7ee252883b28f98f12b59960f4c2a0b4cc9a4526e4669ebcd4 android.hardware.soundtrigger@2.0::types
+97f1ec446043bc5a6645b74529a6276496bdb35e0aee41eda55cb92d51eb7802 android.hardware.thermal@1.0::IThermal
+84965a6908bceb4ef51546bf8731f309f1ea9d09a0177dcc7974132e523dd6d2 android.hardware.thermal@1.0::types
+938850621c3c5ef426a4b88e752ba99b3559037e782a3d938604f3aef5cc0f1b android.hardware.tv.cec@1.0::IHdmiCec
+e75b6eea711d36fac678bce072b3cec6544b27fa9f4cd903999404e5c110ca10 android.hardware.tv.cec@1.0::IHdmiCecCallback
+6e25f8dbfadb668e1d4ec80eb9acd95d8bc9e0a240c36d27e662adb440314b95 android.hardware.tv.cec@1.0::types
+0cafa3c8388e9631916d2d800f78decbcec2904f11415b32c71a31d9a51ebf79 android.hardware.tv.input@1.0::ITvInput
+dee83e5c864fbbee8f02448d0800be32f06856386b9f907bc5d952208c9434f9 android.hardware.tv.input@1.0::ITvInputCallback
+07aab30410b612381234dca6d453d4ab96f2e536368715717c6e28101b9851b5 android.hardware.tv.input@1.0::types
+4ef57499273f38bdbdd0c15e56ee7a4bc5f18a5644092170a531df3541d9e015 android.hardware.usb@1.0::IUsb
+4be7881e411ba42784bf5b7354c14ae0cf161004d39433aaecaab0d19ea99354 android.hardware.usb@1.0::IUsbCallback
+f7e6e747910a3cd0a35846141e3b990a6a612a297b2b70ccd5740b646a450a8c android.hardware.usb@1.0::types
+06ea64cc3565777f3b259e400ffa7100d07f3827ad9357b0c5d3c651384e5553 android.hardware.vibrator@1.0::IVibrator
+0fecd34ae64f32eff6aa615fd662349242c0b8b6e303ef05a7cb5776c732f413 android.hardware.vibrator@1.0::types
+4b962968a7df4ab104d1315d66a0a7348a713fecbb5d2c1b23688494458f37ce android.hardware.vr@1.0::IVr
+b9be36719a8ad534000a51ea07be91be94c405bf1e038ae825acf65087ffd378 android.hardware.wifi@1.0::IWifi
+ee0224ee18813506d9d6f13d8c8e4679f053c290a443a52a7c52a5d3c852262b android.hardware.wifi@1.0::IWifiApIface
+f3eecc489deb4c74892f59eb7adb769063bd5c354ac132b626a5f42b363d36bc android.hardware.wifi@1.0::IWifiChip
+a1b988377645a58e5e2542ca2bad4e17c21a4a389213d05de2f0e32d57b7d339 android.hardware.wifi@1.0::IWifiChipEventCallback
+5ed6760ce77e84bc6c49d1acb3f7d8117c9176b3f06514bc44ad3af84c80dcfe android.hardware.wifi@1.0::IWifiEventCallback
+6b9ad43a5efbe6ca214f751e22ce43cf5cd4d5d5f2cba80f24ccd3755a72401c android.hardware.wifi@1.0::IWifiIface
+ba5aa74f1ba714f0093864227923492808795bda6199c4ea0891322d27f8c931 android.hardware.wifi@1.0::IWifiNanIface
+325c94f3e1a565b56bbc74faddbd0ba7cb824f263dccf9dfff2daf62b86ed774 android.hardware.wifi@1.0::IWifiNanIfaceEventCallback
+c2c3f0372b41780fb6dfe83c022296806c2024d7046682fd201de5aa9b791c7a android.hardware.wifi@1.0::IWifiP2pIface
+766e9765f5c9c759b2a763c2288353fb5deff3389c2cc28f81d79c939704ce8b android.hardware.wifi@1.0::IWifiRttController
+72ab6f3e120cbf07aa6f8e87ca89112bdeb36b7fbb96bce5af3712323ab8b8e6 android.hardware.wifi@1.0::IWifiRttControllerEventCallback
+3b8093d39ef1e10e43c5538afbf5ff6e39b8d8168ebbe1998d993e89e25f14a5 android.hardware.wifi@1.0::IWifiStaIface
+7fbfc551c3e23c8b4398c3e16e452b516457e6921424a53474cbf373ca306fa9 android.hardware.wifi@1.0::IWifiStaIfaceEventCallback
+e20d5132d6d23e072c15de065b5e2aa13ff965031246a2c82581732bae56bf6d android.hardware.wifi@1.0::types
+f7e55c08187d8c855068a1ee3d0c8daeee7570292d96509c21a8756d4f5cfb9b android.hardware.wifi.supplicant@1.0::ISupplicant
+56b5c7267cb3d3337f44eb8b0b38ff4c6260dcc70e07687fcab94b1ccea8d159 android.hardware.wifi.supplicant@1.0::ISupplicantCallback
+35ba7bcdf18f24a866a7e5429548f06768bb20a257f75b10a397c4d825ef8438 android.hardware.wifi.supplicant@1.0::ISupplicantIface
+cda01008c06922fa37c1213e9bb831a109b3174532805616fb7161edc403866f android.hardware.wifi.supplicant@1.0::ISupplicantNetwork
+4907410338c5e8dbeec4b5edc2608ea323f5561945f8810af81810c47b019184 android.hardware.wifi.supplicant@1.0::ISupplicantP2pIface
+8b63f5efa2e3be3a7cb8a428760d82285a4ab79bcbdea6ef90aa547555e582d4 android.hardware.wifi.supplicant@1.0::ISupplicantP2pIfaceCallback
+56128f74560571b6777d59453f35c6b35693ee377e2a23c807708906928f09de android.hardware.wifi.supplicant@1.0::ISupplicantP2pNetwork
+2067c22197bca9743dab66a6f561a8a8375c67b4f76aed05f776839499bd4c8f android.hardware.wifi.supplicant@1.0::ISupplicantP2pNetworkCallback
+7752e1de93aaf5fed37011c219ac247069f6af320b0810daa98510584a10e7b4 android.hardware.wifi.supplicant@1.0::ISupplicantStaIface
+d781c8d7e7b3fe5cca8cf6e1d8806e770982ae5358c7816ed51b0f0ec272e70d android.hardware.wifi.supplicant@1.0::ISupplicantStaIfaceCallback
+b12ef0bdd8a4d247a8a6e960b227ed32383f2b0241f55d67fcea6eff6a6737fa android.hardware.wifi.supplicant@1.0::ISupplicantStaNetwork
+d8f0877ae1d321c1d884c7631dfe36cab0ec8a4b2863d4b687f85d3549a63bcc android.hardware.wifi.supplicant@1.0::ISupplicantStaNetworkCallback
+fe3c3c2f572b72f15f8594c538b0577bd5c28722c31879cfe6231330cddb6747 android.hardware.wifi.supplicant@1.0::types
+
+# ABI preserving changes to HALs during Android O MR1 (Initial Set)
+
+# android.hardware.automotive.* are unfrozen
+150a338ce11fcec70757c9675d83cf6a5d7b40d0c812741b91671fecce59eac9 android.hardware.broadcastradio@1.0::types
+dc7e6d4f537b9943e27edc4f86c5a03bb643b18f18f866f8c3c71c0ac4ea8cbc android.hardware.broadcastradio@1.0::types
+760485232f6cce07f8bb05e3475509956996b702f77415ee5bff05e2ec5a5bcc android.hardware.dumpstate@1.0::IDumpstateDevice
+e822cb7f4a1bdd45689c5e92ccd19a2201c20b771bd4b2ec1ae627e324591f9d android.hardware.radio@1.0::IRadioResponse
+6e69adb24d7c0b0ca3a54a38c49a5625b161b3f5d5f7d6fda0befdbbfc8e9e06 android.hardware.radio@1.0::IRadioResponse
+28e929b453df3d9f5060af2764e6cdb123ddb893e3e86923c877f6ff7e5f02c9 android.hardware.wifi@1.0::types
+df1d7b27e644bfed0a4f606a8c44d35d45cafce82c7c648494c8a25c7cd4a949 android.hardware.wifi@1.0::types
+
+# HALs released in Android O MR1 (Initial Set)
+
+4b65763663a94a3920134011691f8fbb42ccb7b7795589efddc049a9106047d6 android.hardware.oemlock@1.0::IOemLock
+e02cd3722cb5e8fa51179f5defacb4f7866f903c9c7c51dc01a3148473a71525 android.hardware.oemlock@1.0::types
+224f9d22a367a0016f09b6dc676f53f1446697d9dc747163032329e5da552de5 android.hardware.power@1.1::IPower
+574fd9758b7cab4922c72cc5a9f36d1cd48ffd3425fdd776426653280d3d4138 android.hardware.power@1.1::types
+f79edf50a378a9c9bb737f93f205dab91b4c63ea49723afc6f856c138203ea81 android.hardware.radio@1.1::IRadio
+fcc5c8c88b85a9f63fba67d9e674da466c72a98ca287f343fb5721d098713f86 android.hardware.radio@1.1::IRadioIndication
+50f27e8c7ec009d5d4418b2ce8392b940bbf052ecc1d7251285f332485a5ba4e android.hardware.radio@1.1::IRadioResponse
+be981148c95c0089f3ae92854f0e7ae999d308e927db3e065f12a4fabe07852f android.hardware.radio@1.1::ISap
+d8d6bf7b4d36c04ce587df75953c3f723cfbe71c896c1aa8ab6478eae126723d android.hardware.radio@1.1::types
+d8aae01606bfd34bf2fb9a59cadc016f46f318e56cddb8f15a945c5b3c1222bc android.hardware.tetheroffload.config@1.0::IOffloadConfig
+447b00306bc95a7aafec1d660f6f3e9f76ac8bc0353193435e5579ab833da619 android.hardware.tetheroffload.control@1.0::IOffloadControl
+07658829339d75962016e00ed81b005ad29fca7ac12ad3bc3ccd86b08d94c2d3 android.hardware.tetheroffload.control@1.0::ITetheringOffloadCallback
+0df5b0178af15c53cdce8fcf8ca14035e8e08db4fa76fdc12009ddbe0b53626b android.hardware.tetheroffload.control@1.0::types
+b30ef02ef26ff804e2f6acf1201bc141b59e134e6a0338562284491102cb13e3 android.hardware.usb@1.1::IUsb
+13a580e35af01270a1e9774177c51db51d8672e6139ba00851e654e68a4d7dff android.hardware.usb@1.1::IUsbCallback
+f0ed667288908c08fced570bd1f3c4a0f236aa927938e805f0d9fece525da81e android.hardware.usb@1.1::types
+f95a1e85612f2d0d616eacd2eb63c52d10dfa889f165df57697c30e1f47b4785 android.hardware.vibrator@1.1::IVibrator
+246fb9d9e2b4800aeb0adc3cdbaa15d0321ebab54b7bd1ab87da5b67c7b0b064 android.hardware.vibrator@1.1::types
+9bc43413b80cd0c59a022e93da1448dcb82dd10c6dd31932df4659e4bdcb1368 android.hardware.weaver@1.0::IWeaver
+7728b0393a2ed9796537d4165c7d95407e9d8cb447a647b545fdfe06a28689e7 android.hardware.weaver@1.0::types
+bb7c96762d0aa3ddb874c8815bacdd3cbc8fb87ea2f82b928bc29e24a3593055 android.hardware.wifi.offload@1.0::IOffload
+c3354ab0d381a236c12dc486ad4b6bec28c979d26748b4661f12ede36f392808 android.hardware.wifi.offload@1.0::IOffloadCallback
+b18caefefcc765092412285d776234fcf213b73bdf07ae1b67a5f71b2d2464e3 android.hardware.wifi.offload@1.0::types
+c26473e2e4a00af43e28a0ddf9002e5062a7d0940429e5efb6e5513a8abcb75c android.hardware.wifi@1.1::IWifi
+b056e1defab4071584214584057d0bc73a613081bf1152590549649d4582c13c android.hardware.wifi@1.1::IWifiChip
+
+# ABI preserving changes to HALs during Android O MR1 (Final Set)
+2d833aeed0cd1d59437aca210be590a953cf32bcb6683cd63d089762a643fb49 android.hardware.radio@1.0::IRadioResponse
+05aa3de6130a9788fdb6f4d3cc57c3ea90f067e77a5e09d6a772ec7f6bca33d2 android.hardware.radio@1.1::IRadioResponse
+
+# HALs released in Android O MR1 (Final Set)
+044cb039378b8a0e36f40ff1e6ce04dc0d339da02095f968d5062a051e99d108 android.hardware.broadcastradio@1.1::types
+c9699483f8cefe4f9b39b4b9609b76cab2dd1659a06188056b45797d337d4256 android.hardware.broadcastradio@1.1::IBroadcastRadio
+b5d62dcd663fc4fcc977b252af59b333043bdfe73de2f11fe6d6a8bf438a0f92 android.hardware.broadcastradio@1.1::IBroadcastRadioFactory
+bc7e054a6e93adebedff345aeed44549be89e6b1b6ffe071ff47a61de764b232 android.hardware.broadcastradio@1.1::ITuner
+e9139fc755be578693f17c8cd1e27c75f412cfc722157bab5bf03ee68896e31d android.hardware.broadcastradio@1.1::ITunerCallback
+63929c99e5755d9e09d9e0fd2527391fbb1609dda0508f5933b7943b92ae0fbc android.hardware.camera.device@3.3::types
+bbcfc3f748b078f6a66c4e228084a679d30bd61bfde8bb7a91efd507b91c1bfd android.hardware.camera.device@3.3::ICameraDeviceSession
+4a6998cd6793a3f9f03989c29d662589b1bc9d38826c6698c6c17864f7a814f5 android.hardware.cas@1.0::types
+0e656ba1bac11461a17096ef752b69d24b000d820ef5652f0150a0f9731d54c2 android.hardware.cas@1.0::ICas
+b80e1456b81f80032d0de7cb45652ac15af11e7474d520d757481ecaad796dff android.hardware.cas@1.0::ICasListener
+a432d6d9200248dc2126827bcd6cdea31dd65eff39b939f64585d27d915a5857 android.hardware.cas@1.0::IDescramblerBase
+86ba9c03978b79a742e990420bc5ced0673d25a939f82572996bef92621e2014 android.hardware.cas@1.0::IMediaCasService
+503da837d1a67cbdb7c08a033e927e5430ae1b159d98bf72c6336b4dcc5e76f5 android.hardware.cas.native@1.0::types
+619600109232ed64b827c8a11beed8070b1827ae464547d7aa146cf0473b4bca android.hardware.cas.native@1.0::IDescrambler
+0a159f81359cd4f71bbe00972ee8403ea79351fb7c0cd48be72ebb3e424dbaef android.hardware.radio@1.0::types
+09342041e17c429fce0034b9096d17849122111436a5f0053e7e59500e1cb89c android.hardware.media.omx@1.0::IOmxStore
+246a56d37d57a47224562c9d077b4a2886ce6242b9311bd98a17325944c280d7 android.hardware.neuralnetworks@1.0::types
+93eb3757ceaf21590fa4cd1d4a7dfe3b3794af5396100a6d25630879352abce9 android.hardware.neuralnetworks@1.0::IDevice
+f66f9a38541bf92001d3adcce678cd7e3da2262124befb460b1c9aea9492813b android.hardware.neuralnetworks@1.0::IExecutionCallback
+953607822954435874f4b81686440a604e2a88cdd2d9164c6293f3d5772510d7 android.hardware.neuralnetworks@1.0::IPreparedModel
+73e03573494ba96f0e711ab7f1956c5b2d54c3da690cd7ecf4d6d0f287447730 android.hardware.neuralnetworks@1.0::IPreparedModelCallback
+f4945e397b5dea41bb64518dfde59be71245d8a125fd1e0acffeb57ac7b08fed android.hardware.thermal@1.1::IThermal
+c8bc853546dd55584611def2a9fa1d99f657e3366c976d2f60fe6b8aa6d2cb87 android.hardware.thermal@1.1::IThermalCallback
diff --git a/prebuilt_hashes/28.txt b/prebuilt_hashes/28.txt
new file mode 100644
index 0000000..cc15322
--- /dev/null
+++ b/prebuilt_hashes/28.txt
@@ -0,0 +1,382 @@
+# Do not change this file except to add new interfaces. Changing
+# pre-existing interfaces will fail VTS and break framework-only OTAs
+
+# HALs released in Android O
+
+f219c3b5b8c6cb1d659d4c7328f67246abfe1a8613f469826fd3b9ad090417a2 android.hardware.audio@2.0::IDevice
+4d579cae1cd87a783fd49233e10ce720ba183cfd1d5ccd80149e69de5c1c7362 android.hardware.audio@2.0::IDevicesFactory
+203e23f18011390b8cd10c303e0c16c4eebc8fa187e80e40d6be4624c2b0848a android.hardware.audio@2.0::IPrimaryDevice
+aaf93123deec336eb247ad8099849469a541ca0cf7c28c5f5336cebe1ee86748 android.hardware.audio@2.0::IStream
+0468c5723b0d44c5b451bdfa06153000c6f352fd3336e0ad2697127b04b766df android.hardware.audio@2.0::IStreamIn
+7296f7064fd3ab24082b43a1da34cc876268065310b785499fba5178d063680a android.hardware.audio@2.0::IStreamOut
+19d241d71c3e1140afba8140dcb57448446025a5fc03739788c4c25e9a98b6c2 android.hardware.audio@2.0::IStreamOutCallback
+c84da9f586087227daa3b96d42b4575326bccfd5bc8a2a5acf86d774f8ea2648 android.hardware.audio@2.0::types
+1305786c06e22b9b24ebde136054cc827b63c86d8bf4a136d6f7f54752b8566b android.hardware.audio.common@2.0::types
+fa8fbae3d1da3c264e4f3110728076abc09b4e65f12af6ae136367328de988ab android.hardware.audio.effect@2.0::IAcousticEchoCancelerEffect
+ca4752545d54547ff069eae161af7550cb5f5a7e8b60316ddd132a30906a68e7 android.hardware.audio.effect@2.0::IAutomaticGainControlEffect
+d2b8af988dc66f514d886bcee44b440d8034bc2a762f7161717ef3c956073067 android.hardware.audio.effect@2.0::IBassBoostEffect
+611bc09c75e796f3512b1ca6be508b0a9ba996759b8a2c60507784ff58076229 android.hardware.audio.effect@2.0::IDownmixEffect
+36a57369dfdc75180e8b64ae80b1970db8f6d9085dbff6ca931715038cc056e1 android.hardware.audio.effect@2.0::IEffect
+d2aa2df6d189c580f5be8460fa0ff4134d9c05a383f3204659baee426a6f0edf android.hardware.audio.effect@2.0::IEffectBufferProviderCallback
+217f9161983a48d3bf3faeb158f868aa8bf0ce25889e4ee3d2bab1a2e8d33e77 android.hardware.audio.effect@2.0::IEffectsFactory
+c2b38bc07991e880c83ca8cb88181411eeef708b8b936aedd2f2e0acade7df69 android.hardware.audio.effect@2.0::IEnvironmentalReverbEffect
+2ff9f9704be5f167745b4de790e9dafc3cc4719e2f6e2e5497085e679853cfe7 android.hardware.audio.effect@2.0::IEqualizerEffect
+c31447fb02dbc8b56c359941dad22f416511860173c5c5fd278d1bf2312b13de android.hardware.audio.effect@2.0::ILoudnessEnhancerEffect
+804831ca258802eb3eb65a0a7b5d5e3d37d4a15ba8c2836b4276eda98b47e1d0 android.hardware.audio.effect@2.0::INoiseSuppressionEffect
+778fd5b9837f481d8e47425b3e2a3bd0c6362a0b6870291518e2d863530fdb61 android.hardware.audio.effect@2.0::IPresetReverbEffect
+c93cb25a1a92d07aa80a617c01e8d22fc97bf8cefd3962b6a5be386ad4704d89 android.hardware.audio.effect@2.0::IVirtualizerEffect
+918f331780c9c7b04f2151a2e563aab088198ede8e6f865302ebaa13905bd9ce android.hardware.audio.effect@2.0::IVisualizerEffect
+4caad099f8fc00262b6c03ba41271808b37cea90ac98b534299bbf4ee823af02 android.hardware.audio.effect@2.0::types
+1fbdc1f852f8bd2e4a6c5cb30ac2b78668c98dce118a61762d4034ae859f43d8 android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint
+aabb5c3c585592d71ee57b77298c14993d77914ddeaa64b2c5109a602b02ea47 android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprintClientCallback
+1ec60d4efddae9a7b2469278a576967b4751e88de5b8d7e9df6eff6bc0da7bc9 android.hardware.biometrics.fingerprint@2.1::types
+347ce746815607567f5f3b53e4800998ca5ab9355141f0880fc0cf0c1fc5c355 android.hardware.bluetooth@1.0::IBluetoothHci
+835f41be2281bfb22f3e33c6fa870bde7bc21e37e5cfbaf9a36fff170632f754 android.hardware.bluetooth@1.0::IBluetoothHciCallbacks
+a8dfd0dbe463a3cdbcf1d985b38a28b3d93ba2ae5a1d1db4aaef4c38a5781b91 android.hardware.bluetooth@1.0::types
+7192d756aeba00aba32f4504981df8172ffca83e210c4838dabf295e53e93590 android.hardware.boot@1.0::IBootControl
+cebaa803b8e33807a0d69f46652b650ccb549e8f9b19d6becbbf26690e828b49 android.hardware.boot@1.0::types
+a98d49f23712a7cc327d1e0602d05f6f3ad32cfb5c74711d009c726611ee1c93 android.hardware.broadcastradio@1.0::IBroadcastRadio
+ed82579c0c165feaa12d0e33c06b3342ab41ec0a439247f202775e8369e46ef6 android.hardware.broadcastradio@1.0::IBroadcastRadioFactory
+da6ab32ee2793d2c86d3b603075d5383852b89d7eaa201861aa0473d418f3c7f android.hardware.broadcastradio@1.0::ITuner
+04d3ca022e25c308d9efd2e7eb77b3a7a206907cdc1b9ea9326340b377868172 android.hardware.broadcastradio@1.0::ITunerCallback
+bd42c8d7838cfed1998b49c39745dec116d2d6edc2c11a4c0399b8f3a1d1655a android.hardware.broadcastradio@1.0::types
+81164323115d6588e259e8319fddf7487adfa1f49ce60f7e80ba74e0783392a4 android.hardware.camera.common@1.0::types
+c1705e9d62438a1d955269965af915ae28e692bd480a3b1ce67056fef992d62f android.hardware.camera.device@1.0::ICameraDevice
+78e9b44cf8660bdc1e98dca07451804153824efcd28db208a62f5ad728f44076 android.hardware.camera.device@1.0::ICameraDeviceCallback
+28f0386ba86ddf41e53a8117b48a0328d7a4d2574213e89f4a1062398a244566 android.hardware.camera.device@1.0::ICameraDevicePreviewCallback
+4db48439ce9dde97f1cfb3d7408f6c737f621ac0f7494aeea35ed599bc2352a3 android.hardware.camera.device@1.0::types
+b32f9aeaf1c442195eb06ffc7600968c919d005b2718874f09c57287fae55918 android.hardware.camera.device@3.2::ICameraDevice
+63bfc3da0f2d2301f7a0508c7c2b9ffc521d4d545ee03718da70e9d6273b3b21 android.hardware.camera.device@3.2::ICameraDeviceCallback
+0fa3e1e64819283b8737fc4e5ab759f0cb4ac1a996e8a51cc4aa8025a457208e android.hardware.camera.device@3.2::ICameraDeviceSession
+030be3d2b159cbde7920485807140f6b6064ef4a5de4a40a6c4bc8d2c72f7cd3 android.hardware.camera.device@3.2::types
+5ba7947cee515d7a2359bfcbfb9678c1c3a768c288471919ac095b96ae6f3d40 android.hardware.camera.metadata@3.2::types
+f7e299d85033ac52d1095a35784fcfeaff43603f58c751e4153c85bbade3b330 android.hardware.camera.provider@2.4::ICameraProvider
+a501ca1aecd09f1b9fd70a9af84205430dbd49a808e8fa395d363b9902e6f58c android.hardware.camera.provider@2.4::ICameraProviderCallback
+7f5fe8f4f8a24037153c504d8b4d3313c2ce33d81c8c69fe5194ddd2d4080e72 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
+87beacc481897cf02fb1628d75e68133de6d74d4cffe582cda2f5e16bdd74516 android.hardware.configstore@1.0::types
+a5ae0fe8667f0b1af09b13e72d29600f4eb3853b257079c45a99b6f4a3360649 android.hardware.contexthub@1.0::IContexthub
+2ab3054c2d9302d8417ee7495353a2887fe338f913276f2eb41e80f11395ec2e android.hardware.contexthub@1.0::IContexthubCallback
+c3b2b37d561d31ea094411f251bf73bea334f4fe849a4390aef5e20bca6cadba android.hardware.contexthub@1.0::types
+df174c1871c864b4c79ca9f64aae7936d24a272eca3191a30458ca2b706dec79 android.hardware.drm@1.0::ICryptoFactory
+83639e90caeb996b0274e420de3cd556779de1ca48464b68eee799bef32b34cd android.hardware.drm@1.0::ICryptoPlugin
+1440cffdfaeb12830ac10ee6ffdb0f1083e701057b806df11fb4787b4c91e718 android.hardware.drm@1.0::IDrmFactory
+78ba33b108f620e6a0eec01ef654547e69a85754578ea4c9ef03ec205f16121c android.hardware.drm@1.0::IDrmPlugin
+701d9e51952172364e4ea70db9c397f08c3b4577ba33051f050a6cdd532de1b4 android.hardware.drm@1.0::IDrmPluginListener
+4238d62ad90df63aa338c6f1b6264c09c5a3706945d5c49d1189c0be1dc9e942 android.hardware.drm@1.0::types
+f07b1ee3ba11a2fc9f200421b2e1afb7c1854ee987000e45c987fb9507795055 android.hardware.dumpstate@1.0::IDumpstateDevice
+c9d318df7922bde3b265927b521ff5a965002826fc0cabfcaef52a56760f2d34 android.hardware.gatekeeper@1.0::IGatekeeper
+da13bd69282fb275767abb18704c57ff8038e6c139ad17157dc702810f70d06a android.hardware.gatekeeper@1.0::types
+37c7da4f823ec958dfa9c960e2d341c48f877e0bfa758f3fa9e2d9c1e1bd66d9 android.hardware.gnss@1.0::IAGnss
+7ec9afdb964bfb8369866913caf018f2636592885bcb558a65de2c5436ab4f60 android.hardware.gnss@1.0::IAGnssCallback
+d16e6a359be6963ea753d7138e84ecf2b93052097938938c4d36d7a47ea2e2ae android.hardware.gnss@1.0::IAGnssRil
+2f907708d74d94b1e121ed27651c9c72af65952d347b58ff07dac5d5d7a7f678 android.hardware.gnss@1.0::IAGnssRilCallback
+5ac7edad06d76064b882be161f3f9d9692a997ec72e9f36addb7fe8918f49992 android.hardware.gnss@1.0::IGnss
+b05c983c87c3376e145223688c3b541b5e11b827f211e38d5a31af1ca3a2e222 android.hardware.gnss@1.0::IGnssBatching
+4981d2d2c4e725c7544be0956099a91fc7bbc8048c563394158083fe924e651e android.hardware.gnss@1.0::IGnssBatchingCallback
+3cd22d92cc1f935150c5048310e84886f14eed2556e8f00636733d204045cc4f android.hardware.gnss@1.0::IGnssCallback
+175185a5eda87476193ca5461df75dd16d36664591e8130530dd8ef0eb2ddf6a android.hardware.gnss@1.0::IGnssConfiguration
+4542122b96fbf27101cb8222bafb76e7c8d032d977dd1058edd8e5881ca5752f android.hardware.gnss@1.0::IGnssDebug
+e6dd0c8416e523ab9cbd14d56ab6f016481a8aef3bc8a750051122d31075f6c7 android.hardware.gnss@1.0::IGnssGeofenceCallback
+f90e4ddc652706299d8e3d8ba18e0745c3bae9bf4d1be6bd06d9c1f50ec8d28a android.hardware.gnss@1.0::IGnssGeofencing
+9ea8987bb1089c8c5d7b67866575b866ef516045021d9efcc37c6352bce072a3 android.hardware.gnss@1.0::IGnssMeasurement
+cf20492673d6a423e4c2e87fdfb5a4c4a602431721978db852e246f258e25edb android.hardware.gnss@1.0::IGnssMeasurementCallback
+af85aa0f48ae99a39f4688c344e4419304f681f9af818a5c8d759286fc4418de android.hardware.gnss@1.0::IGnssNavigationMessage
+76b0874ea4c06b29f66418c59820f4286b3be9629cd872923d0dfbb602cd432d android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+248bcf51da4273d64f367bf6877baef2feeaca365459842fd3c214a2dc6e0224 android.hardware.gnss@1.0::IGnssNi
+c781b7b125f68be5db8a8c3d412d526acdbdf77dcc592a4c0ed70b8ce4fe6c49 android.hardware.gnss@1.0::IGnssNiCallback
+c1142657de16fdb292a502372fe938614d65270ab8359217d6e13604fe4dbca4 android.hardware.gnss@1.0::IGnssXtra
+bd366b83d8d565d0e8bfabff3adfcab0259d75b4e2a9f8e1b91e11d1593a2ffb android.hardware.gnss@1.0::IGnssXtraCallback
+881bc2f94026784d194cffbff166c6e8bf911de4e02abe96fc7d89ec75b0574a android.hardware.gnss@1.0::types
+17971eb8a482893dadcfc16e0583f492d42a034ef95d9b0b709417af30838396 android.hardware.graphics.allocator@2.0::IAllocator
+60bf42a4898e4fb70dbd720b263aeafd7f35f5e1a5effeabb4d5d659878a5f18 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer
+b8a75617b9ec12bea641f3a73d4025a33e8b9a2f9169dd46094af56adf9249c5 android.hardware.graphics.bufferqueue@1.0::IProducerListener
+4f6dedbcdd21c309dfc650acea81a096d6b242493ffe49c8d61bd3c43aad354e android.hardware.graphics.common@1.0::types
+b3aac6c3817f039964fcd62268274b3039e17bd7d0d5b40b4d1d1c7b19a1f866 android.hardware.graphics.composer@2.1::IComposer
+b19d00eb8a8b3b0034a0321f22e8f32162bf4c2aebbce6da22c025f56e459ea2 android.hardware.graphics.composer@2.1::IComposerCallback
+61ee43ffe6fb6dbe8b22dc17c51ff3d5ba703fc6029cba211f901f3d79c8a72d android.hardware.graphics.composer@2.1::IComposerClient
+1c98c2f5154345312ec054871792a2982ec5f3e2bc2abfb61a10c0b517978e20 android.hardware.graphics.composer@2.1::types
+a695898589e1ef15b2b2510f11edd6aafac9918d9cf8d74b4b6143b309dee542 android.hardware.graphics.mapper@2.0::IMapper
+28507d385a3dd224bf3c32f1bfd9f96092c4701b9c1cc66caa578fc3efc97877 android.hardware.graphics.mapper@2.0::types
+91e2ba3805c923f01fc1231ec9ff838942aee3346f2d7614ecc0caeadbe57ed4 android.hardware.health@1.0::IHealth
+1275aa2e8732909101b26aec49ed2285489e89d97b8610a8908b7868e35a3cc5 android.hardware.health@1.0::types
+3a8d3922e06e6d4f8e0befc6be78d0e9e07aed1585b3da6521bed406d25a9483 android.hardware.ir@1.0::IConsumerIr
+7090bd37912fcf723a12f4bc17783e3527577c4944805a028c296fd7a95bd682 android.hardware.ir@1.0::types
+cc7925a78c0ab022515f48840d3dae76f384ed3a1287abadcb461a5cd5396163 android.hardware.keymaster@3.0::IKeymasterDevice
+822998d7bb76f0cd719a409291434fcb56e6d50bc4780788bb157a3374d63b8c android.hardware.keymaster@3.0::types
+d4ed2f0e14f9e914d0b1275d2e0363192fe30aca9059c84edb5fad15995f9ec4 android.hardware.light@2.0::ILight
+d9584bfcaedd6e62cf337881748246b23e36cbc2bc3aa84c01b6a1e622061400 android.hardware.light@2.0::types
+16c0cf0f73de1e5208a95020c6c6474903e7094f76b2d782651afaca0e5fd86f android.hardware.media@1.0::types
+8bc2f5fdcad68856eb61a62fe4cc043fa064bb7f1dab95a71d1918ec1eef7b55 android.hardware.media.omx@1.0::IGraphicBufferSource
+0d3de9cd89d4718ea3b772f2d8b93be004feb3abb7e7dc5402e37047cc730d05 android.hardware.media.omx@1.0::IOmx
+32002e1c358c64de106c977a6dc6af7da27be4803a5bb66fd6f891a5ba0a1617 android.hardware.media.omx@1.0::IOmxBufferSource
+81ad8d8bb1cf6f41923cf11dd39354a8fe433db284a234cc675de7e75a82224c android.hardware.media.omx@1.0::IOmxNode
+494c0c8bf6065edc82ec127228ed19dd2243dc1c2f7d601c7c6be7b7015c1713 android.hardware.media.omx@1.0::IOmxObserver
+252c2fc50c78fd6de8365e5b60e5115119ace107db0b94b0b26815cbf3d2b64a android.hardware.media.omx@1.0::IOmxStore
+148c1b50b0958988373145ffdf5fa0e1b6534e0a2034a570e74b15c127cf7c5e android.hardware.media.omx@1.0::types
+c66902fe48d687ac6740a3e32ae55fb75532c48c36c6386461c2b4416ad2e0f1 android.hardware.memtrack@1.0::IMemtrack
+860bacd8b11a269c40567542b613fe4ca448d5cb4326d0058899e608e89dfca1 android.hardware.memtrack@1.0::types
+07ac2dc95270321ec7d4c33cd25e5085a057f47fe350d645af6f7a7a11e3cf57 android.hardware.nfc@1.0::INfc
+f2fe54426c07d67388d4774a60641ad4c0538f22eb6e1111722f231772655de6 android.hardware.nfc@1.0::INfcClientCallback
+9626fd18db113d709faf593a70caf19bd0980294d23c468c80c30186f9d298a6 android.hardware.nfc@1.0::types
+deee1dc4948f33af207e1008aba0f6cc07afb7900eab53f33192c8cac137eefc android.hardware.power@1.0::IPower
+efc83df3f962b93c7c0290d691d7d300dabe12683e2cde3591fb3c0beedce20f android.hardware.power@1.0::types
+9b5aa499ec3b4226f15f48f5ed08896e2fc0676f978c9e199c1da21daaf002a6 android.hardware.radio@1.0::IRadio
+5c8efbb9c451a59737ed2c6c20230aae4745839ca01d8088d6dcc9020e52d2c5 android.hardware.radio@1.0::IRadioIndication
+69f6b4b8ec40ca02ccc7bb8227a097135c20c00bd94c822e421cd9af1267252c android.hardware.radio@1.0::IRadioResponse
+de3ab9f73b1073cd677b19d886fb927e9381b30161a704712d2b30f875873f5c android.hardware.radio@1.0::ISap
+d183e406ef0897df2117a9dde384e8e6ea4fa6ab1c7f6f28e65b87011218c9ea android.hardware.radio@1.0::ISapCallback
+96986fbd22f0e6ca752e1fcdc0a64bda213995a81f5f36bc4faf3532d9306b97 android.hardware.radio@1.0::types
+00f70085d6fae1d482fb700a3fd42ed475384c95b51c9269b9ae5037b74ad4dd android.hardware.radio.deprecated@1.0::IOemHook
+06837b6d7e843cfa9cd20fed4070feca7a9b5c81a9ed643bf7d06803455a9816 android.hardware.radio.deprecated@1.0::IOemHookIndication
+6fd4874f0eddd4626a27658fd94fad526c317f3563439e79718bdb1a3a2309d5 android.hardware.radio.deprecated@1.0::IOemHookResponse
+6983a2cafe39d5c57dfdc1743055fb0f757a0df8c78e00423d5e1810836927e1 android.hardware.renderscript@1.0::IContext
+7f9417a0ccf78ea042ec7a8ac8e3750346d4d9d7e5ae01b1b35fde303f47c24d android.hardware.renderscript@1.0::IDevice
+fc6f325b266b32353f7d1534fbe58e0d368265a12b77fa396fb556e8c443f739 android.hardware.renderscript@1.0::types
+89585ff541c319de4091a5a0b687dd526ac81c6382ffd7b979a4164b3d7419a6 android.hardware.sensors@1.0::ISensors
+e04ab978fc28f4c515f4a75617dfda8607733a64f13666beeb0e604a07a39333 android.hardware.sensors@1.0::types
+5befc019cbe94953661e2cdb95e3cf64f5e565c29403e1c2daecc2be44e0a55c android.hardware.soundtrigger@2.0::ISoundTriggerHw
+d7ec5f612a5e0a59ea4f2b61317e208ff56dd50920fd4eb441e0cbc8f97e4f49 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
+5bee9e70f7e5ec7ee252883b28f98f12b59960f4c2a0b4cc9a4526e4669ebcd4 android.hardware.soundtrigger@2.0::types
+97f1ec446043bc5a6645b74529a6276496bdb35e0aee41eda55cb92d51eb7802 android.hardware.thermal@1.0::IThermal
+84965a6908bceb4ef51546bf8731f309f1ea9d09a0177dcc7974132e523dd6d2 android.hardware.thermal@1.0::types
+938850621c3c5ef426a4b88e752ba99b3559037e782a3d938604f3aef5cc0f1b android.hardware.tv.cec@1.0::IHdmiCec
+e75b6eea711d36fac678bce072b3cec6544b27fa9f4cd903999404e5c110ca10 android.hardware.tv.cec@1.0::IHdmiCecCallback
+6e25f8dbfadb668e1d4ec80eb9acd95d8bc9e0a240c36d27e662adb440314b95 android.hardware.tv.cec@1.0::types
+0cafa3c8388e9631916d2d800f78decbcec2904f11415b32c71a31d9a51ebf79 android.hardware.tv.input@1.0::ITvInput
+dee83e5c864fbbee8f02448d0800be32f06856386b9f907bc5d952208c9434f9 android.hardware.tv.input@1.0::ITvInputCallback
+07aab30410b612381234dca6d453d4ab96f2e536368715717c6e28101b9851b5 android.hardware.tv.input@1.0::types
+4ef57499273f38bdbdd0c15e56ee7a4bc5f18a5644092170a531df3541d9e015 android.hardware.usb@1.0::IUsb
+4be7881e411ba42784bf5b7354c14ae0cf161004d39433aaecaab0d19ea99354 android.hardware.usb@1.0::IUsbCallback
+f7e6e747910a3cd0a35846141e3b990a6a612a297b2b70ccd5740b646a450a8c android.hardware.usb@1.0::types
+06ea64cc3565777f3b259e400ffa7100d07f3827ad9357b0c5d3c651384e5553 android.hardware.vibrator@1.0::IVibrator
+0fecd34ae64f32eff6aa615fd662349242c0b8b6e303ef05a7cb5776c732f413 android.hardware.vibrator@1.0::types
+4b962968a7df4ab104d1315d66a0a7348a713fecbb5d2c1b23688494458f37ce android.hardware.vr@1.0::IVr
+b9be36719a8ad534000a51ea07be91be94c405bf1e038ae825acf65087ffd378 android.hardware.wifi@1.0::IWifi
+ee0224ee18813506d9d6f13d8c8e4679f053c290a443a52a7c52a5d3c852262b android.hardware.wifi@1.0::IWifiApIface
+f3eecc489deb4c74892f59eb7adb769063bd5c354ac132b626a5f42b363d36bc android.hardware.wifi@1.0::IWifiChip
+a1b988377645a58e5e2542ca2bad4e17c21a4a389213d05de2f0e32d57b7d339 android.hardware.wifi@1.0::IWifiChipEventCallback
+5ed6760ce77e84bc6c49d1acb3f7d8117c9176b3f06514bc44ad3af84c80dcfe android.hardware.wifi@1.0::IWifiEventCallback
+6b9ad43a5efbe6ca214f751e22ce43cf5cd4d5d5f2cba80f24ccd3755a72401c android.hardware.wifi@1.0::IWifiIface
+ba5aa74f1ba714f0093864227923492808795bda6199c4ea0891322d27f8c931 android.hardware.wifi@1.0::IWifiNanIface
+325c94f3e1a565b56bbc74faddbd0ba7cb824f263dccf9dfff2daf62b86ed774 android.hardware.wifi@1.0::IWifiNanIfaceEventCallback
+c2c3f0372b41780fb6dfe83c022296806c2024d7046682fd201de5aa9b791c7a android.hardware.wifi@1.0::IWifiP2pIface
+766e9765f5c9c759b2a763c2288353fb5deff3389c2cc28f81d79c939704ce8b android.hardware.wifi@1.0::IWifiRttController
+72ab6f3e120cbf07aa6f8e87ca89112bdeb36b7fbb96bce5af3712323ab8b8e6 android.hardware.wifi@1.0::IWifiRttControllerEventCallback
+3b8093d39ef1e10e43c5538afbf5ff6e39b8d8168ebbe1998d993e89e25f14a5 android.hardware.wifi@1.0::IWifiStaIface
+7fbfc551c3e23c8b4398c3e16e452b516457e6921424a53474cbf373ca306fa9 android.hardware.wifi@1.0::IWifiStaIfaceEventCallback
+e20d5132d6d23e072c15de065b5e2aa13ff965031246a2c82581732bae56bf6d android.hardware.wifi@1.0::types
+f7e55c08187d8c855068a1ee3d0c8daeee7570292d96509c21a8756d4f5cfb9b android.hardware.wifi.supplicant@1.0::ISupplicant
+56b5c7267cb3d3337f44eb8b0b38ff4c6260dcc70e07687fcab94b1ccea8d159 android.hardware.wifi.supplicant@1.0::ISupplicantCallback
+35ba7bcdf18f24a866a7e5429548f06768bb20a257f75b10a397c4d825ef8438 android.hardware.wifi.supplicant@1.0::ISupplicantIface
+cda01008c06922fa37c1213e9bb831a109b3174532805616fb7161edc403866f android.hardware.wifi.supplicant@1.0::ISupplicantNetwork
+4907410338c5e8dbeec4b5edc2608ea323f5561945f8810af81810c47b019184 android.hardware.wifi.supplicant@1.0::ISupplicantP2pIface
+8b63f5efa2e3be3a7cb8a428760d82285a4ab79bcbdea6ef90aa547555e582d4 android.hardware.wifi.supplicant@1.0::ISupplicantP2pIfaceCallback
+56128f74560571b6777d59453f35c6b35693ee377e2a23c807708906928f09de android.hardware.wifi.supplicant@1.0::ISupplicantP2pNetwork
+2067c22197bca9743dab66a6f561a8a8375c67b4f76aed05f776839499bd4c8f android.hardware.wifi.supplicant@1.0::ISupplicantP2pNetworkCallback
+7752e1de93aaf5fed37011c219ac247069f6af320b0810daa98510584a10e7b4 android.hardware.wifi.supplicant@1.0::ISupplicantStaIface
+d781c8d7e7b3fe5cca8cf6e1d8806e770982ae5358c7816ed51b0f0ec272e70d android.hardware.wifi.supplicant@1.0::ISupplicantStaIfaceCallback
+b12ef0bdd8a4d247a8a6e960b227ed32383f2b0241f55d67fcea6eff6a6737fa android.hardware.wifi.supplicant@1.0::ISupplicantStaNetwork
+d8f0877ae1d321c1d884c7631dfe36cab0ec8a4b2863d4b687f85d3549a63bcc android.hardware.wifi.supplicant@1.0::ISupplicantStaNetworkCallback
+fe3c3c2f572b72f15f8594c538b0577bd5c28722c31879cfe6231330cddb6747 android.hardware.wifi.supplicant@1.0::types
+
+# ABI preserving changes to HALs during Android O MR1 (Initial Set)
+
+150a338ce11fcec70757c9675d83cf6a5d7b40d0c812741b91671fecce59eac9 android.hardware.broadcastradio@1.0::types
+dc7e6d4f537b9943e27edc4f86c5a03bb643b18f18f866f8c3c71c0ac4ea8cbc android.hardware.broadcastradio@1.0::types
+760485232f6cce07f8bb05e3475509956996b702f77415ee5bff05e2ec5a5bcc android.hardware.dumpstate@1.0::IDumpstateDevice
+78589343d8ee2e1b155acad3fbdc7fcbb6af94491aee968b2383c21627264f8b android.hardware.radio@1.0::IRadioResponse # Available in Android O, b/68061860
+e822cb7f4a1bdd45689c5e92ccd19a2201c20b771bd4b2ec1ae627e324591f9d android.hardware.radio@1.0::IRadioResponse
+6e69adb24d7c0b0ca3a54a38c49a5625b161b3f5d5f7d6fda0befdbbfc8e9e06 android.hardware.radio@1.0::IRadioResponse
+c2c50ec74c87a583c683b4493f8f9f2e454a8d41c57af5b3eb88823a999f0ea4 android.hardware.radio@1.0::IRadioResponse # Added for b/65230472 for Android O
+4922dd58e89a03181ed1c48a6e118e47633b73b11090bdfed5aa920d25a7592b android.hardware.radio@1.0::IRadioResponse # Added for b/65230472 for Android O DR
+28e929b453df3d9f5060af2764e6cdb123ddb893e3e86923c877f6ff7e5f02c9 android.hardware.wifi@1.0::types
+df1d7b27e644bfed0a4f606a8c44d35d45cafce82c7c648494c8a25c7cd4a949 android.hardware.wifi@1.0::types
+
+# HALs released in Android O MR1 (Initial Set)
+
+4b65763663a94a3920134011691f8fbb42ccb7b7795589efddc049a9106047d6 android.hardware.oemlock@1.0::IOemLock
+e02cd3722cb5e8fa51179f5defacb4f7866f903c9c7c51dc01a3148473a71525 android.hardware.oemlock@1.0::types
+224f9d22a367a0016f09b6dc676f53f1446697d9dc747163032329e5da552de5 android.hardware.power@1.1::IPower
+574fd9758b7cab4922c72cc5a9f36d1cd48ffd3425fdd776426653280d3d4138 android.hardware.power@1.1::types
+f79edf50a378a9c9bb737f93f205dab91b4c63ea49723afc6f856c138203ea81 android.hardware.radio@1.1::IRadio
+fcc5c8c88b85a9f63fba67d9e674da466c72a98ca287f343fb5721d098713f86 android.hardware.radio@1.1::IRadioIndication
+50f27e8c7ec009d5d4418b2ce8392b940bbf052ecc1d7251285f332485a5ba4e android.hardware.radio@1.1::IRadioResponse
+be981148c95c0089f3ae92854f0e7ae999d308e927db3e065f12a4fabe07852f android.hardware.radio@1.1::ISap
+d8d6bf7b4d36c04ce587df75953c3f723cfbe71c896c1aa8ab6478eae126723d android.hardware.radio@1.1::types
+d8aae01606bfd34bf2fb9a59cadc016f46f318e56cddb8f15a945c5b3c1222bc android.hardware.tetheroffload.config@1.0::IOffloadConfig
+447b00306bc95a7aafec1d660f6f3e9f76ac8bc0353193435e5579ab833da619 android.hardware.tetheroffload.control@1.0::IOffloadControl
+07658829339d75962016e00ed81b005ad29fca7ac12ad3bc3ccd86b08d94c2d3 android.hardware.tetheroffload.control@1.0::ITetheringOffloadCallback
+0df5b0178af15c53cdce8fcf8ca14035e8e08db4fa76fdc12009ddbe0b53626b android.hardware.tetheroffload.control@1.0::types
+b30ef02ef26ff804e2f6acf1201bc141b59e134e6a0338562284491102cb13e3 android.hardware.usb@1.1::IUsb
+13a580e35af01270a1e9774177c51db51d8672e6139ba00851e654e68a4d7dff android.hardware.usb@1.1::IUsbCallback
+f0ed667288908c08fced570bd1f3c4a0f236aa927938e805f0d9fece525da81e android.hardware.usb@1.1::types
+f95a1e85612f2d0d616eacd2eb63c52d10dfa889f165df57697c30e1f47b4785 android.hardware.vibrator@1.1::IVibrator
+246fb9d9e2b4800aeb0adc3cdbaa15d0321ebab54b7bd1ab87da5b67c7b0b064 android.hardware.vibrator@1.1::types
+9bc43413b80cd0c59a022e93da1448dcb82dd10c6dd31932df4659e4bdcb1368 android.hardware.weaver@1.0::IWeaver
+7728b0393a2ed9796537d4165c7d95407e9d8cb447a647b545fdfe06a28689e7 android.hardware.weaver@1.0::types
+bb7c96762d0aa3ddb874c8815bacdd3cbc8fb87ea2f82b928bc29e24a3593055 android.hardware.wifi.offload@1.0::IOffload
+c3354ab0d381a236c12dc486ad4b6bec28c979d26748b4661f12ede36f392808 android.hardware.wifi.offload@1.0::IOffloadCallback
+b18caefefcc765092412285d776234fcf213b73bdf07ae1b67a5f71b2d2464e3 android.hardware.wifi.offload@1.0::types
+c26473e2e4a00af43e28a0ddf9002e5062a7d0940429e5efb6e5513a8abcb75c android.hardware.wifi@1.1::IWifi
+b056e1defab4071584214584057d0bc73a613081bf1152590549649d4582c13c android.hardware.wifi@1.1::IWifiChip
+
+# ABI preserving changes to HALs during Android O MR1 (Final Set)
+09342041e17c429fce0034b9096d17849122111436a5f0053e7e59500e1cb89c android.hardware.media.omx@1.0::IOmxStore
+2d833aeed0cd1d59437aca210be590a953cf32bcb6683cd63d089762a643fb49 android.hardware.radio@1.0::IRadioResponse
+0a159f81359cd4f71bbe00972ee8403ea79351fb7c0cd48be72ebb3e424dbaef android.hardware.radio@1.0::types
+05aa3de6130a9788fdb6f4d3cc57c3ea90f067e77a5e09d6a772ec7f6bca33d2 android.hardware.radio@1.1::IRadioResponse
+
+# HALs released in Android O MR1 (Final Set)
+044cb039378b8a0e36f40ff1e6ce04dc0d339da02095f968d5062a051e99d108 android.hardware.broadcastradio@1.1::types
+c9699483f8cefe4f9b39b4b9609b76cab2dd1659a06188056b45797d337d4256 android.hardware.broadcastradio@1.1::IBroadcastRadio
+b5d62dcd663fc4fcc977b252af59b333043bdfe73de2f11fe6d6a8bf438a0f92 android.hardware.broadcastradio@1.1::IBroadcastRadioFactory
+bc7e054a6e93adebedff345aeed44549be89e6b1b6ffe071ff47a61de764b232 android.hardware.broadcastradio@1.1::ITuner
+e9139fc755be578693f17c8cd1e27c75f412cfc722157bab5bf03ee68896e31d android.hardware.broadcastradio@1.1::ITunerCallback
+63929c99e5755d9e09d9e0fd2527391fbb1609dda0508f5933b7943b92ae0fbc android.hardware.camera.device@3.3::types
+bbcfc3f748b078f6a66c4e228084a679d30bd61bfde8bb7a91efd507b91c1bfd android.hardware.camera.device@3.3::ICameraDeviceSession
+4a6998cd6793a3f9f03989c29d662589b1bc9d38826c6698c6c17864f7a814f5 android.hardware.cas@1.0::types
+0e656ba1bac11461a17096ef752b69d24b000d820ef5652f0150a0f9731d54c2 android.hardware.cas@1.0::ICas
+b80e1456b81f80032d0de7cb45652ac15af11e7474d520d757481ecaad796dff android.hardware.cas@1.0::ICasListener
+a432d6d9200248dc2126827bcd6cdea31dd65eff39b939f64585d27d915a5857 android.hardware.cas@1.0::IDescramblerBase
+86ba9c03978b79a742e990420bc5ced0673d25a939f82572996bef92621e2014 android.hardware.cas@1.0::IMediaCasService
+503da837d1a67cbdb7c08a033e927e5430ae1b159d98bf72c6336b4dcc5e76f5 android.hardware.cas.native@1.0::types
+619600109232ed64b827c8a11beed8070b1827ae464547d7aa146cf0473b4bca android.hardware.cas.native@1.0::IDescrambler
+93eb3757ceaf21590fa4cd1d4a7dfe3b3794af5396100a6d25630879352abce9 android.hardware.neuralnetworks@1.0::IDevice
+f66f9a38541bf92001d3adcce678cd7e3da2262124befb460b1c9aea9492813b android.hardware.neuralnetworks@1.0::IExecutionCallback
+953607822954435874f4b81686440a604e2a88cdd2d9164c6293f3d5772510d7 android.hardware.neuralnetworks@1.0::IPreparedModel
+73e03573494ba96f0e711ab7f1956c5b2d54c3da690cd7ecf4d6d0f287447730 android.hardware.neuralnetworks@1.0::IPreparedModelCallback
+246a56d37d57a47224562c9d077b4a2886ce6242b9311bd98a17325944c280d7 android.hardware.neuralnetworks@1.0::types
+f4945e397b5dea41bb64518dfde59be71245d8a125fd1e0acffeb57ac7b08fed android.hardware.thermal@1.1::IThermal
+c8bc853546dd55584611def2a9fa1d99f657e3366c976d2f60fe6b8aa6d2cb87 android.hardware.thermal@1.1::IThermalCallback
+
+# ABI preserving changes to HALs during Android P
+9e7a0b650d0e461ece2cfec0e1072abf8676f592b41a7fb48f01e88fc3c8f780 android.hardware.broadcastradio@1.0::types
+cf72ff5a52bfa4d08e9e1000cf3ab5952a2d280c7f13cdad5ab7905c08050766 android.hardware.camera.metadata@3.2::types
+3902efc42097cba55f0655aa389e052ea70164e99ced1a6d1ef53dafc13f7650 android.hardware.camera.provider@2.4::ICameraProvider
+6fa9804a17a8bb7923a56bd10493a5483c20007e4c9026fd04287bee7c945a8c android.hardware.gnss@1.0::IGnssCallback
+fb92e2b40f8e9d494e8fd3b4ac18499a3216342e7cff160714c3bbf3660b6e79 android.hardware.gnss@1.0::IGnssConfiguration
+251594ea9b27447bfa005ebd806e58fb0ae4aad84a69938129c9800ec0c64eda android.hardware.gnss@1.0::IGnssMeasurementCallback
+4e7169919d24fbe5573e5bcd683d0bd7abf553a4e6c34c41f9dfc1e12050db07 android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+190ea4898809de6cf379afe318f5fa9564686157b24d9a2d7f5698b0c977d8b2 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer
+25892789b50eb673506b6c5a2cdab5d9aa428d41608aab10280cc898538b524a android.hardware.graphics.composer@2.1::IComposerClient
+e205dd30f5ff99445b706a901de8ebc46c379e9d7c1921d6a327ed2082cfa83d android.hardware.graphics.composer@2.1::types
+a46251718abfada458dc64c41ce94915757bf6c87cfa2d9e99cfb01fa8e32331 android.hardware.graphics.mapper@2.0::IMapper
+bd33ac23c57b4a07632691d2191bc2c93930f57e62f4ccf459748fdaa5c0f480 android.hardware.graphics.mapper@2.0::types
+ad8a28ca3a5549fb9bc24cf5f80ac8f660cc27be885210d76266780aa52ddb8d android.hardware.keymaster@3.0::types
+5804ca86611d72e5481f022b3a0c1b334217f2e4988dad25730c42af2d1f4d1c android.hardware.neuralnetworks@1.0::IDevice
+12e8dca4ab7d8aadd0ef8f1b438021938e2396139e85db2ed65783b08800aa52 android.hardware.neuralnetworks@1.0::IExecutionCallback
+86b77e06da756a76aa3685be88765852dd982a86d8c90b8b4fc1130ed4184c8f android.hardware.neuralnetworks@1.0::types
+d4840db8efabdf1e4b344fc981cd36e5fe81a39aff6e199f6d06c1c8da413efd android.hardware.radio@1.0::types
+f96cbc59dfe16c8d0c2a7e06db24d8738a6328b6e90f7b8e1640ea2b4600debd android.hardware.radio@1.1::ISap
+2d86929794795e5c70f4fdb5073485fd05835c9c6f496116687c3d9f32e6df3e android.hardware.radio@1.2::ISap
+905a4af79c8329b39d8b11b08f015137216bb078b427b6986f32884a04bc1bec android.hardware.tv.cec@1.0::types
+aebcd9ff2da05c9d4c439916f40dfd219ba7629919007cb981ebf150064b4f82 android.hardware.usb@1.1::IUsb
+e29fb1941b40a990676f8e9c676a38761defd890b81a9c034608eb7ba6496023 android.hardware.wifi@1.0::IWifiP2pIface
+b280c4704dfcc548a9bf127b59b7c3578f460c50cce70a06b66fe0df8b27cff0 android.hardware.wifi@1.0::types
+
+# HALs released in Android P
+5860cf040a3d5d771967ecf648b00d06876a7120da985ee2b3e95d01f634dd20 android.hardware.audio@4.0::IDevice
+cf82a0249e918fdc657e189895e92d60af0491868477e82cdc30f6cab0ca2c65 android.hardware.audio@4.0::IDevicesFactory
+be3dc9baed45a0d330152eca3ca24fa419b375b20a41644c88d4fb46b72784d2 android.hardware.audio@4.0::IPrimaryDevice
+3e3acb70c4e6c7d578f511f4a44ee764ab9126f887a3bf65d523c42e40012bf6 android.hardware.audio@4.0::IStream
+d5de64e66b95f135dd42492250a309134b8227203ef3524440798c66b6f5a392 android.hardware.audio@4.0::IStreamIn
+888ac906461327fa0bd93854d5109be8c292a33afdb467164826970a8bd5b789 android.hardware.audio@4.0::IStreamOut
+15f6ae78e73344c8e7d68847ef03caec64fcd9f951bbcf59957d1712c247fcff android.hardware.audio@4.0::IStreamOutCallback
+61f0eaa4d08547d039e9b1dd7c82abe2c004286d1b9b8153c2491ff46a8a63ca android.hardware.audio@4.0::types
+5d47a2ad2c136b8aba067dd45bb10d0ad390dd76340764154f580658f98f4fe6 android.hardware.audio.common@4.0::types
+b04b6b364938b80008e61fa2e318bc299622433e57c2e1f6cfba332a3f6e3f15 android.hardware.audio.effect@4.0::IAcousticEchoCancelerEffect
+1c17d4ece5c8ba3f7a646a305ee0dd109b0d51372e1bd585812e513cd40e1852 android.hardware.audio.effect@4.0::IAutomaticGainControlEffect
+34174259fe6fbb1bb14e7103e097f2f25529271a676687845b2f55d6d0d9d617 android.hardware.audio.effect@4.0::IBassBoostEffect
+7a18e9bd0163f3784448f6e24be0db75f877e2f0f9bd0d7ec427f1c34b382c0b android.hardware.audio.effect@4.0::IDownmixEffect
+bac81bffbe2661d5b6839087d2dd3a27eded66e60c6c76d35c68d54014cd5c06 android.hardware.audio.effect@4.0::IEffect
+65f0bcf9e498b26f3266ad10cf513a6c2b5906cc49f9db4bc5c7d3ba11a72e05 android.hardware.audio.effect@4.0::IEffectBufferProviderCallback
+5a746e81175489eb2371b88864c36c9bb63bc64ef799fae74cd96003b013c0d1 android.hardware.audio.effect@4.0::IEffectsFactory
+839980c7c5be79da6b95fdb9354a62b04407b4b084749b7a21d2c340773d7638 android.hardware.audio.effect@4.0::IEnvironmentalReverbEffect
+2805fbdac7cff050a1c095b9276bb41ac02a3b7b354336817487eb9a4b6bb462 android.hardware.audio.effect@4.0::IEqualizerEffect
+a91b547f5922f39fe4231d97fac1c3825c1c1b0c8ef7a5136689ceed37e8bfe9 android.hardware.audio.effect@4.0::ILoudnessEnhancerEffect
+1145f5b921ddec184fda5bdc87487b46f2a89cd9f42cc882bbb3a54f4ac80466 android.hardware.audio.effect@4.0::INoiseSuppressionEffect
+3661fa0623056922fdc4235ac5a9c91a2d066ab6f1ab4297e3b240fe302ba500 android.hardware.audio.effect@4.0::IPresetReverbEffect
+e88e520f8c98a62fccd8d5316c6687808f775de145d1405a7a9a66587ee6a001 android.hardware.audio.effect@4.0::IVirtualizerEffect
+fe28829dab10d171783b79ac9cc45412739f8ff275e90228d7c6370ef189b859 android.hardware.audio.effect@4.0::IVisualizerEffect
+21c8a702579356480236c6851b5b2c16b9bd369ce12bdd6ffdc4626a89f34f73 android.hardware.audio.effect@4.0::types
+42a06dc288f61b0690580f3d37b30b663c31d74d50bb58d0772386b550d5faab android.hardware.authsecret@1.0::IAuthSecret
+32cc50cc2a7658ec613c0c2dd2accbf6a05113b749852879e818b8b7b438db19 android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioHost
+ff4be64d7992f8bec97dff37f35450e79b3430c61f85f54322ce45bef229dc3b android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload
+27f22d2e873e6201f9620cf4d8e2facb25bd0dd30a2b911e441b4600d560fa62 android.hardware.bluetooth.a2dp@1.0::types
+3d8ed67d807e9f15d0708390a416bee00920f6a22196c104cc9e443c8d217df8 android.hardware.broadcastradio@2.0::IAnnouncementListener
+44017c42e6f4d8cb30f07eb1da04540a98736a336ac28c7e0ed2e69e1589f8d1 android.hardware.broadcastradio@2.0::IBroadcastRadio
+e5f4960290b4f3089163dd43251e1a032c81e9bdb796e75a87fc7c5810c262b3 android.hardware.broadcastradio@2.0::ICloseHandle
+af24b87ca8b8f02fcde205e47db6a9609fc7e9d77d73e694ec8f9c508ca19575 android.hardware.broadcastradio@2.0::ITunerCallback
+d70464c517a4a1b5167730843775a97f455102919e945b04f717b9da390c0f39 android.hardware.broadcastradio@2.0::ITunerSession
+2afa59ebf8145e7fbc090cf49605c27280c07d4178d47cd7f9d82b3b95a47af0 android.hardware.broadcastradio@2.0::types
+4fb0725c36ed4f77a42b42e3f18d8b5f7919cb62b90098b23143a555aa7dd96d android.hardware.camera.device@3.4::ICameraDeviceCallback
+812fa66aa10ba0cba27cfddc2fd7f0ee27a8ab65a1f15aa79fdad97d403e6a14 android.hardware.camera.device@3.4::ICameraDeviceSession
+cc288f1f78d1e643eb3d3dbc16e1401d44033d8e6856761f5156814a29986ec7 android.hardware.camera.device@3.4::types
+f9278c8beb9d42d96e26d73ecabe1dff1d7e2fb301ab7f737d93e5ffae8d3312 android.hardware.camera.metadata@3.3::types
+f858091b10f7d5927be60573c06df4805275d37226bbb41a732190bfb81457ec android.hardware.configstore@1.1::ISurfaceFlingerConfigs
+5b0fb9842f8b0eb3730b93c30a7925290ab44763ab86bb493bfa58d0f2eeb369 android.hardware.configstore@1.1::types
+1a46aeae45b7a0e47f79b7207300532986f9d9cd7060779afc7a529f54d712ab android.hardware.confirmationui@1.0::IConfirmationResultCallback
+6d8347ff3cd7de471065ac3e8e68385073630cdeebe9f8fa58cb91cf44436c95 android.hardware.confirmationui@1.0::IConfirmationUI
+a3ff916784dce87a56c757ab5c86433f0cdf562280999a5f978a6e8a0f3f19e7 android.hardware.confirmationui@1.0::types
+1fbf2d7e383632216aaaa1d972a21a618f55659263d2e6f0b309e3cb323b4b63 android.hardware.drm@1.1::ICryptoFactory
+7877ff8e4c1e48b825e6e5e66d050288e5656ed535c61cc7830a92ed4a9e1990 android.hardware.drm@1.1::IDrmFactory
+fef2f0ebde7704548fb203df46673ceb342272fc4fa9d0af25a980d2584a36e7 android.hardware.drm@1.1::IDrmPlugin
+5047a346ecce239404b9020959f60dd467318e9c17b290a6386bc3894df62c3c android.hardware.drm@1.1::types
+a830336ac8627d6432cfafb1b884343ad9f885dee0a5323e380e6d3c519156b8 android.hardware.gnss@1.1::IGnss
+8ad55bc35bb3a83e65c018bdfde7ae5ebc749ff2bf6b79412ded0bc6c89b97d8 android.hardware.gnss@1.1::IGnssCallback
+3c5183d7506010be57e0f748e3640fc2ded1ba955784b6256ba427f4c399591c android.hardware.gnss@1.1::IGnssConfiguration
+1a07d1383e847c3deb696ec7a2c9e33b9683772945660448a010b18063da67a4 android.hardware.gnss@1.1::IGnssMeasurement
+83e7a10ff3702147bd7ffa04567b20d407a3b16bbb7705644af44d919afe9103 android.hardware.gnss@1.1::IGnssMeasurementCallback
+0b96e0254e2168cfecb30c1ed5fb42681652cc00faa68c6e07568fafe64d1d50 android.hardware.graphics.common@1.1::types
+7d2cef99c838fb58038de8bbfd3cdb76ff4797241987077721715297f8d45e34 android.hardware.graphics.common@1.1::types # b/78135149
+d9b40a5b09962a5a0780b10fe33a4e607e69e2e088fc83de88a584115b7cb1c0 android.hardware.graphics.composer@2.2::IComposer
+a2f183f7fcc79aabedaef11095ab223aac0ed5ef984d850893872515e7f560c7 android.hardware.graphics.composer@2.2::IComposerClient
+dd83be076b6b3f10ed62ab34d8c8b95f2415961fb785200eb842e7bfb2b0ee92 android.hardware.graphics.mapper@2.1::IMapper
+675682dd3007805c985eaaec91612abc88f4c25b3431fb84070b7584a1a741fb android.hardware.health@2.0::IHealth
+434c4c32c00b0e54bb05e40c79503208b40f786a318029a2a4f66e34f10f2a76 android.hardware.health@2.0::IHealthInfoCallback
+c9e498f1ade5e26f00d290b4763a9671ec6720f915e7d592844b62e8cb1f9b5c android.hardware.health@2.0::types
+201f9723353fdbd40bf3705537fb7e015e4c399879425e68688fe0f43606ea4d android.hardware.keymaster@4.0::IKeymasterDevice
+1b7d2090c0a28b229d37c4b96160796b1f0d703950ac6ccc163fccd280830503 android.hardware.keymaster@4.0::types
+6d5c646a83538f0f9d8438c259932509f4353410c6c76e56db0d6ca98b69c3bb android.hardware.media.bufferpool@1.0::IAccessor
+b8c7ed58aa8740361e63d0ce9e7c94227572a629f356958840b34809d2393a7c android.hardware.media.bufferpool@1.0::IClientManager
+4a2c0dc82780e6c90731725a103feab8ab6ecf85a64e049b9cbd2b2c61620fe1 android.hardware.media.bufferpool@1.0::IConnection
+6aef1218e5949f867b0104752ac536c1b707222a403341720de90141df129e3e android.hardware.media.bufferpool@1.0::types
+7698dc2382a2eeb43541840e3ee624f34108efdfb976b2bfa7c13ef15fb8c4c4 android.hardware.neuralnetworks@1.1::IDevice
+72cc6126632456e8fbb8776fe50150c3c4dd5d09145653193affb70785211dfa android.hardware.neuralnetworks@1.1::types
+8d3d86da0bfa4bf070970d8303c659f67f35d670c287d45a3f542e4fedadd578 android.hardware.nfc@1.1::INfc
+e85f566698d2a2c28100e264fcf2c691a066756ddf8dd341d009ff50cfe10614 android.hardware.nfc@1.1::INfcClientCallback
+5e278fcaa3287d397d8eebe1c22aaa28150f5caae1cf9381cd6dc32cb37899c5 android.hardware.nfc@1.1::types
+163e115e833fc1d77cdd4a8cf0c833bb8b8d74fe35c880fe693101d17774926f android.hardware.power@1.2::IPower
+7899b9305587b2d5cd74a3cc87e9090f58bf4ae74256ce3ee36e7ec011822840 android.hardware.power@1.2::types
+ab132c990a62f0aca35871c092c22fb9c85d478e22124ef6a4d0a2302da76a9f android.hardware.radio@1.2::IRadio
+cda752aeabaabc20486a82ac57a3dd107785c006094a349bc5e224e8aa22a17c android.hardware.radio@1.2::IRadioIndication
+da8c6ae991c6a4b284cc6e445332e064e28ee8a09482ed5afff9d159ec6694b7 android.hardware.radio@1.2::IRadioResponse
+b65332996eb39ba63300a1011404141fa59ce5c252bc17afae637be6eeca5f55 android.hardware.radio@1.2::ISap
+a9361522cc97ef66209d39ba324095b2f08344054bb4d3481e803eee0480623a android.hardware.radio@1.2::types
+87385469cf4409f0f33b01508e7a477cf71f2a11e466dd7e3ab5971a1baaa72b android.hardware.radio.config@1.0::IRadioConfig
+228b2ee3c8c276c9f0afad2dc313ca3d6bbd9e482ddf313c7204c60ad9b636ab android.hardware.radio.config@1.0::IRadioConfigIndication
+a2e9b7aa09f79426f765838174e04b6f9a3e6c8b76b923fc1705632207bad44b android.hardware.radio.config@1.0::IRadioConfigResponse
+4307696b64ded9bd8de06887f9dfc533e875c4e0d83b8008df4d705164bde0b1 android.hardware.radio.config@1.0::types
+bd7699f07ba5392310fefd33ea964e01f4f4a66015146845c85055004823cc81 android.hardware.secure_element@1.0::ISecureElement
+a65aa82bbe48d81a9ae9e86247bb1b89fd2d3138d4053d7a5b716c71149b7dee android.hardware.secure_element@1.0::ISecureElementHalCallback
+2984c069f48ba35cd1bf49b0e17daad0d418fef52cb7a4a84dba0043114063d4 android.hardware.secure_element@1.0::types
+b4f507b4dc9b5cd5f0e4445926acb7d94525ae60dc307b3951142283632207b6 android.hardware.soundtrigger@2.1::ISoundTriggerHw
+92c2cc0f06ef744c5bda21f1d660258f7937203109b493eee22c3f3e2dbb0d3e android.hardware.soundtrigger@2.1::ISoundTriggerHwCallback
+8ddfa7542772cc7bca19972b2d856264efa31914bfd098aeb7c2079d950194cb android.hardware.usb.gadget@1.0::IUsbGadget
+ad0a620cda08f01b151c30cb7afa23b0637cc84340cf8dec00ac8e32cf54a8db android.hardware.usb.gadget@1.0::IUsbGadgetCallback
+51fc20f223561ac3a32ace3217837ef3860265bd91c8b7ae3859532caef9bc39 android.hardware.usb.gadget@1.0::types
+1bfc9fd9536ed09f04bcaf222a332bc919f1565d4d08bddccdebe1bfca8f01b5 android.hardware.vibrator@1.2::IVibrator
+a0aefa29881235c21e4761d15c55edc35ef85c2e0d9e01d0966176d1dbf5f811 android.hardware.vibrator@1.2::types
+8bc75a0dfac15c6f87ffec950b76c7d7de30d516b54e8e0b1f3c0ff9c7c6873b android.hardware.wifi@1.2::IWifi
+780c16fdeda13b779d993953a67f7ca578c938a172a9424c1c715ae81bc40fd7 android.hardware.wifi@1.2::IWifiChip
+167af870fdb87e1cbbaa0fa62ef35e1031caad20dd1ba695983dedb1e9993486 android.hardware.wifi@1.2::IWifiChipEventCallback
+8c7ef32fc78d5ec6e6956de3784cc2c6f42614b5272d2e461f6d60534ba38ec2 android.hardware.wifi@1.2::IWifiNanIface
+1e6074efad9da333803fb7c1acdb719d51c30b2e1e92087b0420341631c30b60 android.hardware.wifi@1.2::IWifiNanIfaceEventCallback
+f5682dbf19f712bef9cc3faa5fe3dc670b6ffbcb62a147a1d86b9d43574cd83f android.hardware.wifi@1.2::IWifiStaIface
+6db2e7d274be2dca9bf3087afd1f774a68c99d2b4dc7eeaf41690e5cebcbef7a android.hardware.wifi@1.2::types
+ee08280de21cb41e3ec26d6ed636c701b7f70516e71fb22f4fe60a13e603f406 android.hardware.wifi.hostapd@1.0::IHostapd
+b2479cd7a417a1cf4f3a22db4e4579e21bac38fdcaf381e2bf10176d05397e01 android.hardware.wifi.hostapd@1.0::types
+e362203b941f18bd4cba29a62adfa02453ed00d6be5b72cdb6c4d7e0bf394a40 android.hardware.wifi.supplicant@1.1::ISupplicant
+21757d0e5dd4b7e4bd981a4a20531bca3c32271ad9777b17b74eb5a1ea508384 android.hardware.wifi.supplicant@1.1::ISupplicantStaIface
+cd4330c3196bda1d642a32abfe23a7d64ebfbda721940643af6867af3b3f0aa9 android.hardware.wifi.supplicant@1.1::ISupplicantStaIfaceCallback
+10ff2fae516346b86121368ce5790d5accdfcb73983246b813f3d488b66db45a android.hardware.wifi.supplicant@1.1::ISupplicantStaNetwork
diff --git a/prebuilt_hashes/Android.bp b/prebuilt_hashes/Android.bp
new file mode 100644
index 0000000..4692b76
--- /dev/null
+++ b/prebuilt_hashes/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 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.
+
+python_binary_host {
+ name: "dump_hals_for_release",
+
+ srcs: [
+ "dump_hals_for_release.py",
+ ],
+
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+}
diff --git a/prebuilt_hashes/dump_hals_for_release.py b/prebuilt_hashes/dump_hals_for_release.py
new file mode 100755
index 0000000..fee12ab
--- /dev/null
+++ b/prebuilt_hashes/dump_hals_for_release.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 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.
+#
+
+"""
+Dump new HIDL types that are introduced in each dessert release.
+"""
+
+from __future__ import print_function
+
+import argparse
+import collections
+import json
+import os
+import re
+
+class Globals:
+ pass
+
+class Constants:
+ CURRENT = 'current'
+ HAL_PATH_PATTERN = r'/((?:[a-zA-Z_]+/)*)(\d+\.\d+)/([a-zA-Z_]+).hal'
+ CURRENT_TXT_PATTERN = r'(?:.*/)?([0-9]+|current).txt'
+
+def trim_trailing_comments(line):
+ idx = line.find('#')
+ if idx < 0: return line
+ return line[0:idx]
+
+def strip_begin(s, prefix):
+ if s.startswith(prefix):
+ return strip_begin(s[len(prefix):], prefix)
+ return s
+
+def strip_end(s, suffix):
+ if s.endswith(suffix):
+ return strip_end(s[0:-len(suffix)], suffix)
+ return s
+
+def get_interfaces(file_name):
+ with open(file_name) as file:
+ for line in file:
+ line_tokens = trim_trailing_comments(line).strip().split()
+ if not line_tokens:
+ continue
+ assert len(line_tokens) == 2, \
+ "Unrecognized line in file {}:\n{}".format(file_name, line)
+ yield line_tokens[1]
+
+def api_level_to_int(api_level):
+ try:
+ if api_level == Constants.CURRENT: return float('inf')
+ return int(api_level)
+ except ValueError:
+ return None
+
+def get_interfaces_from_package_root(package, root):
+ root = strip_end(root, '/')
+ for dirpath, _, filenames in os.walk(root, topdown=False):
+ dirpath = strip_begin(dirpath, root)
+ for filename in filenames:
+ filepath = os.path.join(dirpath, filename)
+ mo = re.match(Constants.HAL_PATH_PATTERN, filepath)
+ if not mo:
+ continue
+ yield '{}.{}@{}::{}'.format(
+ package, mo.group(1).strip('/').replace('/', '.'), mo.group(2), mo.group(3))
+
+def filter_out(iterable):
+ return iterable if not Globals.filter_out else filter(
+ lambda s: all(re.search(pattern, s) is None for pattern in Globals.filter_out),
+ iterable)
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--pretty', help='Print pretty JSON', action='store_true')
+ parser.add_argument('--package-root', metavar='PACKAGE:PATH', nargs='*',
+ help='package root of current directory, e.g. android.hardware:hardware/interfaces')
+ parser.add_argument('--filter-out', metavar='REGEX', nargs='*',
+ help='A regular expression that filters out interfaces.')
+ parser.add_argument('hashes', metavar='FILE', nargs='*',
+ help='Locations of current.txt for each release.')
+ parser.parse_args(namespace=Globals)
+
+ interfaces_for_level = dict()
+
+ for filename in Globals.hashes or tuple():
+ mo = re.match(Constants.CURRENT_TXT_PATTERN, filename)
+ assert mo is not None, \
+ 'Input hash file names must have the format {} but is {}'.format(Constants.CURRENT_TXT_PATTERN, filename)
+
+ api_level = mo.group(1)
+ assert api_level_to_int(api_level) is not None
+
+ if api_level not in interfaces_for_level:
+ interfaces_for_level[api_level] = set()
+ interfaces_for_level[api_level].update(filter_out(get_interfaces(filename)))
+
+ for package_root in Globals.package_root or tuple():
+ tup = package_root.split(':')
+ assert len(tup) == 2, \
+ '--package-root must have the format PACKAGE:PATH, but is {}'.format(package_root)
+ if Constants.CURRENT not in interfaces_for_level:
+ interfaces_for_level[Constants.CURRENT] = set()
+ interfaces_for_level[Constants.CURRENT].update(filter_out(get_interfaces_from_package_root(*tup)))
+
+ seen_interfaces = set()
+ new_interfaces_for_level = collections.OrderedDict()
+ for level, interfaces in sorted(interfaces_for_level.items(), key=lambda tup: api_level_to_int(tup[0])):
+ if level != Constants.CURRENT:
+ removed_interfaces = seen_interfaces - interfaces
+ assert not removed_interfaces, \
+ "The following interfaces are removed from API level {}:\n{}".format(
+ level, removed_interfaces)
+ new_interfaces_for_level[level] = sorted(interfaces - seen_interfaces)
+ seen_interfaces.update(interfaces)
+
+ print(json.dumps(new_interfaces_for_level,
+ separators=None if Globals.pretty else (',',':'),
+ indent=4 if Globals.pretty else None))
+
+if __name__ == '__main__':
+ main()
diff --git a/radio/1.3/Android.bp b/radio/1.3/Android.bp
index 6a9b1d0..7012f6b 100644
--- a/radio/1.3/Android.bp
+++ b/radio/1.3/Android.bp
@@ -17,15 +17,21 @@
"android.hardware.radio@1.1",
"android.hardware.radio@1.2",
"android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
],
types: [
"AccessNetwork",
+ "CellConfigLte",
+ "CellInfo",
+ "CellInfoLte",
+ "CardStatus",
"DataProfileInfo",
"DataRegStateResult",
"EmergencyNumber",
"EmergencyNumberSource",
"EmergencyServiceCategory",
"LteVopsInfo",
+ "NetworkScanResult",
],
gen_java: true,
}
diff --git a/radio/1.3/IRadioIndication.hal b/radio/1.3/IRadioIndication.hal
index 509eef8..e7f26ac 100644
--- a/radio/1.3/IRadioIndication.hal
+++ b/radio/1.3/IRadioIndication.hal
@@ -49,4 +49,17 @@
*/
oneway currentEmergencyNumberList(RadioIndicationType type,
vec<EmergencyNumber> emergencyNumberList);
+
+ /**
+ * Request all of the current cell information known to the radio.
+ *
+ * @param type Type of radio indication
+ * @param records Current cell information
+ */
+ oneway cellInfoList_1_3(RadioIndicationType type, vec<CellInfo> records);
+
+ /**
+ * Incremental network scan results
+ */
+ oneway networkScanResult_1_3(RadioIndicationType type, NetworkScanResult result);
};
diff --git a/radio/1.3/IRadioResponse.hal b/radio/1.3/IRadioResponse.hal
index 10e7d63..fecd951 100644
--- a/radio/1.3/IRadioResponse.hal
+++ b/radio/1.3/IRadioResponse.hal
@@ -50,6 +50,17 @@
/**
* @param info Response info struct containing response type, serial no. and error
+ * @param cellInfo List of current cell information known to radio
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getCellInfoListResponse_1_3(RadioResponseInfo info, vec<CellInfo> cellInfo);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
* @param dataRegResponse Current Data registration response as defined by DataRegStateResult in
* types.hal
*
@@ -61,4 +72,19 @@
*/
oneway getDataRegistrationStateResponse_1_3(RadioResponseInfo info,
DataRegStateResult dataRegResponse);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param cardStatus ICC card status as defined by CardStatus in types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NO_MEMORY
+ * RadioError:NO_RESOURCES
+ * RadioError:CANCELLED
+ * RadioError:REQUEST_NOT_SUPPORTED
+ */
+ oneway getIccCardStatusResponse_1_3(RadioResponseInfo info, CardStatus cardStatus);
};
diff --git a/radio/1.3/types.hal b/radio/1.3/types.hal
index a41f4b2..d3a6f78 100644
--- a/radio/1.3/types.hal
+++ b/radio/1.3/types.hal
@@ -18,14 +18,27 @@
import @1.0::ApnAuthType;
import @1.0::ApnTypes;
+import @1.0::CellInfoType;
import @1.0::DataProfileId;
import @1.0::DataProfileInfoType;
import @1.0::RadioAccessFamily;
+import @1.0::RadioError;
import @1.0::RegState;
+import @1.0::TimeStampType;
+import @1.1::ScanStatus;
import @1.2::AccessNetwork;
+import @1.2::CellInfo;
+import @1.2::CellInfoCdma;
+import @1.2::CellInfoGsm;
+import @1.2::CellInfoLte;
+import @1.2::CellInfoTdscdma;
+import @1.2::CellInfoWcdma;
+import @1.2::CardStatus;
import @1.2::CellIdentity;
import @1.2::DataRegStateResult;
+import android.hidl.safe_union@1.0::Monostate;
+
enum AccessNetwork : @1.2::AccessNetwork {
/**
* Unknown access network
@@ -162,14 +175,88 @@
* will be empty when device is camped only on 2G/3G .
*/
safe_union VopsInfo {
+ Monostate noinit;
+
LteVopsInfo lteVopsInfo; // LTE network capability
} vopsInfo;
+
+ /**
+ * True if use of dual connectivity with NR is restricted.
+ * Reference: 3GPP TS 24.301 v15.03 section 9.3.3.12A.
+ */
+ bool isDcNrRestricted;
+
+ /**
+ * True if the bit N is in the PLMN-InfoList-r15 is true and the selected PLMN is present in
+ * plmn-IdentityList at position N.
+ * Reference: 3GPP TS 36.331 v15.2.2 section 6.3.1 PLMN-InfoList-r15.
+ * 3GPP TS 36.331 v15.2.2 section 6.2.2 SystemInformationBlockType1 message.
+ */
+ bool isNrAvailable;
+};
+
+/** Contains the configuration of the LTE cell tower. */
+struct CellConfigLte {
+ /**
+ * Indicates that if E-UTRA-NR Dual Connectivity (EN-DC) is supported by the LTE cell.
+ *
+ * True if the plmn-InfoList-r15 is present in SIB2 and at least one bit in this list is true,
+ * otherwise this value should be false.
+ *
+ * Reference: 3GPP TS 36.331 v15.2.2 6.3.1 System information blocks.
+ */
+ bool isEndcAvailable;
+};
+
+/** Inherits from @1.2::CellInfoLte, in order to add the LTE configuration. */
+struct CellInfoLte {
+ @1.2::CellInfoLte base;
+ CellConfigLte cellConfig;
+};
+
+/** Overwritten from @1.2::CellInfo in order to update the CellInfoLte to 1.3 version. */
+struct CellInfo {
+ /** Cell type for selecting from union CellInfo. */
+ CellInfoType cellInfoType;
+
+ /**
+ * True if the phone is registered to a mobile network that provides service on this cell and
+ * this cell is being used or would be used for network signaling.
+ */
+ bool isRegistered;
+
+ /** CellInfo details, cellInfoType can tell which cell info should be used. */
+ safe_union Info {
+ CellInfoGsm gsm;
+ CellInfoCdma cdma;
+ CellInfoWcdma wcdma;
+ CellInfoTdscdma tdscdma;
+ CellInfoLte lte;
+ } info;
+};
+
+/** Overwritten from @1.2::NetworkScanResult in order to update the CellInfo to 1.3 version. */
+struct NetworkScanResult {
+ /**
+ * The status of the scan.
+ */
+ ScanStatus status;
+
+ /**
+ * The error code of the incremental result.
+ */
+ RadioError error;
+
+ /**
+ * List of network information as CellInfo.
+ */
+ vec<CellInfo> networkInfos;
};
/**
- * Overwritten from @1.0::DataProfileInfo in order to deprecate 'mvnoType', 'mvnoMatchData',
- * 'maxConnsTime', and 'maxConns'. In the future, this must be extended instead of overwritten.
- * Added 'preferred' and 'persistent' in this version.
+ * Overwritten from @1.0::DataProfileInfo in order to deprecate 'mvnoType', and 'mvnoMatchData'.
+ * In the future, this must be extended instead of overwritten.
+ * Also added 'preferred' and 'persistent' in this version.
*/
struct DataProfileInfo {
/** id of the data profile */
@@ -202,6 +289,12 @@
/** Data profile technology type */
DataProfileInfoType type;
+ /** The period in seconds to limit the maximum connections */
+ int32_t maxConnsTime;
+
+ /** The maximum connections during maxConnsTime */
+ int32_t maxConns;
+
/**
* The required wait time in seconds after a successful UE initiated disconnect of a given PDN
* connection before the device can send a new PDN connection request for that given PDN.
@@ -233,3 +326,15 @@
*/
bool persistent;
};
+
+struct CardStatus {
+ @1.2::CardStatus base;
+ /**
+ * The EID is the eUICC identifier. The EID shall be stored within the ECASD and can be
+ * retrieved by the Device at any time using the standard GlobalPlatform GET DATA command.
+ *
+ * This data is mandatory and applicable only when cardState is CardState:PRESENT and SIM card
+ * supports eUICC.
+ */
+ string eid;
+};
diff --git a/radio/config/1.1/Android.bp b/radio/config/1.1/Android.bp
new file mode 100644
index 0000000..8dc0f27
--- /dev/null
+++ b/radio/config/1.1/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.radio.config@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IRadioConfigIndication.hal",
+ "IRadioConfigResponse.hal",
+ ],
+ interfaces: [
+ "android.hardware.radio@1.0",
+ "android.hardware.radio.config@1.0",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "SimSlotStatus",
+ ],
+ gen_java: true,
+}
diff --git a/radio/config/1.1/IRadioConfigIndication.hal b/radio/config/1.1/IRadioConfigIndication.hal
new file mode 100644
index 0000000..53eaa4d
--- /dev/null
+++ b/radio/config/1.1/IRadioConfigIndication.hal
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.radio.config@1.1;
+
+import @1.0::IRadioConfigIndication;
+import android.hardware.radio@1.0::RadioIndicationType;
+
+/**
+ * Interface declaring unsolicited radio config indications.
+ */
+interface IRadioConfigIndication extends @1.0::IRadioConfigIndication {
+
+ /**
+ * Indicates SIM slot status change.
+ *
+ * This indication must be sent by the modem whenever there is any slot status change, even the
+ * slot is inactive. For example, this indication must be triggered if a SIM card is inserted
+ * into an inactive slot.
+ *
+ * @param type Type of radio indication
+ * @param slotStatus new slot status info with size equals to the number of physical slots on
+ * the device
+ */
+ oneway simSlotsStatusChanged_1_1(RadioIndicationType type, vec<SimSlotStatus> slotStatus);
+};
diff --git a/radio/config/1.1/IRadioConfigResponse.hal b/radio/config/1.1/IRadioConfigResponse.hal
new file mode 100644
index 0000000..6f543ab
--- /dev/null
+++ b/radio/config/1.1/IRadioConfigResponse.hal
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.radio.config@1.1;
+
+import android.hardware.radio@1.0::RadioResponseInfo;
+import @1.0::IRadioConfigResponse;
+import @1.1::SimSlotStatus;
+
+/**
+ * Interface declaring response functions to solicited radio config requests.
+ */
+interface IRadioConfigResponse extends @1.0::IRadioConfigResponse {
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param slotStatus Sim slot struct containing all the physical SIM slots info with size
+ * equal to the number of physical slots on the device
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:NO_MEMORY
+ * RadioError:INTERNAL_ERR
+ * RadioError:MODEM_ERR
+ */
+ oneway getSimSlotsStatusResponse_1_1(RadioResponseInfo info, vec<SimSlotStatus> slotStatus);
+};
diff --git a/radio/config/1.1/types.hal b/radio/config/1.1/types.hal
new file mode 100644
index 0000000..0c9d11e
--- /dev/null
+++ b/radio/config/1.1/types.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.radio.config@1.1;
+
+import android.hardware.radio@1.0::CardState;
+import @1.0::SimSlotStatus;
+
+struct SimSlotStatus {
+ @1.0::SimSlotStatus base;
+ /**
+ * The EID is the eUICC identifier. The EID shall be stored within the ECASD and can be
+ * retrieved by the Device at any time using the standard GlobalPlatform GET DATA command.
+ *
+ * This data is mandatory and applicable only when cardState is CardState:PRESENT and SIM card
+ * supports eUICC.
+ */
+ string eid;
+};
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index a5747d4..52f5e4f 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -74,8 +74,7 @@
};
switch (dst->sensorType) {
- case SensorType::META_DATA:
- {
+ case SensorType::META_DATA: {
dst->u.meta.what = (MetaDataEventType)src.meta_data.what;
// Legacy HALs contain the handle reference in the meta data field.
// Copy that over to the handle of the event. In legacy HALs this
@@ -89,8 +88,7 @@
case SensorType::ORIENTATION:
case SensorType::GYROSCOPE:
case SensorType::GRAVITY:
- case SensorType::LINEAR_ACCELERATION:
- {
+ case SensorType::LINEAR_ACCELERATION: {
dst->u.vec3.x = src.acceleration.x;
dst->u.vec3.y = src.acceleration.y;
dst->u.vec3.z = src.acceleration.z;
@@ -98,10 +96,7 @@
break;
}
- case SensorType::ROTATION_VECTOR:
- case SensorType::GAME_ROTATION_VECTOR:
- case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
- {
+ case SensorType::GAME_ROTATION_VECTOR: {
dst->u.vec4.x = src.data[0];
dst->u.vec4.y = src.data[1];
dst->u.vec4.z = src.data[2];
@@ -109,151 +104,150 @@
break;
}
- case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
- case SensorType::GYROSCOPE_UNCALIBRATED:
- case SensorType::ACCELEROMETER_UNCALIBRATED:
- {
- dst->u.uncal.x = src.uncalibrated_gyro.x_uncalib;
- dst->u.uncal.y = src.uncalibrated_gyro.y_uncalib;
- dst->u.uncal.z = src.uncalibrated_gyro.z_uncalib;
- dst->u.uncal.x_bias = src.uncalibrated_gyro.x_bias;
- dst->u.uncal.y_bias = src.uncalibrated_gyro.y_bias;
- dst->u.uncal.z_bias = src.uncalibrated_gyro.z_bias;
- break;
- }
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ dst->u.data[0] = src.data[0];
+ dst->u.data[1] = src.data[1];
+ dst->u.data[2] = src.data[2];
+ dst->u.data[3] = src.data[3];
+ dst->u.data[4] = src.data[4];
+ break;
+ }
- case SensorType::DEVICE_ORIENTATION:
- case SensorType::LIGHT:
- case SensorType::PRESSURE:
- case SensorType::TEMPERATURE:
- case SensorType::PROXIMITY:
- case SensorType::RELATIVE_HUMIDITY:
- case SensorType::AMBIENT_TEMPERATURE:
- case SensorType::SIGNIFICANT_MOTION:
- case SensorType::STEP_DETECTOR:
- case SensorType::TILT_DETECTOR:
- case SensorType::WAKE_GESTURE:
- case SensorType::GLANCE_GESTURE:
- case SensorType::PICK_UP_GESTURE:
- case SensorType::WRIST_TILT_GESTURE:
- case SensorType::STATIONARY_DETECT:
- case SensorType::MOTION_DETECT:
- case SensorType::HEART_BEAT:
- case SensorType::LOW_LATENCY_OFFBODY_DETECT:
- {
- dst->u.scalar = src.data[0];
- break;
- }
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED: {
+ dst->u.uncal.x = src.uncalibrated_gyro.x_uncalib;
+ dst->u.uncal.y = src.uncalibrated_gyro.y_uncalib;
+ dst->u.uncal.z = src.uncalibrated_gyro.z_uncalib;
+ dst->u.uncal.x_bias = src.uncalibrated_gyro.x_bias;
+ dst->u.uncal.y_bias = src.uncalibrated_gyro.y_bias;
+ dst->u.uncal.z_bias = src.uncalibrated_gyro.z_bias;
+ break;
+ }
- case SensorType::STEP_COUNTER:
- {
- dst->u.stepCount = src.u64.step_counter;
- break;
- }
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::TEMPERATURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
+ dst->u.scalar = src.data[0];
+ break;
+ }
- case SensorType::HEART_RATE:
- {
- dst->u.heartRate.bpm = src.heart_rate.bpm;
- dst->u.heartRate.status = (SensorStatus)src.heart_rate.status;
- break;
- }
+ case SensorType::STEP_COUNTER: {
+ dst->u.stepCount = src.u64.step_counter;
+ break;
+ }
- case SensorType::POSE_6DOF: // 15 floats
- {
- for (size_t i = 0; i < 15; ++i) {
- dst->u.pose6DOF[i] = src.data[i];
- }
- break;
- }
+ case SensorType::HEART_RATE: {
+ dst->u.heartRate.bpm = src.heart_rate.bpm;
+ dst->u.heartRate.status = (SensorStatus)src.heart_rate.status;
+ break;
+ }
- case SensorType::DYNAMIC_SENSOR_META:
- {
- dst->u.dynamic.connected = src.dynamic_sensor_meta.connected;
- dst->u.dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+ case SensorType::POSE_6DOF: { // 15 floats
+ for (size_t i = 0; i < 15; ++i) {
+ dst->u.pose6DOF[i] = src.data[i];
+ }
+ break;
+ }
- memcpy(dst->u.dynamic.uuid.data(),
- src.dynamic_sensor_meta.uuid,
- 16);
+ case SensorType::DYNAMIC_SENSOR_META: {
+ dst->u.dynamic.connected = src.dynamic_sensor_meta.connected;
+ dst->u.dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
- break;
- }
+ memcpy(dst->u.dynamic.uuid.data(), src.dynamic_sensor_meta.uuid, 16);
- case SensorType::ADDITIONAL_INFO:
- {
- ::android::hardware::sensors::V1_0::AdditionalInfo *dstInfo =
- &dst->u.additional;
+ break;
+ }
- const additional_info_event_t &srcInfo = src.additional_info;
+ case SensorType::ADDITIONAL_INFO: {
+ ::android::hardware::sensors::V1_0::AdditionalInfo* dstInfo = &dst->u.additional;
- dstInfo->type =
- (::android::hardware::sensors::V1_0::AdditionalInfoType)
- srcInfo.type;
+ const additional_info_event_t& srcInfo = src.additional_info;
- dstInfo->serial = srcInfo.serial;
+ dstInfo->type = (::android::hardware::sensors::V1_0::AdditionalInfoType)srcInfo.type;
- CHECK_EQ(sizeof(dstInfo->u), sizeof(srcInfo.data_int32));
- memcpy(&dstInfo->u, srcInfo.data_int32, sizeof(srcInfo.data_int32));
- break;
- }
+ dstInfo->serial = srcInfo.serial;
- default:
- {
- CHECK_GE((int32_t)dst->sensorType,
- (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+ CHECK_EQ(sizeof(dstInfo->u), sizeof(srcInfo.data_int32));
+ memcpy(&dstInfo->u, srcInfo.data_int32, sizeof(srcInfo.data_int32));
+ break;
+ }
- memcpy(dst->u.data.data(), src.data, 16 * sizeof(float));
- break;
- }
- }
+ default: {
+ CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ memcpy(dst->u.data.data(), src.data, 16 * sizeof(float));
+ break;
+ }
+ }
}
void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
- *dst = {
- .version = sizeof(sensors_event_t),
- .sensor = src.sensorHandle,
- .type = (int32_t)src.sensorType,
- .reserved0 = 0,
- .timestamp = src.timestamp
- };
+ *dst = {.version = sizeof(sensors_event_t),
+ .sensor = src.sensorHandle,
+ .type = (int32_t)src.sensorType,
+ .reserved0 = 0,
+ .timestamp = src.timestamp};
- switch (src.sensorType) {
- case SensorType::META_DATA:
- {
- // Legacy HALs expect the handle reference in the meta data field.
- // Copy it over from the handle of the event.
- dst->meta_data.what = (int32_t)src.u.meta.what;
- dst->meta_data.sensor = src.sensorHandle;
- // Set the sensor handle to 0 to maintain compatibility.
- dst->sensor = 0;
- break;
- }
+ switch (src.sensorType) {
+ case SensorType::META_DATA: {
+ // Legacy HALs expect the handle reference in the meta data field.
+ // Copy it over from the handle of the event.
+ dst->meta_data.what = (int32_t)src.u.meta.what;
+ dst->meta_data.sensor = src.sensorHandle;
+ // Set the sensor handle to 0 to maintain compatibility.
+ dst->sensor = 0;
+ break;
+ }
- case SensorType::ACCELEROMETER:
- case SensorType::MAGNETIC_FIELD:
- case SensorType::ORIENTATION:
- case SensorType::GYROSCOPE:
- case SensorType::GRAVITY:
- case SensorType::LINEAR_ACCELERATION:
- {
- dst->acceleration.x = src.u.vec3.x;
- dst->acceleration.y = src.u.vec3.y;
- dst->acceleration.z = src.u.vec3.z;
- dst->acceleration.status = (int8_t)src.u.vec3.status;
- break;
- }
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION: {
+ dst->acceleration.x = src.u.vec3.x;
+ dst->acceleration.y = src.u.vec3.y;
+ dst->acceleration.z = src.u.vec3.z;
+ dst->acceleration.status = (int8_t)src.u.vec3.status;
+ break;
+ }
- case SensorType::ROTATION_VECTOR:
- case SensorType::GAME_ROTATION_VECTOR:
- case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
- {
- dst->data[0] = src.u.vec4.x;
- dst->data[1] = src.u.vec4.y;
- dst->data[2] = src.u.vec4.z;
- dst->data[3] = src.u.vec4.w;
- break;
- }
+ case SensorType::GAME_ROTATION_VECTOR: {
+ dst->data[0] = src.u.vec4.x;
+ dst->data[1] = src.u.vec4.y;
+ dst->data[2] = src.u.vec4.z;
+ dst->data[3] = src.u.vec4.w;
+ break;
+ }
- case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ dst->data[0] = src.u.data[0];
+ dst->data[1] = src.u.data[1];
+ dst->data[2] = src.u.data[2];
+ dst->data[3] = src.u.data[3];
+ dst->data[4] = src.u.data[4];
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
case SensorType::GYROSCOPE_UNCALIBRATED:
case SensorType::ACCELEROMETER_UNCALIBRATED:
{
@@ -283,35 +277,30 @@
case SensorType::STATIONARY_DETECT:
case SensorType::MOTION_DETECT:
case SensorType::HEART_BEAT:
- case SensorType::LOW_LATENCY_OFFBODY_DETECT:
- {
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
dst->data[0] = src.u.scalar;
break;
}
- case SensorType::STEP_COUNTER:
- {
+ case SensorType::STEP_COUNTER: {
dst->u64.step_counter = src.u.stepCount;
break;
}
- case SensorType::HEART_RATE:
- {
+ case SensorType::HEART_RATE: {
dst->heart_rate.bpm = src.u.heartRate.bpm;
dst->heart_rate.status = (int8_t)src.u.heartRate.status;
break;
}
- case SensorType::POSE_6DOF: // 15 floats
- {
+ case SensorType::POSE_6DOF: { // 15 floats
for (size_t i = 0; i < 15; ++i) {
dst->data[i] = src.u.pose6DOF[i];
}
break;
}
- case SensorType::DYNAMIC_SENSOR_META:
- {
+ case SensorType::DYNAMIC_SENSOR_META: {
dst->dynamic_sensor_meta.connected = src.u.dynamic.connected;
dst->dynamic_sensor_meta.handle = src.u.dynamic.sensorHandle;
dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
@@ -323,8 +312,7 @@
break;
}
- case SensorType::ADDITIONAL_INFO:
- {
+ case SensorType::ADDITIONAL_INFO: {
const ::android::hardware::sensors::V1_0::AdditionalInfo &srcInfo =
src.u.additional;
@@ -341,8 +329,7 @@
break;
}
- default:
- {
+ default: {
CHECK_GE((int32_t)src.sensorType,
(int32_t)SensorType::DEVICE_PRIVATE_BASE);
diff --git a/sensors/1.0/types.hal b/sensors/1.0/types.hal
index 3926e2f..e91820c 100644
--- a/sensors/1.0/types.hal
+++ b/sensors/1.0/types.hal
@@ -1157,8 +1157,7 @@
Vec3 vec3;
/**
- * SensorType::ROTATION_VECTOR, SensorType::GAME_ROTATION_VECTOR,
- * SensorType::GEOMAGNETIC_ROTATION_VECTOR
+ * SensorType::GAME_ROTATION_VECTOR
*/
Vec4 vec4;
@@ -1200,7 +1199,14 @@
/** SensorType::ADDITIONAL_INFO */
AdditionalInfo additional;
- /** undefined/custom sensor type >= SensorType::DEVICE_PRIVATE_BASE */
+ /**
+ * The following sensors should use the data field:
+ * - Undefined/custom sensor type >= SensorType::DEVICE_PRIVATE_BASE
+ * - SensorType::ROTATION_VECTOR, SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+ * - These are Vec4 types with an additional float accuracy field,
+ * where data[4] is the estimated heading accuracy in radians
+ * (-1 if unavailable, and invalid if not in the range (0, 2 * pi]).
+ */
float[16] data;
};
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
index f8b021e..00207b1 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
@@ -94,9 +94,9 @@
}
void SensorsHidlEnvironmentV1_0::startPollingThread() {
- stopThread = false;
- pollThread = std::thread(pollingThread, this, std::ref(stopThread));
- events.reserve(128);
+ mStopThread = false;
+ mPollThread = std::thread(pollingThread, this, std::ref(mStopThread));
+ mEvents.reserve(128);
}
void SensorsHidlEnvironmentV1_0::pollingThread(SensorsHidlEnvironmentV1_0* env,
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index 4155f16..47308e1 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -17,354 +17,64 @@
#define LOG_TAG "sensors_hidl_hal_test"
#include "SensorsHidlEnvironmentV1_0.h"
-#include "sensors-vts-utils/GrallocWrapper.h"
-#include "sensors-vts-utils/SensorEventsChecker.h"
+#include "sensors-vts-utils/SensorsHidlTestBase.h"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android-base/logging.h>
#include <android/hardware/sensors/1.0/ISensors.h>
#include <android/hardware/sensors/1.0/types.h>
-#include <cutils/ashmem.h>
-#include <hardware/sensors.h> // for sensor type strings
#include <log/log.h>
#include <utils/SystemClock.h>
-#include <algorithm>
#include <cinttypes>
-#include <cmath>
-#include <memory>
-#include <mutex>
-#include <thread>
-#include <unordered_set>
#include <vector>
-#include <sys/mman.h>
-#include <unistd.h>
-
-using ::android::GrallocWrapper;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hardware::hidl_string;
using ::android::sp;
using namespace ::android::hardware::sensors::V1_0;
-class SensorsTestSharedMemory {
- public:
- static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
- SharedMemInfo getSharedMemInfo() const;
- char * getBuffer() const;
- std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
- virtual ~SensorsTestSharedMemory();
- private:
- SensorsTestSharedMemory(SharedMemType type, size_t size);
-
- SharedMemType mType;
- native_handle_t* mNativeHandle;
- size_t mSize;
- char* mBuffer;
- std::unique_ptr<GrallocWrapper> mGrallocWrapper;
-
- DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
-};
-
-SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
- SharedMemInfo mem = {
- .type = mType,
- .format = SharedMemFormat::SENSORS_EVENT,
- .size = static_cast<uint32_t>(mSize),
- .memoryHandle = mNativeHandle
- };
- return mem;
-}
-
-char * SensorsTestSharedMemory::getBuffer() const {
- return mBuffer;
-}
-
-std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
-
- constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
- constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
- constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
- constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
- constexpr size_t kOffsetAtomicCounter =
- static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
- constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
- constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
-
- std::vector<Event> events;
- std::vector<float> data(16);
-
- while (offset + kEventSize <= mSize) {
- int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter);
- if (atomicCounter <= lastCounter) {
- ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter, lastCounter);
- break;
- }
-
- int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize);
- if (size != kEventSize) {
- // unknown error, events parsed may be wrong, remove all
- events.clear();
- break;
- }
-
- int32_t token = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetToken);
- int32_t type = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetType);
- int64_t timestamp = *reinterpret_cast<int64_t *>(mBuffer + offset + kOffsetTimestamp);
-
- ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 ", timestamp %" PRId64,
- offset, atomicCounter, token, type, timestamp);
-
- Event event = {
- .timestamp = timestamp,
- .sensorHandle = token,
- .sensorType = static_cast<SensorType>(type),
- };
- event.u.data = android::hardware::hidl_array<float, 16>
- (reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
-
- events.push_back(event);
-
- lastCounter = atomicCounter;
- offset += kEventSize;
- }
-
- return events;
-}
-
-SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
- : mType(type), mSize(0), mBuffer(nullptr) {
- native_handle_t *handle = nullptr;
- char *buffer = nullptr;
- switch(type) {
- case SharedMemType::ASHMEM: {
- int fd;
- handle = ::native_handle_create(1 /*nFds*/, 0/*nInts*/);
- if (handle != nullptr) {
- handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
- if (handle->data[0] > 0) {
- // memory is pinned by default
- buffer = static_cast<char *>
- (::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
- if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
- break;
- }
- ::native_handle_close(handle);
- }
- ::native_handle_delete(handle);
- handle = nullptr;
- }
- break;
- }
- case SharedMemType::GRALLOC: {
- mGrallocWrapper = std::make_unique<GrallocWrapper>();
- if (mGrallocWrapper->getAllocator() == nullptr || mGrallocWrapper->getMapper() == nullptr) {
- break;
- }
- using android::hardware::graphics::common::V1_0::BufferUsage;
- using android::hardware::graphics::common::V1_0::PixelFormat;
- mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
- .width = static_cast<uint32_t>(size),
- .height = 1,
- .layerCount = 1,
- .usage = static_cast<uint64_t> (BufferUsage::SENSOR_DIRECT_DATA |
- BufferUsage::CPU_READ_OFTEN),
- .format = PixelFormat::BLOB
- };
-
- handle = const_cast<native_handle_t *>(mGrallocWrapper->allocate(buf_desc_info));
- if (handle != nullptr) {
- mapper2::IMapper::Rect region{0, 0,
- static_cast<int32_t>(buf_desc_info.width),
- static_cast<int32_t>(buf_desc_info.height)};
- buffer = static_cast<char *>
- (mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
- if (buffer != nullptr) {
- break;
- }
- mGrallocWrapper->freeBuffer(handle);
- handle = nullptr;
- }
- break;
- }
- default:
- break;
- }
-
- if (buffer != nullptr) {
- mNativeHandle = handle;
- mSize = size;
- mBuffer = buffer;
- }
-}
-
-SensorsTestSharedMemory::~SensorsTestSharedMemory() {
- switch(mType) {
- case SharedMemType::ASHMEM: {
- if (mSize != 0) {
- ::munmap(mBuffer, mSize);
- mBuffer = nullptr;
-
- ::native_handle_close(mNativeHandle);
- ::native_handle_delete(mNativeHandle);
-
- mNativeHandle = nullptr;
- mSize = 0;
- }
- break;
- }
- case SharedMemType::GRALLOC: {
- if (mSize != 0) {
- mGrallocWrapper->unlock(mNativeHandle);
- mGrallocWrapper->freeBuffer(mNativeHandle);
-
- mNativeHandle = nullptr;
- mSize = 0;
- }
- break;
- }
- default: {
- if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
- ALOGE("SensorsTestSharedMemory %p not properly destructed: "
- "type %d, native handle %p, size %zu, buffer %p",
- this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
- }
- break;
- }
- }
-}
-
-SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) {
- constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M
- if (size == 0 || size >= kMaxSize) {
- return nullptr;
- }
-
- auto m = new SensorsTestSharedMemory(type, size);
- if (m->mSize != size || m->mBuffer == nullptr) {
- delete m;
- m = nullptr;
- }
- return m;
-}
-
// The main test class for SENSORS HIDL HAL.
-class SensorsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- }
- virtual void TearDown() override {
- // stop all sensors
- for (auto s : mSensorHandles) {
- S()->activate(s, false);
+class SensorsHidlTest : public SensorsHidlTestBase {
+ protected:
+ SensorInfo defaultSensorByType(SensorType type) override;
+ std::vector<SensorInfo> getSensorsList();
+ // implementation wrapper
+ Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override {
+ return S()->getSensorsList(_hidl_cb);
}
- mSensorHandles.clear();
- // stop all direct report and channels
- for (auto c : mDirectChannelHandles) {
- // disable all reports
- S()->configDirectReport(-1, c, RateLevel::STOP, [] (auto, auto){});
- S()->unregisterDirectChannel(c);
+ Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+ Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override {
+ return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
}
- mDirectChannelHandles.clear();
- }
- protected:
- SensorInfo defaultSensorByType(SensorType type);
- std::vector<SensorInfo> getSensorsList();
- std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
- bool clearBeforeStart = true, bool changeCollection = true);
+ Return<Result> flush(int32_t sensorHandle) override { return S()->flush(sensorHandle); }
- // implementation wrapper
- Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) {
- return S()->getSensorsList(_hidl_cb);
- }
+ Return<Result> injectSensorData(const Event& event) override {
+ return S()->injectSensorData(event);
+ }
- Return<Result> activate(
- int32_t sensorHandle, bool enabled);
+ Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ ISensors::registerDirectChannel_cb _hidl_cb) override;
- Return<Result> batch(
- int32_t sensorHandle,
- int64_t samplingPeriodNs,
- int64_t maxReportLatencyNs) {
- return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
- }
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+ return S()->unregisterDirectChannel(channelHandle);
+ }
- Return<Result> flush(int32_t sensorHandle) {
- return S()->flush(sensorHandle);
- }
+ Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ ISensors::configDirectReport_cb _hidl_cb) override {
+ return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+ }
- Return<Result> injectSensorData(const Event& event) {
- return S()->injectSensorData(event);
- }
+ inline sp<ISensors>& S() { return SensorsHidlEnvironmentV1_0::Instance()->sensors; }
- Return<void> registerDirectChannel(
- const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb);
-
- Return<Result> unregisterDirectChannel(int32_t channelHandle) {
- return S()->unregisterDirectChannel(channelHandle);
- }
-
- Return<void> configDirectReport(
- int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
- ISensors::configDirectReport_cb _hidl_cb) {
- return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
- }
-
- inline sp<ISensors>& S() { return SensorsHidlEnvironmentV1_0::Instance()->sensors; }
-
- inline static SensorFlagBits extractReportMode(uint64_t flag) {
- return (SensorFlagBits) (flag
- & ((uint64_t) SensorFlagBits::CONTINUOUS_MODE
- | (uint64_t) SensorFlagBits::ON_CHANGE_MODE
- | (uint64_t) SensorFlagBits::ONE_SHOT_MODE
- | (uint64_t) SensorFlagBits::SPECIAL_REPORTING_MODE));
- }
-
- inline static bool isMetaSensorType(SensorType type) {
- return (type == SensorType::META_DATA
- || type == SensorType::DYNAMIC_SENSOR_META
- || type == SensorType::ADDITIONAL_INFO);
- }
-
- inline static bool isValidType(SensorType type) {
- return (int32_t) type > 0;
- }
-
- void testStreamingOperation(SensorType type,
- std::chrono::nanoseconds samplingPeriod,
- std::chrono::seconds duration,
- const SensorEventsChecker &checker);
- void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true);
- void testBatchingOperation(SensorType type);
- void testDirectReportOperation(
- SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker);
-
- static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
- static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
- static void assertDelayMatchReportMode(
- int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
- static SensorFlagBits expectedReportModeForType(SensorType type);
- static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
- static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
-
- // checkers
- static const Vec3NormChecker sAccelNormChecker;
- static const Vec3NormChecker sGyroNormChecker;
-
- // all sensors and direct channnels used
- std::unordered_set<int32_t> mSensorHandles;
- std::unordered_set<int32_t> mDirectChannelHandles;
+ SensorsHidlEnvironmentBase* getEnvironment() override {
+ return SensorsHidlEnvironmentV1_0::Instance();
+ }
};
-const Vec3NormChecker SensorsHidlTest::sAccelNormChecker(
- Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f/*m/s^2*/));
-const Vec3NormChecker SensorsHidlTest::sGyroNormChecker(
- Vec3NormChecker::byNominal(0.f, 0.1f/*rad/s*/));
-
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
// If activating a sensor, add the handle in a set so that when test fails it can be turned off.
// The handle is not removed when it is deactivating on purpose so that it is not necessary to
@@ -391,195 +101,6 @@
return Void();
}
-std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
- bool clearBeforeStart, bool changeCollection) {
- std::vector<Event> events;
- constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //granularity 100 ms
-
- ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
- nEventLimit, timeLimitUs, clearBeforeStart);
-
- if (changeCollection) {
- SensorsHidlEnvironmentV1_0::Instance()->setCollection(true);
- }
- if (clearBeforeStart) {
- SensorsHidlEnvironmentV1_0::Instance()->catEvents(nullptr);
- }
-
- while (timeLimitUs > 0) {
- useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
- usleep(duration);
- timeLimitUs -= duration;
-
- SensorsHidlEnvironmentV1_0::Instance()->catEvents(&events);
- if (events.size() >= nEventLimit) {
- break;
- }
- ALOGV("time to go = %d, events to go = %d",
- (int)timeLimitUs, (int)(nEventLimit - events.size()));
- }
-
- if (changeCollection) {
- SensorsHidlEnvironmentV1_0::Instance()->setCollection(false);
- }
- return events;
-}
-
-void SensorsHidlTest::assertTypeMatchStringType(SensorType type, const hidl_string& stringType) {
-
- if (type >= SensorType::DEVICE_PRIVATE_BASE) {
- return;
- }
-
- switch (type) {
-#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
- case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType.c_str()); break;
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
- default:
- FAIL() << "Type " << static_cast<int>(type) << " in android defined range is not checked, "
- << "stringType = " << stringType;
-#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
- }
-}
-
-void SensorsHidlTest::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
- if (type >= SensorType::DEVICE_PRIVATE_BASE) {
- return;
- }
-
- SensorFlagBits expected = expectedReportModeForType(type);
-
- ASSERT_TRUE(expected == (SensorFlagBits) -1 || expected == reportMode)
- << "reportMode=" << static_cast<int>(reportMode)
- << "expected=" << static_cast<int>(expected);
-}
-
-void SensorsHidlTest::assertDelayMatchReportMode(
- int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode) {
- switch(reportMode) {
- case SensorFlagBits::CONTINUOUS_MODE:
- ASSERT_LT(0, minDelay);
- ASSERT_LE(0, maxDelay);
- break;
- case SensorFlagBits::ON_CHANGE_MODE:
- ASSERT_LE(0, minDelay);
- ASSERT_LE(0, maxDelay);
- break;
- case SensorFlagBits::ONE_SHOT_MODE:
- ASSERT_EQ(-1, minDelay);
- ASSERT_EQ(0, maxDelay);
- break;
- case SensorFlagBits::SPECIAL_REPORTING_MODE:
- // do not enforce anything for special reporting mode
- break;
- default:
- FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
- }
-}
-
-// return -1 means no expectation for this type
-SensorFlagBits SensorsHidlTest::expectedReportModeForType(SensorType type) {
- switch (type) {
- case SensorType::ACCELEROMETER:
- case SensorType::ACCELEROMETER_UNCALIBRATED:
- case SensorType::GYROSCOPE:
- case SensorType::MAGNETIC_FIELD:
- case SensorType::ORIENTATION:
- case SensorType::PRESSURE:
- case SensorType::TEMPERATURE:
- case SensorType::GRAVITY:
- case SensorType::LINEAR_ACCELERATION:
- case SensorType::ROTATION_VECTOR:
- case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
- case SensorType::GAME_ROTATION_VECTOR:
- case SensorType::GYROSCOPE_UNCALIBRATED:
- case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
- case SensorType::POSE_6DOF:
- case SensorType::HEART_BEAT:
- return SensorFlagBits::CONTINUOUS_MODE;
-
- case SensorType::LIGHT:
- case SensorType::PROXIMITY:
- case SensorType::RELATIVE_HUMIDITY:
- case SensorType::AMBIENT_TEMPERATURE:
- case SensorType::HEART_RATE:
- case SensorType::DEVICE_ORIENTATION:
- case SensorType::STEP_COUNTER:
- case SensorType::LOW_LATENCY_OFFBODY_DETECT:
- return SensorFlagBits::ON_CHANGE_MODE;
-
- case SensorType::SIGNIFICANT_MOTION:
- case SensorType::WAKE_GESTURE:
- case SensorType::GLANCE_GESTURE:
- case SensorType::PICK_UP_GESTURE:
- case SensorType::MOTION_DETECT:
- case SensorType::STATIONARY_DETECT:
- return SensorFlagBits::ONE_SHOT_MODE;
-
- case SensorType::STEP_DETECTOR:
- case SensorType::TILT_DETECTOR:
- case SensorType::WRIST_TILT_GESTURE:
- case SensorType::DYNAMIC_SENSOR_META:
- return SensorFlagBits::SPECIAL_REPORTING_MODE;
-
- default:
- ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
- return (SensorFlagBits)-1;
- }
-}
-
-bool SensorsHidlTest::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
- unsigned int r =
- static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT)
- >> static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
- return r >= static_cast<unsigned int>(rate);
-}
-
-bool SensorsHidlTest::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
- switch (type) {
- case SharedMemType::ASHMEM:
- return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
- case SharedMemType::GRALLOC:
- return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
- default:
- return false;
- }
-}
-
SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
SensorInfo ret;
@@ -724,69 +245,6 @@
ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
}
-void SensorsHidlTest::testStreamingOperation(SensorType type,
- std::chrono::nanoseconds samplingPeriod,
- std::chrono::seconds duration,
- const SensorEventsChecker &checker) {
- std::vector<Event> events;
- std::vector<Event> sensorEvents;
-
- const int64_t samplingPeriodInNs = samplingPeriod.count();
- const int64_t batchingPeriodInNs = 0; // no batching
- const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
- const size_t minNEvent = duration / samplingPeriod;
-
- SensorInfo sensor = defaultSensorByType(type);
-
- if (!isValidType(sensor.type)) {
- // no default sensor of this type
- return;
- }
-
- if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
- // rate not supported
- return;
- }
-
- int32_t handle = sensor.sensorHandle;
-
- ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
- ASSERT_EQ(activate(handle, 1), Result::OK);
- events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
- ASSERT_EQ(activate(handle, 0), Result::OK);
-
- ALOGI("Collected %zu samples", events.size());
-
- ASSERT_GT(events.size(), 0u);
-
- bool handleMismatchReported = false;
- bool metaSensorTypeErrorReported = false;
- for (auto & e : events) {
- if (e.sensorType == type) {
- // avoid generating hundreds of error
- if (!handleMismatchReported) {
- EXPECT_EQ(e.sensorHandle, handle)
- << (handleMismatchReported = true,
- "Event of the same type must come from the sensor registered");
- }
- sensorEvents.push_back(e);
- } else {
- // avoid generating hundreds of error
- if (!metaSensorTypeErrorReported) {
- EXPECT_TRUE(isMetaSensorType(e.sensorType))
- << (metaSensorTypeErrorReported = true,
- "Only meta types are allowed besides the type registered");
- }
- }
- }
-
- std::string s;
- EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
-
- EXPECT_GE(sensorEvents.size(),
- minNEvent / 2); // make sure returned events are not all meta
-}
-
// Test if sensor hal can do UI speed accelerometer streaming properly
TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
testStreamingOperation(SensorType::ACCELEROMETER,
@@ -859,103 +317,6 @@
NullChecker());
}
-void SensorsHidlTest::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) {
- std::vector<Event> events1, events2;
-
- constexpr int64_t batchingPeriodInNs = 0; // no batching
- constexpr int64_t collectionTimeoutUs = 60000000; // 60s
- constexpr size_t minNEvent = 50;
-
- SensorInfo sensor = defaultSensorByType(type);
-
- if (!isValidType(sensor.type)) {
- // no default sensor of this type
- return;
- }
-
- int32_t handle = sensor.sensorHandle;
- int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
- int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll;
-
- if (minSamplingPeriodInNs == maxSamplingPeriodInNs) {
- // only support single rate
- return;
- }
-
- int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
- int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
-
- // first collection
- ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK);
- ASSERT_EQ(activate(handle, 1), Result::OK);
-
- usleep(500000); // sleep 0.5 sec to wait for change rate to happen
- events1 = collectEvents(collectionTimeoutUs, minNEvent);
-
- // second collection, without stop sensor
- ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
-
- usleep(500000); // sleep 0.5 sec to wait for change rate to happen
- events2 = collectEvents(collectionTimeoutUs, minNEvent);
-
- // end of collection, stop sensor
- ASSERT_EQ(activate(handle, 0), Result::OK);
-
- ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
-
- ASSERT_GT(events1.size(), 0u);
- ASSERT_GT(events2.size(), 0u);
-
- int64_t minDelayAverageInterval, maxDelayAverageInterval;
- std::vector<Event> &minDelayEvents(fastToSlow ? events1 : events2);
- std::vector<Event> &maxDelayEvents(fastToSlow ? events2 : events1);
-
- size_t nEvent = 0;
- int64_t prevTimestamp = -1;
- int64_t timestampInterval = 0;
- for (auto & e : minDelayEvents) {
- if (e.sensorType == type) {
- ASSERT_EQ(e.sensorHandle, handle);
- if (prevTimestamp > 0) {
- timestampInterval += e.timestamp - prevTimestamp;
- }
- prevTimestamp = e.timestamp;
- ++ nEvent;
- }
- }
- ASSERT_GT(nEvent, 2u);
- minDelayAverageInterval = timestampInterval / (nEvent - 1);
-
- nEvent = 0;
- prevTimestamp = -1;
- timestampInterval = 0;
- for (auto & e : maxDelayEvents) {
- if (e.sensorType == type) {
- ASSERT_EQ(e.sensorHandle, handle);
- if (prevTimestamp > 0) {
- timestampInterval += e.timestamp - prevTimestamp;
- }
- prevTimestamp = e.timestamp;
- ++ nEvent;
- }
- }
- ASSERT_GT(nEvent, 2u);
- maxDelayAverageInterval = timestampInterval / (nEvent - 1);
-
- // change of rate is significant.
- ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64,
- minDelayAverageInterval, maxDelayAverageInterval);
- EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
-
- // fastest rate sampling time is close to spec
- EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
- minSamplingPeriodInNs / 10);
-
- // slowest rate sampling time is close to spec
- EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
- maxSamplingPeriodInNs / 10);
-}
-
// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
@@ -974,74 +335,6 @@
testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
}
-void SensorsHidlTest::testBatchingOperation(SensorType type) {
- std::vector<Event> events;
-
- constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
- constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
-
- SensorInfo sensor = defaultSensorByType(type);
-
- if (!isValidType(sensor.type)) {
- // no default sensor of this type
- return;
- }
-
- int32_t handle = sensor.sensorHandle;
- int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
- uint32_t minFifoCount = sensor.fifoReservedEventCount;
- int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs;
-
- if (batchingPeriodInNs < oneSecondInNs) {
- // batching size too small to test reliably
- return;
- }
-
- batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs);
-
- ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000));
-
- int64_t allowedBatchDeliverTimeNs =
- std::max(oneSecondInNs, batchingPeriodInNs / 10);
-
- ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
- ASSERT_EQ(activate(handle, 1), Result::OK);
-
- usleep(500000); // sleep 0.5 sec to wait for initialization
- ASSERT_EQ(flush(handle), Result::OK);
-
- // wait for 80% of the reserved batching period
- // there should not be any significant amount of events
- // since collection is not enabled all events will go down the drain
- usleep(batchingPeriodInNs / 1000 * 8 / 10);
-
- SensorsHidlEnvironmentV1_0::Instance()->setCollection(true);
- // clean existing collections
- collectEvents(0 /*timeLimitUs*/, 0/*nEventLimit*/,
- true /*clearBeforeStart*/, false /*change collection*/);
-
- // 0.8 + 0.2 times the batching period
- usleep(batchingPeriodInNs / 1000 * 8 / 10);
- ASSERT_EQ(flush(handle), Result::OK);
-
- // plus some time for the event to deliver
- events = collectEvents(allowedBatchDeliverTimeNs / 1000,
- minFifoCount, false /*clearBeforeStart*/, false /*change collection*/);
-
- SensorsHidlEnvironmentV1_0::Instance()->setCollection(false);
- ASSERT_EQ(activate(handle, 0), Result::OK);
-
- size_t nEvent = 0;
- for (auto & e : events) {
- if (e.sensorType == type && e.sensorHandle == handle) {
- ++ nEvent;
- }
- }
-
- // at least reach 90% of advertised capacity
- ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10));
-}
-
// Test if sensor hal can do accelerometer batching properly
TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
testBatchingOperation(SensorType::ACCELEROMETER);
@@ -1057,124 +350,6 @@
testBatchingOperation(SensorType::MAGNETIC_FIELD);
}
-void SensorsHidlTest::testDirectReportOperation(
- SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker) {
- constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
- constexpr size_t kNEvent = 4096;
- constexpr size_t kMemSize = kEventSize * kNEvent;
-
- constexpr float kNormalNominal = 50;
- constexpr float kFastNominal = 200;
- constexpr float kVeryFastNominal = 800;
-
- constexpr float kNominalTestTimeSec = 1.f;
- constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization
-
- SensorInfo sensor = defaultSensorByType(type);
-
- if (!isValidType(sensor.type)) {
- // no default sensor of this type
- return;
- }
-
- if (!isDirectReportRateSupported(sensor, rate)) {
- return;
- }
-
- if (!isDirectChannelTypeSupported(sensor, memType)) {
- return;
- }
-
- std::unique_ptr<SensorsTestSharedMemory>
- mem(SensorsTestSharedMemory::create(memType, kMemSize));
- ASSERT_NE(mem, nullptr);
-
- char* buffer = mem->getBuffer();
- // fill memory with data
- for (size_t i = 0; i < kMemSize; ++i) {
- buffer[i] = '\xcc';
- }
-
- int32_t channelHandle;
- registerDirectChannel(mem->getSharedMemInfo(),
- [&channelHandle] (auto result, auto channelHandle_) {
- ASSERT_EQ(result, Result::OK);
- channelHandle = channelHandle_;
- });
-
- // check memory is zeroed
- for (size_t i = 0; i < kMemSize; ++i) {
- ASSERT_EQ(buffer[i], '\0');
- }
-
- int32_t eventToken;
- configDirectReport(sensor.sensorHandle, channelHandle, rate,
- [&eventToken] (auto result, auto token) {
- ASSERT_EQ(result, Result::OK);
- eventToken = token;
- });
-
- usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
- auto events = mem->parseEvents();
-
- // find norminal rate
- float nominalFreq = 0.f;
- switch (rate) {
- case RateLevel::NORMAL:
- nominalFreq = kNormalNominal;
- break;
- case RateLevel::FAST:
- nominalFreq = kFastNominal;
- break;
- case RateLevel::VERY_FAST:
- nominalFreq = kVeryFastNominal;
- break;
- case RateLevel::STOP:
- FAIL();
- }
-
- // allowed to be between 55% and 220% of nominal freq
- ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
- ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
-
- int64_t lastTimestamp = 0;
- bool typeErrorReported = false;
- bool tokenErrorReported = false;
- bool timestampErrorReported = false;
- std::vector<Event> sensorEvents;
- for (auto &e : events) {
- if (!tokenErrorReported) {
- EXPECT_EQ(eventToken, e.sensorHandle)
- << (tokenErrorReported = true,
- "Event token does not match that retured from configDirectReport");
- }
-
- if (isMetaSensorType(e.sensorType)) {
- continue;
- }
- sensorEvents.push_back(e);
-
- if (!typeErrorReported) {
- EXPECT_EQ(type, e.sensorType)
- << (typeErrorReported = true,
- "Type in event does not match type of sensor registered.");
- }
- if (!timestampErrorReported) {
- EXPECT_GT(e.timestamp, lastTimestamp)
- << (timestampErrorReported = true, "Timestamp not monotonically increasing");
- }
- lastTimestamp = e.timestamp;
- }
-
- std::string s;
- EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
-
- // stop sensor and unregister channel
- configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
- [](auto result, auto) { EXPECT_EQ(result, Result::OK); });
- EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
-}
-
// Test sensor event direct report with ashmem for accel sensor at normal rate
TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp
new file mode 100644
index 0000000..db0b148
--- /dev/null
+++ b/sensors/2.0/default/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 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.
+
+cc_binary {
+ name: "android.hardware.sensors@2.0-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "Sensor.cpp",
+ "Sensors.cpp",
+ ],
+ init_rc: ["android.hardware.sensors@2.0-service.rc"],
+ shared_libs: [
+ "android.hardware.sensors@1.0",
+ "android.hardware.sensors@2.0",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libpower",
+ "libutils",
+ ],
+}
diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS
new file mode 100644
index 0000000..2031d84
--- /dev/null
+++ b/sensors/2.0/default/OWNERS
@@ -0,0 +1,2 @@
+bduddie@google.com
+bstack@google.com
diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/2.0/default/Sensor.cpp
new file mode 100644
index 0000000..168b402
--- /dev/null
+++ b/sensors/2.0/default/Sensor.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "Sensor.h"
+
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+
+Sensor::Sensor(ISensorsEventCallback* callback)
+ : mIsEnabled(false),
+ mSamplingPeriodNs(0),
+ mLastSampleTimeNs(0),
+ mCallback(callback),
+ mMode(OperationMode::NORMAL) {
+ mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mStopThread = true;
+ mIsEnabled = false;
+ mWaitCV.notify_all();
+ lock.release();
+ mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+ return mSensorInfo;
+}
+
+void Sensor::batch(int32_t samplingPeriodNs) {
+ if (samplingPeriodNs < mSensorInfo.minDelay * 1000) {
+ samplingPeriodNs = mSensorInfo.minDelay * 1000;
+ } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000) {
+ samplingPeriodNs = mSensorInfo.maxDelay * 1000;
+ }
+
+ if (mSamplingPeriodNs != samplingPeriodNs) {
+ mSamplingPeriodNs = samplingPeriodNs;
+ // Wake up the 'run' thread to check if a new event should be generated now
+ mWaitCV.notify_all();
+ }
+}
+
+void Sensor::activate(bool enable) {
+ if (mIsEnabled != enable) {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mIsEnabled = enable;
+ mWaitCV.notify_all();
+ }
+}
+
+Result Sensor::flush() {
+ // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+ // one-shot sensor.
+ if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
+ return Result::BAD_VALUE;
+ }
+
+ // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+ // to the Event FMQ prior to writing the flush complete event.
+ Event ev;
+ ev.sensorHandle = mSensorInfo.sensorHandle;
+ ev.sensorType = SensorType::ADDITIONAL_INFO;
+ ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+ std::vector<Event> evs{ev};
+ mCallback->postEvents(evs, isWakeUpSensor());
+
+ return Result::OK;
+}
+
+void Sensor::startThread(Sensor* sensor) {
+ sensor->run();
+}
+
+void Sensor::run() {
+ std::unique_lock<std::mutex> runLock(mRunMutex);
+ constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+ while (!mStopThread) {
+ if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+ mWaitCV.wait(runLock, [&] {
+ return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+ });
+ } else {
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME, &curTime);
+ int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+ int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+ if (now >= nextSampleTime) {
+ mLastSampleTimeNs = now;
+ nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+ mCallback->postEvents(readEvents(), isWakeUpSensor());
+ }
+
+ mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+ }
+ }
+}
+
+bool Sensor::isWakeUpSensor() {
+ return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+ std::vector<Event> events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ event.u.vec3.x = 1;
+ event.u.vec3.y = 2;
+ event.u.vec3.z = 3;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ events.push_back(event);
+ return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+ if (mMode != mode) {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mMode = mode;
+ mWaitCV.notify_all();
+ }
+}
+
+bool Sensor::supportsDataInjection() const {
+ return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+ Result result = Result::OK;
+ if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+ // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+ // environment data into the device.
+ } else if (!supportsDataInjection()) {
+ result = Result::INVALID_OPERATION;
+ } else if (mMode == OperationMode::DATA_INJECTION) {
+ mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+ } else {
+ result = Result::BAD_VALUE;
+ }
+ return result;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Accel Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::ACCELEROMETER;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 78.4f; // +/- 8g
+ mSensorInfo.resolution = 1.52e-5;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 20 * 1000; // microseconds
+ mSensorInfo.maxDelay = 1000 * 1000; // microseconds
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags =
+ static_cast<uint32_t>(SensorFlagBits::WAKE_UP | SensorFlagBits::DATA_INJECTION);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/default/Sensor.h b/sensors/2.0/default/Sensor.h
new file mode 100644
index 0000000..3ab2299
--- /dev/null
+++ b/sensors/2.0/default/Sensor.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
+#define ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
+
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+class ISensorsEventCallback {
+ public:
+ virtual ~ISensorsEventCallback(){};
+ virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+ public:
+ Sensor(ISensorsEventCallback* callback);
+ virtual ~Sensor();
+
+ const SensorInfo& getSensorInfo() const;
+ void batch(int32_t samplingPeriodNs);
+ void activate(bool enable);
+ Result flush();
+
+ void setOperationMode(OperationMode mode);
+ bool supportsDataInjection() const;
+ Result injectEvent(const Event& event);
+
+ protected:
+ void run();
+ virtual std::vector<Event> readEvents();
+ static void startThread(Sensor* sensor);
+
+ bool isWakeUpSensor();
+
+ bool mIsEnabled;
+ int64_t mSamplingPeriodNs;
+ int64_t mLastSampleTimeNs;
+ SensorInfo mSensorInfo;
+
+ std::atomic_bool mStopThread;
+ std::condition_variable mWaitCV;
+ std::mutex mRunMutex;
+ std::thread mRunThread;
+
+ ISensorsEventCallback* mCallback;
+
+ OperationMode mMode;
+};
+
+class AccelSensor : public Sensor {
+ public:
+ AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp
new file mode 100644
index 0000000..efc8b05
--- /dev/null
+++ b/sensors/2.0/default/Sensors.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "Sensors.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+
+constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
+
+Sensors::Sensors()
+ : mEventQueueFlag(nullptr),
+ mOutstandingWakeUpEvents(0),
+ mReadWakeLockQueueRun(false),
+ mAutoReleaseWakeLockTime(0),
+ mHasWakeLock(false) {
+ std::shared_ptr<AccelSensor> accel =
+ std::make_shared<AccelSensor>(1 /* sensorHandle */, this /* callback */);
+ mSensors[accel->getSensorInfo().sensorHandle] = accel;
+}
+
+Sensors::~Sensors() {
+ deleteEventFlag();
+ mReadWakeLockQueueRun = false;
+ mWakeLockThread.join();
+}
+
+// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+Return<void> Sensors::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& sensor : mSensors) {
+ sensors.push_back(sensor.second->getSensorInfo());
+ }
+
+ // Call the HIDL callback with the SensorInfo
+ _hidl_cb(sensors);
+
+ return Void();
+}
+
+Return<Result> Sensors::setOperationMode(OperationMode mode) {
+ for (auto sensor : mSensors) {
+ sensor.second->setOperationMode(mode);
+ }
+ return Result::OK;
+}
+
+Return<Result> Sensors::activate(int32_t sensorHandle, bool enabled) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->activate(enabled);
+ return Result::OK;
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> Sensors::initialize(
+ const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+ const sp<ISensorsCallback>& sensorsCallback) {
+ Result result = Result::OK;
+
+ // Save a reference to the callback
+ mCallback = sensorsCallback;
+
+ // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+ mEventQueue =
+ std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
+
+ // Ensure that any existing EventFlag is properly deleted
+ deleteEventFlag();
+
+ // Create the EventFlag that is used to signal to the framework that sensor events have been
+ // written to the Event FMQ
+ if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+ result = Result::BAD_VALUE;
+ }
+
+ // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
+ // events have been successfully read and handled by the framework.
+ mWakeLockQueue =
+ std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+
+ if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+ result = Result::BAD_VALUE;
+ }
+
+ // Start the thread to read events from the Wake Lock FMQ
+ mReadWakeLockQueueRun = true;
+ mWakeLockThread = std::thread(startReadWakeLockThread, this);
+
+ return result;
+}
+
+Return<Result> Sensors::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t /* maxReportLatencyNs */) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->batch(samplingPeriodNs);
+ return Result::OK;
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> Sensors::flush(int32_t sensorHandle) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->flush();
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> Sensors::injectSensorData(const Event& event) {
+ auto sensor = mSensors.find(event.sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->injectEvent(event);
+ }
+
+ return Result::BAD_VALUE;
+}
+
+Return<void> Sensors::registerDirectChannel(const SharedMemInfo& /* mem */,
+ registerDirectChannel_cb _hidl_cb) {
+ _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+ return Return<void>();
+}
+
+Return<Result> Sensors::unregisterDirectChannel(int32_t /* channelHandle */) {
+ return Result::INVALID_OPERATION;
+}
+
+Return<void> Sensors::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */,
+ RateLevel /* rate */, configDirectReport_cb _hidl_cb) {
+ _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+ return Return<void>();
+}
+
+void Sensors::postEvents(const std::vector<Event>& events, bool wakeup) {
+ std::lock_guard<std::mutex> lock(mWriteLock);
+ if (mEventQueue->write(events.data(), events.size())) {
+ mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+
+ if (wakeup) {
+ // Keep track of the number of outstanding WAKE_UP events in order to properly hold
+ // a wake lock until the framework has secured a wake lock
+ updateWakeLock(events.size(), 0 /* eventsHandled */);
+ }
+ }
+}
+
+void Sensors::updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
+ std::lock_guard<std::mutex> lock(mWakeLockLock);
+ int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
+ if (newVal < 0) {
+ mOutstandingWakeUpEvents = 0;
+ } else {
+ mOutstandingWakeUpEvents = newVal;
+ }
+
+ if (eventsWritten > 0) {
+ // Update the time at which the last WAKE_UP event was sent
+ mAutoReleaseWakeLockTime = ::android::uptimeMillis() +
+ static_cast<uint32_t>(SensorTimeout::WAKE_LOCK_SECONDS) * 1000;
+ }
+
+ if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
+ mHasWakeLock = true;
+ } else if (mHasWakeLock) {
+ // Check if the wake lock should be released automatically if
+ // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written to
+ // the Wake Lock FMQ.
+ if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
+ ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
+ SensorTimeout::WAKE_LOCK_SECONDS);
+ mOutstandingWakeUpEvents = 0;
+ }
+
+ if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
+ mHasWakeLock = false;
+ }
+ }
+}
+
+void Sensors::readWakeLockFMQ() {
+ while (mReadWakeLockQueueRun.load()) {
+ constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000; // 500 ms
+ uint32_t eventsHandled = 0;
+
+ // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to ensure
+ // that any held wake lock is able to be released if it is held for too long.
+ mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, kReadTimeoutNs);
+ updateWakeLock(0 /* eventsWritten */, eventsHandled);
+ }
+}
+
+void Sensors::startReadWakeLockThread(Sensors* sensors) {
+ sensors->readWakeLockFMQ();
+}
+
+void Sensors::deleteEventFlag() {
+ status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag);
+ if (status != OK) {
+ ALOGI("Failed to delete event flag: %d", status);
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h
new file mode 100644
index 0000000..eba3f97
--- /dev/null
+++ b/sensors/2.0/default/Sensors.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
+#define ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
+
+#include "Sensor.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <memory>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct Sensors : public ISensors, public ISensorsEventCallback {
+ using Event = ::android::hardware::sensors::V1_0::Event;
+ using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
+ using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+ using Result = ::android::hardware::sensors::V1_0::Result;
+ using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+
+ Sensors();
+ virtual ~Sensors();
+
+ // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+ Return<Result> setOperationMode(OperationMode mode) override;
+
+ Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+ Return<Result> initialize(
+ const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+ const sp<ISensorsCallback>& sensorsCallback) override;
+
+ Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override;
+
+ Return<Result> flush(int32_t sensorHandle) override;
+
+ Return<Result> injectSensorData(const Event& event) override;
+
+ Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ registerDirectChannel_cb _hidl_cb) override;
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+ Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ configDirectReport_cb _hidl_cb) override;
+
+ void postEvents(const std::vector<Event>& events, bool wakeup) override;
+
+ private:
+ /**
+ * Utility function to delete the Event Flag
+ */
+ void deleteEventFlag();
+
+ /**
+ * Function to read the Wake Lock FMQ and release the wake lock when appropriate
+ */
+ void readWakeLockFMQ();
+
+ static void startReadWakeLockThread(Sensors* sensors);
+
+ /**
+ * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
+ */
+ void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled);
+
+ using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
+ using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+ /**
+ * The Event FMQ where sensor events are written
+ */
+ std::unique_ptr<EventMessageQueue> mEventQueue;
+
+ /**
+ * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+ */
+ std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
+
+ /**
+ * Event Flag to signal to the framework when sensor events are available to be read
+ */
+ EventFlag* mEventQueueFlag;
+
+ /**
+ * Callback for asynchronous events, such as dynamic sensor connections.
+ */
+ sp<ISensorsCallback> mCallback;
+
+ /**
+ * A map of the available sensors
+ */
+ std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+
+ /**
+ * Lock to protect writes to the FMQs
+ */
+ std::mutex mWriteLock;
+
+ /**
+ * Lock to protect acquiring and releasing the wake lock
+ */
+ std::mutex mWakeLockLock;
+
+ /**
+ * Track the number of WAKE_UP events that have not been handled by the framework
+ */
+ uint32_t mOutstandingWakeUpEvents;
+
+ /**
+ * A thread to read the Wake Lock FMQ
+ */
+ std::thread mWakeLockThread;
+
+ /**
+ * Flag to indicate that the Wake Lock Thread should continue to run
+ */
+ std::atomic_bool mReadWakeLockQueueRun;
+
+ /**
+ * Track the time when the wake lock should automatically be released
+ */
+ int64_t mAutoReleaseWakeLockTime;
+
+ /**
+ * Flag to indicate if a wake lock has been acquired
+ */
+ bool mHasWakeLock;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
diff --git a/sensors/2.0/default/android.hardware.sensors@2.0-service.rc b/sensors/2.0/default/android.hardware.sensors@2.0-service.rc
new file mode 100644
index 0000000..321d760
--- /dev/null
+++ b/sensors/2.0/default/android.hardware.sensors@2.0-service.rc
@@ -0,0 +1,5 @@
+service vendor.sensors-hal-2-0 /vendor/bin/hw/android.hardware.sensors@2.0-service
+ class hal
+ user system
+ group system
+ rlimit rtprio 10 10
diff --git a/sensors/2.0/default/service.cpp b/sensors/2.0/default/service.cpp
new file mode 100644
index 0000000..5c13e33
--- /dev/null
+++ b/sensors/2.0/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "android.hardware.sensors@2.0-service"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "Sensors.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_0::ISensors;
+using android::hardware::sensors::V2_0::implementation::Sensors;
+
+int main(int /* argc */, char** /* argv */) {
+ configureRpcThreadpool(1, true);
+
+ android::sp<ISensors> sensors = new Sensors();
+ if (sensors->registerAsService() != ::android::OK) {
+ ALOGE("Failed to register Sensors HAL instance");
+ return -1;
+ }
+
+ joinRpcThreadpool();
+ return 1; // joinRpcThreadpool shouldn't exit
+}
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..8e8413c
--- /dev/null
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 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.
+//
+
+cc_test {
+ name: "VtsHalSensorsV2_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "SensorsHidlEnvironmentV2_0.cpp",
+ "VtsHalSensorsV2_0TargetTest.cpp"
+ ],
+ static_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.sensors@1.0",
+ "android.hardware.sensors@2.0",
+ "libfmq",
+ "VtsHalSensorsTargetTestUtils",
+ ],
+}
+
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
new file mode 100644
index 0000000..759d87b
--- /dev/null
+++ b/sensors/2.0/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+# Sensors team
+bduddie@google.com
+bstack@google.com
+
+# VTS team
+trong@google.com
+yim@google.com
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
new file mode 100644
index 0000000..37b7349
--- /dev/null
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "SensorsHidlEnvironmentV2_0.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <vector>
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::ISensors;
+
+template <typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+ return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+constexpr size_t SensorsHidlEnvironmentV2_0::MAX_RECEIVE_BUFFER_EVENT_COUNT;
+
+bool SensorsHidlEnvironmentV2_0::resetHal() {
+ bool succeed = false;
+ do {
+ mSensors = ISensors::getService(
+ SensorsHidlEnvironmentV2_0::Instance()->getServiceName<ISensors>());
+ if (mSensors == nullptr) {
+ break;
+ }
+
+ // Initialize FMQs
+ mEventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+ true /* configureEventFlagWord */);
+
+ mWakeLockQueue = std::make_unique<WakeLockQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+ true /* configureEventFlagWord */);
+
+ if (mEventQueue == nullptr || mWakeLockQueue == nullptr) {
+ break;
+ }
+
+ EventFlag::deleteEventFlag(&mEventQueueFlag);
+ EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+ if (mEventQueueFlag == nullptr) {
+ break;
+ }
+
+ mSensors->initialize(*mEventQueue->getDesc(), *mWakeLockQueue->getDesc(),
+ nullptr /* TODO: callback */);
+
+ std::vector<SensorInfo> sensorList;
+ if (!mSensors->getSensorsList([&](const hidl_vec<SensorInfo>& list) { sensorList = list; })
+ .isOk()) {
+ break;
+ }
+
+ // stop each sensor individually
+ bool ok = true;
+ for (const auto& i : sensorList) {
+ if (!mSensors->activate(i.sensorHandle, false).isOk()) {
+ ok = false;
+ break;
+ }
+ }
+ if (!ok) {
+ break;
+ }
+
+ // mark it done
+ succeed = true;
+ } while (0);
+
+ if (!succeed) {
+ mSensors = nullptr;
+ }
+
+ return succeed;
+}
+
+void SensorsHidlEnvironmentV2_0::HidlTearDown() {
+ mStopThread = true;
+
+ // Wake up the event queue so the poll thread can exit
+ mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::READ_AND_PROCESS));
+ mPollThread.join();
+
+ EventFlag::deleteEventFlag(&mEventQueueFlag);
+}
+
+void SensorsHidlEnvironmentV2_0::startPollingThread() {
+ mStopThread = false;
+ mPollThread = std::thread(pollingThread, this);
+ mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+}
+
+void SensorsHidlEnvironmentV2_0::readEvents() {
+ size_t availableEvents = mEventQueue->availableToRead();
+
+ if (availableEvents == 0) {
+ uint32_t eventFlagState = 0;
+
+ mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS), &eventFlagState);
+ availableEvents = mEventQueue->availableToRead();
+ }
+
+ size_t eventsToRead = std::min(availableEvents, mEventBuffer.size());
+ if (eventsToRead > 0) {
+ if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
+ for (size_t i = 0; i < eventsToRead; i++) {
+ addEvent(mEventBuffer[i]);
+ }
+ }
+ }
+}
+
+void SensorsHidlEnvironmentV2_0::pollingThread(SensorsHidlEnvironmentV2_0* env) {
+ ALOGD("polling thread start");
+
+ while (!env->mStopThread.load()) {
+ env->readEvents();
+ }
+
+ ALOGD("polling thread end");
+}
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
new file mode 100644
index 0000000..5e54530
--- /dev/null
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
+#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
+
+#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <fmq/MessageQueue.h>
+#include <utils/StrongPointer.h>
+
+#include <array>
+#include <atomic>
+#include <memory>
+
+using ::android::sp;
+using ::android::hardware::MessageQueue;
+
+class SensorsHidlTest;
+class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
+ public:
+ using Event = ::android::hardware::sensors::V1_0::Event;
+ // get the test environment singleton
+ static SensorsHidlEnvironmentV2_0* Instance() {
+ static SensorsHidlEnvironmentV2_0* instance = new SensorsHidlEnvironmentV2_0();
+ return instance;
+ }
+
+ virtual void registerTestServices() override {
+ registerTestService<android::hardware::sensors::V2_0::ISensors>();
+ }
+
+ virtual void HidlTearDown() override;
+
+ protected:
+ friend SensorsHidlTest;
+
+ SensorsHidlEnvironmentV2_0() : mEventQueueFlag(nullptr) {}
+
+ /**
+ * Resets the HAL with new FMQs and a new Event Flag
+ *
+ * @return bool true if successful, false otherwise
+ */
+ bool resetHal() override;
+
+ /**
+ * Starts the polling thread that reads sensor events from the Event FMQ
+ */
+ void startPollingThread() override;
+
+ /**
+ * Thread responsible for calling functions to read Event FMQ
+ *
+ * @param env SensorEnvironment to being polling for events on
+ */
+ static void pollingThread(SensorsHidlEnvironmentV2_0* env);
+
+ /**
+ * Reads and saves sensor events from the Event FMQ
+ */
+ void readEvents();
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_0);
+
+ /**
+ * Pointer to the Sensors HAL Interface that allows the test to call HAL functions.
+ */
+ sp<android::hardware::sensors::V2_0::ISensors> mSensors;
+
+ /**
+ * Type used to simplify the creation of the Event FMQ
+ */
+ typedef MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite> EventMessageQueue;
+
+ /**
+ * Type used to simplify the creation of the Wake Lock FMQ
+ */
+ typedef MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite> WakeLockQueue;
+
+ /**
+ * The Event FMQ where the test framework is able to read sensor events that the Sensors HAL
+ * has written.
+ */
+ std::unique_ptr<EventMessageQueue> mEventQueue;
+
+ /**
+ * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed
+ * WAKE_UP sensor events.
+ */
+ std::unique_ptr<WakeLockQueue> mWakeLockQueue;
+
+ /**
+ * The Event Queue Flag notifies the test framework when sensor events have been written to the
+ * Event FMQ by the Sensors HAL.
+ */
+ ::android::hardware::EventFlag* mEventQueueFlag;
+
+ /**
+ * The maximum number of sensor events that can be read from the Event FMQ at one time.
+ */
+ static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 128;
+
+ /**
+ * An array that is used to store sensor events read from the Event FMQ
+ */
+ std::array<Event, MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+};
+
+#endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
new file mode 100644
index 0000000..ac020ad
--- /dev/null
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -0,0 +1,954 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "sensors_hidl_hal_test"
+
+#include "SensorsHidlEnvironmentV2_0.h"
+#include "sensors-vts-utils/SensorsHidlTestBase.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include <cinttypes>
+#include <condition_variable>
+#include <cstring>
+#include <map>
+#include <vector>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+using ::android::hardware::sensors::V1_0::SharedMemType;
+using ::android::hardware::sensors::V1_0::Vec3;
+
+class EventCallback : public IEventCallback {
+ public:
+ void reset() {
+ mFlushMap.clear();
+ mEventMap.clear();
+ }
+
+ void onEvent(const ::android::hardware::sensors::V1_0::Event& event) override {
+ if (event.sensorType == SensorType::ADDITIONAL_INFO &&
+ event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) {
+ std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+ mFlushMap[event.sensorHandle]++;
+ mFlushCV.notify_all();
+ } else if (event.sensorType != SensorType::ADDITIONAL_INFO) {
+ std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+ mEventMap[event.sensorHandle].push_back(event);
+ mEventCV.notify_all();
+ }
+ }
+
+ int32_t getFlushCount(int32_t sensorHandle) {
+ std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+ return mFlushMap[sensorHandle];
+ }
+
+ void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
+ int32_t numCallsToFlush, int64_t timeoutMs) {
+ std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+ mFlushCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
+ [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
+ }
+
+ const std::vector<Event> getEvents(int32_t sensorHandle) {
+ std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+ return mEventMap[sensorHandle];
+ }
+
+ void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t timeoutMs) {
+ std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+ mEventCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
+ [&] { return eventsReceived(sensorsToWaitFor); });
+ }
+
+ protected:
+ bool flushesReceived(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t numCallsToFlush) {
+ for (const SensorInfo& sensor : sensorsToWaitFor) {
+ if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool eventsReceived(const std::vector<SensorInfo>& sensorsToWaitFor) {
+ for (const SensorInfo& sensor : sensorsToWaitFor) {
+ if (getEvents(sensor.sensorHandle).size() == 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ std::map<int32_t, int32_t> mFlushMap;
+ std::recursive_mutex mFlushMutex;
+ std::condition_variable_any mFlushCV;
+
+ std::map<int32_t, std::vector<Event>> mEventMap;
+ std::recursive_mutex mEventMutex;
+ std::condition_variable_any mEventCV;
+};
+
+// The main test class for SENSORS HIDL HAL.
+
+class SensorsHidlTest : public SensorsHidlTestBase {
+ protected:
+ SensorInfo defaultSensorByType(SensorType type) override;
+ std::vector<SensorInfo> getSensorsList();
+ // implementation wrapper
+ Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override {
+ return getSensors()->getSensorsList(_hidl_cb);
+ }
+
+ Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+ Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override {
+ return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+ }
+
+ Return<Result> flush(int32_t sensorHandle) override {
+ return getSensors()->flush(sensorHandle);
+ }
+
+ Return<Result> injectSensorData(const Event& event) override {
+ return getSensors()->injectSensorData(event);
+ }
+
+ Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ ISensors::registerDirectChannel_cb _hidl_cb) override;
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+ return getSensors()->unregisterDirectChannel(channelHandle);
+ }
+
+ Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ ISensors::configDirectReport_cb _hidl_cb) override {
+ return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+ }
+
+ inline sp<::android::hardware::sensors::V2_0::ISensors>& getSensors() {
+ return SensorsHidlEnvironmentV2_0::Instance()->mSensors;
+ }
+
+ SensorsHidlEnvironmentBase* getEnvironment() override {
+ return SensorsHidlEnvironmentV2_0::Instance();
+ }
+
+ // Test helpers
+ void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t expectedFlushCount, Result expectedResponse);
+ void runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse);
+
+ // Helper functions
+ void activateAllSensors(bool enable);
+ std::vector<SensorInfo> getNonOneShotSensors();
+ std::vector<SensorInfo> getOneShotSensors();
+ std::vector<SensorInfo> getInjectEventSensors();
+ int32_t getInvalidSensorHandle();
+ void verifyDirectChannel(SharedMemType memType);
+ void verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+ std::shared_ptr<SensorsTestSharedMemory> mem,
+ int32_t* directChannelHandle);
+ void verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
+ int32_t directChannelHandle);
+ void verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+ int32_t directChannelHandle);
+ void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
+};
+
+Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
+ // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+ // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+ // check the return value of deactivation. Deactivating a sensor more than once does not have
+ // negative effect.
+ if (enabled) {
+ mSensorHandles.insert(sensorHandle);
+ }
+ return getSensors()->activate(sensorHandle, enabled);
+}
+
+Return<void> SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem,
+ ISensors::registerDirectChannel_cb cb) {
+ // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
+ // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
+ // Unregistering a channel more than once should not have negative effect.
+ getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ mDirectChannelHandles.insert(channelHandle);
+ }
+ cb(result, channelHandle);
+ });
+ return Void();
+}
+
+SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
+ SensorInfo ret;
+
+ ret.type = (SensorType)-1;
+ getSensors()->getSensorsList([&](const auto& list) {
+ const size_t count = list.size();
+ for (size_t i = 0; i < count; ++i) {
+ if (list[i].type == type) {
+ ret = list[i];
+ return;
+ }
+ }
+ });
+
+ return ret;
+}
+
+std::vector<SensorInfo> SensorsHidlTest::getSensorsList() {
+ std::vector<SensorInfo> ret;
+
+ getSensors()->getSensorsList([&](const auto& list) {
+ const size_t count = list.size();
+ ret.reserve(list.size());
+ for (size_t i = 0; i < count; ++i) {
+ ret.push_back(list[i]);
+ }
+ });
+
+ return ret;
+}
+
+std::vector<SensorInfo> SensorsHidlTest::getNonOneShotSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+std::vector<SensorInfo> SensorsHidlTest::getInjectEventSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ if (info.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION)) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+int32_t SensorsHidlTest::getInvalidSensorHandle() {
+ // Find a sensor handle that does not exist in the sensor list
+ int32_t maxHandle = 0;
+ for (const SensorInfo& sensor : getSensorsList()) {
+ maxHandle = max(maxHandle, sensor.sensorHandle);
+ }
+ return maxHandle + 1;
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, SensorListValid) {
+ getSensors()->getSensorsList([&](const auto& list) {
+ const size_t count = list.size();
+ for (size_t i = 0; i < count; ++i) {
+ const auto& s = list[i];
+ SCOPED_TRACE(::testing::Message()
+ << i << "/" << count << ": "
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+ << " name=" << s.name);
+
+ // Test non-empty type string
+ EXPECT_FALSE(s.typeAsString.empty());
+
+ // Test defined type matches defined string type
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
+
+ // Test if all sensor has name and vendor
+ EXPECT_FALSE(s.name.empty());
+ EXPECT_FALSE(s.vendor.empty());
+
+ // Test power > 0, maxRange > 0
+ EXPECT_LE(0, s.power);
+ EXPECT_LT(0, s.maxRange);
+
+ // Info type, should have no sensor
+ EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA);
+
+ // Test fifoMax >= fifoReserved
+ EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+ << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
+
+ // Test Reporting mode valid
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
+
+ // Test min max are in the right order
+ EXPECT_LE(s.minDelay, s.maxDelay);
+ // Test min/max delay matches reporting mode
+ EXPECT_NO_FATAL_FAILURE(
+ assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+ }
+ });
+}
+
+// Test that SetOperationMode returns the expected value
+TEST_F(SensorsHidlTest, SetOperationMode) {
+ std::vector<SensorInfo> sensors = getInjectEventSensors();
+ if (getInjectEventSensors().size() > 0) {
+ ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+ ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+ ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+ } else {
+ ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+ }
+}
+
+// Test that an injected event is written back to the Event FMQ
+TEST_F(SensorsHidlTest, InjectSensorEventData) {
+ std::vector<SensorInfo> sensors = getInjectEventSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+
+ ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ // AdditionalInfo event should not be sent to Event FMQ
+ Event additionalInfoEvent;
+ additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO;
+ additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
+
+ Event injectedEvent;
+ injectedEvent.timestamp = android::elapsedRealtimeNano();
+ Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+ injectedEvent.u.vec3 = data;
+
+ for (const auto& s : sensors) {
+ additionalInfoEvent.sensorHandle = s.sensorHandle;
+ EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent));
+
+ injectedEvent.sensorType = s.type;
+ injectedEvent.sensorHandle = s.sensorHandle;
+ EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent));
+ }
+
+ // Wait for events to be written back to the Event FMQ
+ callback.waitForEvents(sensors, 1000 /* timeoutMs */);
+
+ for (const auto& s : sensors) {
+ auto events = callback.getEvents(s.sensorHandle);
+ auto lastEvent = events.back();
+
+ // Verify that only a single event has been received
+ ASSERT_EQ(events.size(), 1);
+
+ // Verify that the event received matches the event injected and is not the additional
+ // info event
+ ASSERT_EQ(lastEvent.sensorType, s.type);
+ ASSERT_EQ(lastEvent.sensorType, s.type);
+ ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp);
+ ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x);
+ ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y);
+ ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z);
+ ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status);
+ }
+
+ getEnvironment()->unregisterCallback();
+ ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+}
+
+// Test if sensor hal can do UI speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
+ std::chrono::seconds(5), sAccelNormChecker);
+}
+
+// Test if sensor hal can do normal speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
+ std::chrono::seconds(5), sAccelNormChecker);
+}
+
+// Test if sensor hal can do game speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
+ std::chrono::seconds(5), sAccelNormChecker);
+}
+
+// Test if sensor hal can do UI speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+ testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
+ std::chrono::seconds(5), sGyroNormChecker);
+}
+
+// Test if sensor hal can do normal speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+ testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
+ std::chrono::seconds(5), sGyroNormChecker);
+}
+
+// Test if sensor hal can do game speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+ testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
+ std::chrono::seconds(5), sGyroNormChecker);
+}
+
+// Test if sensor hal can do UI speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
+ std::chrono::seconds(5), NullChecker());
+}
+
+// Test if sensor hal can do normal speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
+ std::chrono::seconds(5), NullChecker());
+}
+
+// Test if sensor hal can do game speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
+ std::chrono::seconds(5), NullChecker());
+}
+
+// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
+ testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
+ testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
+ testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do accelerometer batching properly
+TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+ testBatchingOperation(SensorType::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope batching properly
+TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
+ testBatchingOperation(SensorType::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer batching properly
+TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
+ testBatchingOperation(SensorType::MAGNETIC_FIELD);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at normal rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at very fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
+ RateLevel::VERY_FAST, sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at normal rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at very fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for mag sensor at normal rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at very fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
+ RateLevel::VERY_FAST, NullChecker());
+}
+
+// Test sensor event direct report with gralloc for accel sensor at normal rate
+TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for accel sensor at fast rate
+TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for accel sensor at very fast rate
+TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
+ RateLevel::VERY_FAST, sAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at normal rate
+TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at fast rate
+TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at very fast rate
+TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for mag sensor at normal rate
+TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
+ NullChecker());
+}
+
+// Test sensor event direct report with gralloc for mag sensor at fast rate
+TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
+ NullChecker());
+}
+
+// Test sensor event direct report with gralloc for mag sensor at very fast rate
+TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+ RateLevel::VERY_FAST, NullChecker());
+}
+
+void SensorsHidlTest::activateAllSensors(bool enable) {
+ for (const SensorInfo& sensorInfo : getSensorsList()) {
+ if (isValidType(sensorInfo.type)) {
+ batch(sensorInfo.sensorHandle, sensorInfo.minDelay, 0 /* maxReportLatencyNs */);
+ activate(sensorInfo.sensorHandle, enable);
+ }
+ }
+}
+
+// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second
+// call to the function.
+TEST_F(SensorsHidlTest, CallInitializeTwice) {
+ // Create a helper class so that a second environment is able to be instantiated
+ class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 {};
+
+ if (getSensorsList().size() == 0) {
+ // No sensors
+ return;
+ }
+
+ constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s
+ constexpr int32_t kNumEvents = 1;
+
+ // Create a new environment that calls initialize()
+ std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
+ std::make_unique<SensorsHidlEnvironmentTest>();
+ newEnv->HidlSetUp();
+
+ activateAllSensors(true);
+ // Verify that the old environment does not receive any events
+ ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
+ // Verify that the new event queue receives sensor events
+ ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, newEnv.get()).size(), kNumEvents);
+ activateAllSensors(false);
+
+ // Cleanup the test environment
+ newEnv->HidlTearDown();
+
+ // Restore the test environment for future tests
+ SensorsHidlEnvironmentV2_0::Instance()->HidlTearDown();
+ SensorsHidlEnvironmentV2_0::Instance()->HidlSetUp();
+
+ // Ensure that the original environment is receiving events
+ activateAllSensors(true);
+ ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+ activateAllSensors(false);
+}
+
+void SensorsHidlTest::runSingleFlushTest(const std::vector<SensorInfo>& sensors,
+ bool activateSensor, int32_t expectedFlushCount,
+ Result expectedResponse) {
+ runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse);
+}
+
+void SensorsHidlTest::runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t flushCalls, int32_t expectedFlushCount,
+ Result expectedResponse) {
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ for (const SensorInfo& sensor : sensors) {
+ // Configure and activate the sensor
+ batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */);
+ activate(sensor.sensorHandle, activateSensor);
+
+ // Flush the sensor
+ for (int32_t i = 0; i < flushCalls; i++) {
+ Result flushResult = flush(sensor.sensorHandle);
+ ASSERT_EQ(flushResult, expectedResponse);
+ }
+ activate(sensor.sensorHandle, false);
+ }
+
+ // Wait up to one second for the flush events
+ callback.waitForFlushEvents(sensors, flushCalls, 1000 /* timeoutMs */);
+ getEnvironment()->unregisterCallback();
+
+ // Check that the correct number of flushes are present for each sensor
+ for (const SensorInfo& sensor : sensors) {
+ ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
+ }
+}
+
+TEST_F(SensorsHidlTest, FlushSensor) {
+ // Find a sensor that is not a one-shot sensor
+ std::vector<SensorInfo> sensors = getNonOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+
+ constexpr int32_t kFlushes = 5;
+ runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK);
+ runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK);
+}
+
+TEST_F(SensorsHidlTest, FlushOneShotSensor) {
+ // Find a sensor that is a one-shot sensor
+ std::vector<SensorInfo> sensors = getOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+
+ runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */,
+ Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, FlushInactiveSensor) {
+ // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
+ std::vector<SensorInfo> sensors = getNonOneShotSensors();
+ if (sensors.size() == 0) {
+ sensors = getOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+ }
+
+ runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */,
+ Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, FlushNonexistentSensor) {
+ SensorInfo sensor;
+ std::vector<SensorInfo> sensors = getNonOneShotSensors();
+ if (sensors.size() == 0) {
+ sensors = getOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+ }
+ sensor = sensors.front();
+ sensor.sensorHandle = getInvalidSensorHandle();
+ runSingleFlushTest(std::vector<SensorInfo>{sensor}, false /* activateSensor */,
+ 0 /* expectedFlushCount */, Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, Batch) {
+ if (getSensorsList().size() == 0) {
+ return;
+ }
+
+ activateAllSensors(false /* enable */);
+ for (const SensorInfo& sensor : getSensorsList()) {
+ // Call batch on inactive sensor
+ ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+ Result::OK);
+
+ // Activate the sensor
+ activate(sensor.sensorHandle, true /* enabled */);
+
+ // Call batch on an active sensor
+ ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */),
+ Result::OK);
+ }
+ activateAllSensors(false /* enable */);
+
+ // Call batch on an invalid sensor
+ SensorInfo sensor = getSensorsList().front();
+ sensor.sensorHandle = getInvalidSensorHandle();
+ ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+ Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, Activate) {
+ if (getSensorsList().size() == 0) {
+ return;
+ }
+
+ // Verify that sensor events are generated when activate is called
+ for (const SensorInfo& sensor : getSensorsList()) {
+ batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */);
+ ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+ // Call activate on a sensor that is already activated
+ ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+ // Deactivate the sensor
+ ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+
+ // Call deactivate on a sensor that is already deactivated
+ ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+ }
+
+ // Attempt to activate an invalid sensor
+ int32_t invalidHandle = getInvalidSensorHandle();
+ ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE);
+ ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, NoStaleEvents) {
+ constexpr int64_t kFiveHundredMilliseconds = 500 * 1000;
+ constexpr int64_t kOneSecond = 1000 * 1000;
+
+ // Register the callback to receive sensor events
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ const std::vector<SensorInfo> sensors = getSensorsList();
+ int32_t maxMinDelay = 0;
+ for (const SensorInfo& sensor : getSensorsList()) {
+ maxMinDelay = std::max(maxMinDelay, sensor.minDelay);
+ }
+
+ // Activate the sensors so that they start generating events
+ activateAllSensors(true);
+
+ // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
+ // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
+ // of time to guarantee that a sample has arrived.
+ callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
+ activateAllSensors(false);
+
+ // Save the last received event for each sensor
+ std::map<int32_t, int64_t> lastEventTimestampMap;
+ for (const SensorInfo& sensor : sensors) {
+ ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
+ lastEventTimestampMap[sensor.sensorHandle] =
+ callback.getEvents(sensor.sensorHandle).back().timestamp;
+ }
+
+ // Allow some time to pass, reset the callback, then reactivate the sensors
+ usleep(kOneSecond + (5 * maxMinDelay));
+ callback.reset();
+ activateAllSensors(true);
+ callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
+ activateAllSensors(false);
+
+ for (const SensorInfo& sensor : sensors) {
+ // Ensure that the first event received is not stale by ensuring that its timestamp is
+ // sufficiently different from the previous event
+ const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
+ int64_t delta = newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle];
+ ASSERT_GE(delta, kFiveHundredMilliseconds + (3 * sensor.minDelay));
+ }
+
+ getEnvironment()->unregisterCallback();
+}
+
+void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
+ RateLevel rateLevel) {
+ configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel,
+ [&](Result result, int32_t reportToken) {
+ if (isDirectReportRateSupported(sensor, rateLevel)) {
+ ASSERT_EQ(result, Result::OK);
+ ASSERT_GT(reportToken, 0);
+ } else {
+ ASSERT_EQ(result, Result::BAD_VALUE);
+ }
+ });
+}
+
+void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+ std::shared_ptr<SensorsTestSharedMemory> mem,
+ int32_t* directChannelHandle) {
+ char* buffer = mem->getBuffer();
+ memset(buffer, 0xff, mem->getSize());
+
+ registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
+ if (isDirectChannelTypeSupported(sensor, memType)) {
+ ASSERT_EQ(result, Result::OK);
+ ASSERT_GT(channelHandle, 0);
+
+ // Verify that the memory has been zeroed
+ for (size_t i = 0; i < mem->getSize(); i++) {
+ ASSERT_EQ(buffer[i], 0x00);
+ }
+ } else {
+ ASSERT_EQ(result, Result::INVALID_OPERATION);
+ ASSERT_EQ(channelHandle, -1);
+ }
+ *directChannelHandle = channelHandle;
+ });
+}
+
+void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
+ int32_t directChannelHandle) {
+ if (isDirectChannelTypeSupported(sensor, memType)) {
+ // Verify that each rate level is properly supported
+ checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
+ checkRateLevel(sensor, directChannelHandle, RateLevel::FAST);
+ checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST);
+ checkRateLevel(sensor, directChannelHandle, RateLevel::STOP);
+
+ // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
+ configDirectReport(
+ -1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL,
+ [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); });
+ configDirectReport(
+ -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
+ [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
+ } else {
+ // Direct channel is not supported for this SharedMemType
+ configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
+ [](Result result, int32_t /* reportToken */) {
+ ASSERT_EQ(result, Result::INVALID_OPERATION);
+ });
+ }
+}
+
+void SensorsHidlTest::verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
+ int32_t directChannelHandle) {
+ Result result = unregisterDirectChannel(directChannelHandle);
+ if (isDirectChannelTypeSupported(sensor, memType)) {
+ ASSERT_EQ(result, Result::OK);
+ } else {
+ ASSERT_EQ(result, Result::INVALID_OPERATION);
+ }
+}
+
+void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
+ constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+ constexpr size_t kNumEvents = 1;
+ constexpr size_t kMemSize = kNumEvents * kEventSize;
+
+ std::shared_ptr<SensorsTestSharedMemory> mem(
+ SensorsTestSharedMemory::create(memType, kMemSize));
+ ASSERT_NE(mem, nullptr);
+
+ for (const SensorInfo& sensor : getSensorsList()) {
+ int32_t directChannelHandle = 0;
+ verifyRegisterDirectChannel(sensor, memType, mem, &directChannelHandle);
+ verifyConfigure(sensor, memType, directChannelHandle);
+ verifyUnregisterDirectChannel(sensor, memType, directChannelHandle);
+ }
+}
+
+TEST_F(SensorsHidlTest, DirectChannelAshmem) {
+ verifyDirectChannel(SharedMemType::ASHMEM);
+}
+
+TEST_F(SensorsHidlTest, DirectChannelGralloc) {
+ verifyDirectChannel(SharedMemType::GRALLOC);
+}
+
+TEST_F(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
+ for (const SensorInfo& sensor : getSensorsList()) {
+ if (isDirectChannelTypeSupported(sensor, SharedMemType::ASHMEM) ||
+ isDirectChannelTypeSupported(sensor, SharedMemType::GRALLOC)) {
+ // Find a supported rate level
+ RateLevel rate = RateLevel::STOP;
+ if (isDirectReportRateSupported(sensor, RateLevel::NORMAL)) {
+ rate = RateLevel::NORMAL;
+ } else if (isDirectReportRateSupported(sensor, RateLevel::FAST)) {
+ rate = RateLevel::FAST;
+ } else if (isDirectReportRateSupported(sensor, RateLevel::VERY_FAST)) {
+ rate = RateLevel::VERY_FAST;
+ }
+
+ // Ensure that at least one rate level is supported
+ ASSERT_NE(rate, RateLevel::STOP);
+
+ // Verify that an invalid channel handle produces a BAD_VALUE result
+ configDirectReport(sensor.sensorHandle, -1, rate,
+ [](Result result, int32_t /* reportToken */) {
+ ASSERT_EQ(result, Result::BAD_VALUE);
+ });
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV2_0::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ SensorsHidlEnvironmentV2_0::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
+// vim: set ts=2 sw=2
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 6c25e47..95df425 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -19,6 +19,8 @@
srcs: [
"GrallocWrapper.cpp",
"SensorsHidlEnvironmentBase.cpp",
+ "SensorsHidlTestBase.cpp",
+ "SensorsTestSharedMemory.cpp",
],
export_include_dirs: [
"include",
@@ -33,4 +35,3 @@
"VtsHalHidlTargetTestBase",
],
}
-
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
new file mode 100644
index 0000000..759d87b
--- /dev/null
+++ b/sensors/common/vts/utils/OWNERS
@@ -0,0 +1,7 @@
+# Sensors team
+bduddie@google.com
+bstack@google.com
+
+# VTS team
+trong@google.com
+yim@google.com
diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
index 21c08d2..affdf8b 100644
--- a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
+++ b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
@@ -19,7 +19,7 @@
void SensorsHidlEnvironmentBase::HidlSetUp() {
ASSERT_TRUE(resetHal()) << "could not get hidl service";
- collectionEnabled = false;
+ mCollectionEnabled = false;
startPollingThread();
// In case framework just stopped for test and there is sensor events in the pipe,
@@ -28,26 +28,40 @@
}
void SensorsHidlEnvironmentBase::HidlTearDown() {
- stopThread = true;
- pollThread.detach();
+ mStopThread = true;
+ mPollThread.detach();
}
void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {
- std::lock_guard<std::mutex> lock(events_mutex);
+ std::lock_guard<std::mutex> lock(mEventsMutex);
if (output) {
- output->insert(output->end(), events.begin(), events.end());
+ output->insert(output->end(), mEvents.begin(), mEvents.end());
}
- events.clear();
+ mEvents.clear();
}
void SensorsHidlEnvironmentBase::setCollection(bool enable) {
- std::lock_guard<std::mutex> lock(events_mutex);
- collectionEnabled = enable;
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ mCollectionEnabled = enable;
}
void SensorsHidlEnvironmentBase::addEvent(const Event& ev) {
- std::lock_guard<std::mutex> lock(events_mutex);
- if (collectionEnabled) {
- events.push_back(ev);
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ if (mCollectionEnabled) {
+ mEvents.push_back(ev);
+ }
+
+ if (mCallback != nullptr) {
+ mCallback->onEvent(ev);
}
}
+
+void SensorsHidlEnvironmentBase::registerCallback(IEventCallback* callback) {
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ mCallback = callback;
+}
+
+void SensorsHidlEnvironmentBase::unregisterCallback() {
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ mCallback = nullptr;
+}
\ No newline at end of file
diff --git a/sensors/common/vts/utils/SensorsHidlTestBase.cpp b/sensors/common/vts/utils/SensorsHidlTestBase.cpp
new file mode 100644
index 0000000..18549df
--- /dev/null
+++ b/sensors/common/vts/utils/SensorsHidlTestBase.cpp
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "SensorsHidlTestBase.h"
+
+#include "sensors-vts-utils/GrallocWrapper.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.h"
+
+#include <hardware/sensors.h> // for sensor type strings
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include <cinttypes>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::SensorFlagShift;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
+
+const Vec3NormChecker SensorsHidlTestBase::sAccelNormChecker(
+ Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f /*m/s^2*/));
+const Vec3NormChecker SensorsHidlTestBase::sGyroNormChecker(
+ Vec3NormChecker::byNominal(0.f, 0.1f /*rad/s*/));
+
+std::vector<Event> SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+ bool clearBeforeStart,
+ bool changeCollection) {
+ return collectEvents(timeLimitUs, nEventLimit, getEnvironment(), clearBeforeStart,
+ changeCollection);
+}
+
+std::vector<Event> SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+ SensorsHidlEnvironmentBase* environment,
+ bool clearBeforeStart,
+ bool changeCollection) {
+ std::vector<Event> events;
+ constexpr useconds_t SLEEP_GRANULARITY = 100 * 1000; // granularity 100 ms
+
+ ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", nEventLimit, timeLimitUs,
+ clearBeforeStart);
+
+ if (changeCollection) {
+ environment->setCollection(true);
+ }
+ if (clearBeforeStart) {
+ environment->catEvents(nullptr);
+ }
+
+ while (timeLimitUs > 0) {
+ useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
+ usleep(duration);
+ timeLimitUs -= duration;
+
+ environment->catEvents(&events);
+ if (events.size() >= nEventLimit) {
+ break;
+ }
+ ALOGV("time to go = %d, events to go = %d", (int)timeLimitUs,
+ (int)(nEventLimit - events.size()));
+ }
+
+ if (changeCollection) {
+ environment->setCollection(false);
+ }
+ return events;
+}
+
+void SensorsHidlTestBase::assertTypeMatchStringType(SensorType type,
+ const hidl_string& stringType) {
+ if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+ return;
+ }
+
+ switch (type) {
+#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
+ case SensorType::type: \
+ ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \
+ break;
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
+ default:
+ FAIL() << "Type " << static_cast<int>(type)
+ << " in android defined range is not checked, "
+ << "stringType = " << stringType;
+#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
+ }
+}
+
+void SensorsHidlTestBase::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
+ if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+ return;
+ }
+
+ SensorFlagBits expected = expectedReportModeForType(type);
+
+ ASSERT_TRUE(expected == (SensorFlagBits)-1 || expected == reportMode)
+ << "reportMode=" << static_cast<int>(reportMode)
+ << "expected=" << static_cast<int>(expected);
+}
+
+void SensorsHidlTestBase::assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay,
+ SensorFlagBits reportMode) {
+ switch (reportMode) {
+ case SensorFlagBits::CONTINUOUS_MODE:
+ ASSERT_LT(0, minDelay);
+ ASSERT_LE(0, maxDelay);
+ break;
+ case SensorFlagBits::ON_CHANGE_MODE:
+ ASSERT_LE(0, minDelay);
+ ASSERT_LE(0, maxDelay);
+ break;
+ case SensorFlagBits::ONE_SHOT_MODE:
+ ASSERT_EQ(-1, minDelay);
+ ASSERT_EQ(0, maxDelay);
+ break;
+ case SensorFlagBits::SPECIAL_REPORTING_MODE:
+ // do not enforce anything for special reporting mode
+ break;
+ default:
+ FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
+ }
+}
+
+// return -1 means no expectation for this type
+SensorFlagBits SensorsHidlTestBase::expectedReportModeForType(SensorType type) {
+ switch (type) {
+ case SensorType::ACCELEROMETER:
+ case SensorType::ACCELEROMETER_UNCALIBRATED:
+ case SensorType::GYROSCOPE:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::PRESSURE:
+ case SensorType::TEMPERATURE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION:
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GAME_ROTATION_VECTOR:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+ case SensorType::POSE_6DOF:
+ case SensorType::HEART_BEAT:
+ return SensorFlagBits::CONTINUOUS_MODE;
+
+ case SensorType::LIGHT:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::HEART_RATE:
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::STEP_COUNTER:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+ return SensorFlagBits::ON_CHANGE_MODE;
+
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::MOTION_DETECT:
+ case SensorType::STATIONARY_DETECT:
+ return SensorFlagBits::ONE_SHOT_MODE;
+
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::DYNAMIC_SENSOR_META:
+ return SensorFlagBits::SPECIAL_REPORTING_MODE;
+
+ default:
+ ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
+ return (SensorFlagBits)-1;
+ }
+}
+
+bool SensorsHidlTestBase::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
+ unsigned int r = static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) >>
+ static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
+ return r >= static_cast<unsigned int>(rate);
+}
+
+bool SensorsHidlTestBase::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
+ switch (type) {
+ case SharedMemType::ASHMEM:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
+ case SharedMemType::GRALLOC:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
+ default:
+ return false;
+ }
+}
+
+void SensorsHidlTestBase::testDirectReportOperation(SensorType type, SharedMemType memType,
+ RateLevel rate,
+ const SensorEventsChecker& checker) {
+ constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+ constexpr size_t kNEvent = 4096;
+ constexpr size_t kMemSize = kEventSize * kNEvent;
+
+ constexpr float kNormalNominal = 50;
+ constexpr float kFastNominal = 200;
+ constexpr float kVeryFastNominal = 800;
+
+ constexpr float kNominalTestTimeSec = 1.f;
+ constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isValidType(sensor.type)) {
+ // no default sensor of this type
+ return;
+ }
+
+ if (!isDirectReportRateSupported(sensor, rate)) {
+ return;
+ }
+
+ if (!isDirectChannelTypeSupported(sensor, memType)) {
+ return;
+ }
+
+ std::unique_ptr<SensorsTestSharedMemory> mem(
+ SensorsTestSharedMemory::create(memType, kMemSize));
+ ASSERT_NE(mem, nullptr);
+
+ char* buffer = mem->getBuffer();
+ // fill memory with data
+ for (size_t i = 0; i < kMemSize; ++i) {
+ buffer[i] = '\xcc';
+ }
+
+ int32_t channelHandle;
+ registerDirectChannel(mem->getSharedMemInfo(),
+ [&channelHandle](auto result, auto channelHandle_) {
+ ASSERT_EQ(result, Result::OK);
+ channelHandle = channelHandle_;
+ });
+
+ // check memory is zeroed
+ for (size_t i = 0; i < kMemSize; ++i) {
+ ASSERT_EQ(buffer[i], '\0');
+ }
+
+ int32_t eventToken;
+ configDirectReport(sensor.sensorHandle, channelHandle, rate,
+ [&eventToken](auto result, auto token) {
+ ASSERT_EQ(result, Result::OK);
+ eventToken = token;
+ });
+
+ usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
+ auto events = mem->parseEvents();
+
+ // find norminal rate
+ float nominalFreq = 0.f;
+ switch (rate) {
+ case RateLevel::NORMAL:
+ nominalFreq = kNormalNominal;
+ break;
+ case RateLevel::FAST:
+ nominalFreq = kFastNominal;
+ break;
+ case RateLevel::VERY_FAST:
+ nominalFreq = kVeryFastNominal;
+ break;
+ case RateLevel::STOP:
+ FAIL();
+ }
+
+ // allowed to be between 55% and 220% of nominal freq
+ ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
+ ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
+
+ int64_t lastTimestamp = 0;
+ bool typeErrorReported = false;
+ bool tokenErrorReported = false;
+ bool timestampErrorReported = false;
+ std::vector<Event> sensorEvents;
+ for (auto& e : events) {
+ if (!tokenErrorReported) {
+ EXPECT_EQ(eventToken, e.sensorHandle)
+ << (tokenErrorReported = true,
+ "Event token does not match that retured from configDirectReport");
+ }
+
+ if (isMetaSensorType(e.sensorType)) {
+ continue;
+ }
+ sensorEvents.push_back(e);
+
+ if (!typeErrorReported) {
+ EXPECT_EQ(type, e.sensorType)
+ << (typeErrorReported = true,
+ "Type in event does not match type of sensor registered.");
+ }
+ if (!timestampErrorReported) {
+ EXPECT_GT(e.timestamp, lastTimestamp)
+ << (timestampErrorReported = true, "Timestamp not monotonically increasing");
+ }
+ lastTimestamp = e.timestamp;
+ }
+
+ std::string s;
+ EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
+
+ // stop sensor and unregister channel
+ configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
+ [](auto result, auto) { EXPECT_EQ(result, Result::OK); });
+ EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+}
+
+void SensorsHidlTestBase::testStreamingOperation(SensorType type,
+ std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration,
+ const SensorEventsChecker& checker) {
+ std::vector<Event> events;
+ std::vector<Event> sensorEvents;
+
+ const int64_t samplingPeriodInNs = samplingPeriod.count();
+ const int64_t batchingPeriodInNs = 0; // no batching
+ const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
+ const size_t minNEvent = duration / samplingPeriod;
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isValidType(sensor.type)) {
+ // no default sensor of this type
+ return;
+ }
+
+ if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
+ // rate not supported
+ return;
+ }
+
+ int32_t handle = sensor.sensorHandle;
+
+ ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
+ ASSERT_EQ(activate(handle, 1), Result::OK);
+ events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
+ ASSERT_EQ(activate(handle, 0), Result::OK);
+
+ ALOGI("Collected %zu samples", events.size());
+
+ ASSERT_GT(events.size(), 0u);
+
+ bool handleMismatchReported = false;
+ bool metaSensorTypeErrorReported = false;
+ for (auto& e : events) {
+ if (e.sensorType == type) {
+ // avoid generating hundreds of error
+ if (!handleMismatchReported) {
+ EXPECT_EQ(e.sensorHandle, handle)
+ << (handleMismatchReported = true,
+ "Event of the same type must come from the sensor registered");
+ }
+ sensorEvents.push_back(e);
+ } else {
+ // avoid generating hundreds of error
+ if (!metaSensorTypeErrorReported) {
+ EXPECT_TRUE(isMetaSensorType(e.sensorType))
+ << (metaSensorTypeErrorReported = true,
+ "Only meta types are allowed besides the type registered");
+ }
+ }
+ }
+
+ std::string s;
+ EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
+
+ EXPECT_GE(sensorEvents.size(),
+ minNEvent / 2); // make sure returned events are not all meta
+}
+
+void SensorsHidlTestBase::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) {
+ std::vector<Event> events1, events2;
+
+ constexpr int64_t batchingPeriodInNs = 0; // no batching
+ constexpr int64_t collectionTimeoutUs = 60000000; // 60s
+ constexpr size_t minNEvent = 50;
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isValidType(sensor.type)) {
+ // no default sensor of this type
+ return;
+ }
+
+ int32_t handle = sensor.sensorHandle;
+ int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+ int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll;
+
+ if (minSamplingPeriodInNs == maxSamplingPeriodInNs) {
+ // only support single rate
+ return;
+ }
+
+ int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
+ int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
+
+ // first collection
+ ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK);
+ ASSERT_EQ(activate(handle, 1), Result::OK);
+
+ usleep(500000); // sleep 0.5 sec to wait for change rate to happen
+ events1 = collectEvents(collectionTimeoutUs, minNEvent);
+
+ // second collection, without stop sensor
+ ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
+
+ usleep(500000); // sleep 0.5 sec to wait for change rate to happen
+ events2 = collectEvents(collectionTimeoutUs, minNEvent);
+
+ // end of collection, stop sensor
+ ASSERT_EQ(activate(handle, 0), Result::OK);
+
+ ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
+
+ ASSERT_GT(events1.size(), 0u);
+ ASSERT_GT(events2.size(), 0u);
+
+ int64_t minDelayAverageInterval, maxDelayAverageInterval;
+ std::vector<Event>& minDelayEvents(fastToSlow ? events1 : events2);
+ std::vector<Event>& maxDelayEvents(fastToSlow ? events2 : events1);
+
+ size_t nEvent = 0;
+ int64_t prevTimestamp = -1;
+ int64_t timestampInterval = 0;
+ for (auto& e : minDelayEvents) {
+ if (e.sensorType == type) {
+ ASSERT_EQ(e.sensorHandle, handle);
+ if (prevTimestamp > 0) {
+ timestampInterval += e.timestamp - prevTimestamp;
+ }
+ prevTimestamp = e.timestamp;
+ ++nEvent;
+ }
+ }
+ ASSERT_GT(nEvent, 2u);
+ minDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+ nEvent = 0;
+ prevTimestamp = -1;
+ timestampInterval = 0;
+ for (auto& e : maxDelayEvents) {
+ if (e.sensorType == type) {
+ ASSERT_EQ(e.sensorHandle, handle);
+ if (prevTimestamp > 0) {
+ timestampInterval += e.timestamp - prevTimestamp;
+ }
+ prevTimestamp = e.timestamp;
+ ++nEvent;
+ }
+ }
+ ASSERT_GT(nEvent, 2u);
+ maxDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+ // change of rate is significant.
+ ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, minDelayAverageInterval,
+ maxDelayAverageInterval);
+ EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
+
+ // fastest rate sampling time is close to spec
+ EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+ minSamplingPeriodInNs / 10);
+
+ // slowest rate sampling time is close to spec
+ EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
+ maxSamplingPeriodInNs / 10);
+}
+
+void SensorsHidlTestBase::testBatchingOperation(SensorType type) {
+ std::vector<Event> events;
+
+ constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
+ constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isValidType(sensor.type)) {
+ // no default sensor of this type
+ return;
+ }
+
+ int32_t handle = sensor.sensorHandle;
+ int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+ uint32_t minFifoCount = sensor.fifoReservedEventCount;
+ int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs;
+
+ if (batchingPeriodInNs < oneSecondInNs) {
+ // batching size too small to test reliably
+ return;
+ }
+
+ batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs);
+
+ ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000));
+
+ int64_t allowedBatchDeliverTimeNs = std::max(oneSecondInNs, batchingPeriodInNs / 10);
+
+ ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
+ ASSERT_EQ(activate(handle, 1), Result::OK);
+
+ usleep(500000); // sleep 0.5 sec to wait for initialization
+ ASSERT_EQ(flush(handle), Result::OK);
+
+ // wait for 80% of the reserved batching period
+ // there should not be any significant amount of events
+ // since collection is not enabled all events will go down the drain
+ usleep(batchingPeriodInNs / 1000 * 8 / 10);
+
+ getEnvironment()->setCollection(true);
+ // clean existing collections
+ collectEvents(0 /*timeLimitUs*/, 0 /*nEventLimit*/, true /*clearBeforeStart*/,
+ false /*change collection*/);
+
+ // 0.8 + 0.2 times the batching period
+ usleep(batchingPeriodInNs / 1000 * 8 / 10);
+ ASSERT_EQ(flush(handle), Result::OK);
+
+ // plus some time for the event to deliver
+ events = collectEvents(allowedBatchDeliverTimeNs / 1000, minFifoCount,
+ false /*clearBeforeStart*/, false /*change collection*/);
+
+ getEnvironment()->setCollection(false);
+ ASSERT_EQ(activate(handle, 0), Result::OK);
+
+ size_t nEvent = 0;
+ for (auto& e : events) {
+ if (e.sensorType == type && e.sensorHandle == handle) {
+ ++nEvent;
+ }
+ }
+
+ // at least reach 90% of advertised capacity
+ ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10));
+}
diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
new file mode 100644
index 0000000..819e297
--- /dev/null
+++ b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "SensorsTestSharedMemory.h"
+
+#include <log/log.h>
+
+#include <sys/mman.h>
+#include <cinttypes>
+
+using namespace ::android::hardware::sensors::V1_0;
+
+SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
+ SharedMemInfo mem = {.type = mType,
+ .format = SharedMemFormat::SENSORS_EVENT,
+ .size = static_cast<uint32_t>(mSize),
+ .memoryHandle = mNativeHandle};
+ return mem;
+}
+
+char* SensorsTestSharedMemory::getBuffer() const {
+ return mBuffer;
+}
+
+size_t SensorsTestSharedMemory::getSize() const {
+ return mSize;
+}
+
+std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
+ constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+ constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
+ constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
+ constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
+ constexpr size_t kOffsetAtomicCounter =
+ static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
+ constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
+ constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
+
+ std::vector<Event> events;
+ std::vector<float> data(16);
+
+ while (offset + kEventSize <= mSize) {
+ int64_t atomicCounter =
+ *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter);
+ if (atomicCounter <= lastCounter) {
+ ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter,
+ lastCounter);
+ break;
+ }
+
+ int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize);
+ if (size != kEventSize) {
+ // unknown error, events parsed may be wrong, remove all
+ events.clear();
+ break;
+ }
+
+ int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken);
+ int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType);
+ int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp);
+
+ ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32
+ ", timestamp %" PRId64,
+ offset, atomicCounter, token, type, timestamp);
+
+ Event event = {
+ .timestamp = timestamp,
+ .sensorHandle = token,
+ .sensorType = static_cast<SensorType>(type),
+ };
+ event.u.data = android::hardware::hidl_array<float, 16>(
+ reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
+
+ events.push_back(event);
+
+ lastCounter = atomicCounter;
+ offset += kEventSize;
+ }
+
+ return events;
+}
+
+SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
+ : mType(type), mSize(0), mBuffer(nullptr) {
+ native_handle_t* handle = nullptr;
+ char* buffer = nullptr;
+ switch (type) {
+ case SharedMemType::ASHMEM: {
+ int fd;
+ handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/);
+ if (handle != nullptr) {
+ handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
+ if (handle->data[0] > 0) {
+ // memory is pinned by default
+ buffer = static_cast<char*>(
+ ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+ if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
+ break;
+ }
+ ::native_handle_close(handle);
+ }
+ ::native_handle_delete(handle);
+ handle = nullptr;
+ }
+ break;
+ }
+ case SharedMemType::GRALLOC: {
+ mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
+ if (mGrallocWrapper->getAllocator() == nullptr ||
+ mGrallocWrapper->getMapper() == nullptr) {
+ break;
+ }
+ using android::hardware::graphics::common::V1_0::BufferUsage;
+ using android::hardware::graphics::common::V1_0::PixelFormat;
+ mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
+ .width = static_cast<uint32_t>(size),
+ .height = 1,
+ .layerCount = 1,
+ .usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA |
+ BufferUsage::CPU_READ_OFTEN),
+ .format = PixelFormat::BLOB};
+
+ handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info));
+ if (handle != nullptr) {
+ mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width),
+ static_cast<int32_t>(buf_desc_info.height)};
+ buffer = static_cast<char*>(
+ mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
+ if (buffer != nullptr) {
+ break;
+ }
+ mGrallocWrapper->freeBuffer(handle);
+ handle = nullptr;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (buffer != nullptr) {
+ mNativeHandle = handle;
+ mSize = size;
+ mBuffer = buffer;
+ }
+}
+
+SensorsTestSharedMemory::~SensorsTestSharedMemory() {
+ switch (mType) {
+ case SharedMemType::ASHMEM: {
+ if (mSize != 0) {
+ ::munmap(mBuffer, mSize);
+ mBuffer = nullptr;
+
+ ::native_handle_close(mNativeHandle);
+ ::native_handle_delete(mNativeHandle);
+
+ mNativeHandle = nullptr;
+ mSize = 0;
+ }
+ break;
+ }
+ case SharedMemType::GRALLOC: {
+ if (mSize != 0) {
+ mGrallocWrapper->unlock(mNativeHandle);
+ mGrallocWrapper->freeBuffer(mNativeHandle);
+
+ mNativeHandle = nullptr;
+ mSize = 0;
+ }
+ break;
+ }
+ default: {
+ if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
+ ALOGE(
+ "SensorsTestSharedMemory %p not properly destructed: "
+ "type %d, native handle %p, size %zu, buffer %p",
+ this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+ }
+ break;
+ }
+ }
+}
+
+SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) {
+ constexpr size_t kMaxSize = 128 * 1024 * 1024; // sensor test should not need more than 128M
+ if (size == 0 || size >= kMaxSize) {
+ return nullptr;
+ }
+
+ auto m = new SensorsTestSharedMemory(type, size);
+ if (m->mSize != size || m->mBuffer == nullptr) {
+ delete m;
+ m = nullptr;
+ }
+ return m;
+}
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
index 4a6f713..6499fba 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
@@ -27,11 +27,17 @@
#include <thread>
#include <vector>
+class IEventCallback {
+ public:
+ virtual ~IEventCallback() = default;
+ virtual void onEvent(const ::android::hardware::sensors::V1_0::Event& event) = 0;
+};
+
class SensorsHidlEnvironmentBase : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
using Event = ::android::hardware::sensors::V1_0::Event;
- void HidlSetUp() override;
- void HidlTearDown() override;
+ virtual void HidlSetUp() override;
+ virtual void HidlTearDown() override;
// Get and clear all events collected so far (like "cat" shell command).
// If output is nullptr, it clears all collected events.
@@ -40,19 +46,24 @@
// set sensor event collection status
void setCollection(bool enable);
+ void registerCallback(IEventCallback* callback);
+ void unregisterCallback();
+
protected:
- SensorsHidlEnvironmentBase() {}
+ SensorsHidlEnvironmentBase() : mCollectionEnabled(false), mCallback(nullptr) {}
void addEvent(const Event& ev);
virtual void startPollingThread() = 0;
virtual bool resetHal() = 0;
- bool collectionEnabled;
- std::atomic_bool stopThread;
- std::thread pollThread;
- std::vector<Event> events;
- std::mutex events_mutex;
+ bool mCollectionEnabled;
+ std::atomic_bool mStopThread;
+ std::thread mPollThread;
+ std::vector<Event> mEvents;
+ std::mutex mEventsMutex;
+
+ IEventCallback* mCallback;
GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
};
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
new file mode 100644
index 0000000..6fd9a2b
--- /dev/null
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SENSORS_HIDL_TEST_BASE_H
+#define ANDROID_SENSORS_HIDL_TEST_BASE_H
+
+#include "sensors-vts-utils/SensorEventsChecker.h"
+#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <unordered_set>
+#include <vector>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::ISensors;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V1_0::SharedMemType;
+
+class SensorsHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual SensorsHidlEnvironmentBase* getEnvironment() = 0;
+ virtual void SetUp() override {}
+
+ virtual void TearDown() override {
+ // stop all sensors
+ for (auto s : mSensorHandles) {
+ activate(s, false);
+ }
+ mSensorHandles.clear();
+
+ // stop all direct report and channels
+ for (auto c : mDirectChannelHandles) {
+ // disable all reports
+ configDirectReport(-1, c, RateLevel::STOP, [](auto, auto) {});
+ unregisterDirectChannel(c);
+ }
+ mDirectChannelHandles.clear();
+ }
+
+ // implementation wrapper
+ virtual SensorInfo defaultSensorByType(SensorType type) = 0;
+ virtual Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) = 0;
+
+ virtual Return<Result> activate(int32_t sensorHandle, bool enabled) = 0;
+
+ virtual Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) = 0;
+
+ virtual Return<Result> flush(int32_t sensorHandle) = 0;
+ virtual Return<Result> injectSensorData(const Event& event) = 0;
+ virtual Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ ISensors::registerDirectChannel_cb _hidl_cb) = 0;
+ virtual Return<Result> unregisterDirectChannel(int32_t channelHandle) = 0;
+ virtual Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+ RateLevel rate,
+ ISensors::configDirectReport_cb _hidl_cb) = 0;
+
+ std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+ bool clearBeforeStart = true, bool changeCollection = true);
+ static std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+ SensorsHidlEnvironmentBase* environment,
+ bool clearBeforeStart = true,
+ bool changeCollection = true);
+
+ inline static SensorFlagBits extractReportMode(uint64_t flag) {
+ return (SensorFlagBits)(flag & ((uint64_t)SensorFlagBits::CONTINUOUS_MODE |
+ (uint64_t)SensorFlagBits::ON_CHANGE_MODE |
+ (uint64_t)SensorFlagBits::ONE_SHOT_MODE |
+ (uint64_t)SensorFlagBits::SPECIAL_REPORTING_MODE));
+ }
+
+ inline static bool isMetaSensorType(SensorType type) {
+ return (type == SensorType::META_DATA || type == SensorType::DYNAMIC_SENSOR_META ||
+ type == SensorType::ADDITIONAL_INFO);
+ }
+
+ inline static bool isValidType(SensorType type) { return (int32_t)type > 0; }
+
+ void testStreamingOperation(SensorType type, std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration, const SensorEventsChecker& checker);
+ void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true);
+ void testBatchingOperation(SensorType type);
+ void testDirectReportOperation(SensorType type, SharedMemType memType, RateLevel rate,
+ const SensorEventsChecker& checker);
+
+ static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
+ static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
+ static void assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay,
+ SensorFlagBits reportMode);
+ static SensorFlagBits expectedReportModeForType(SensorType type);
+ static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
+ static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
+
+ protected:
+ // checkers
+ static const Vec3NormChecker sAccelNormChecker;
+ static const Vec3NormChecker sGyroNormChecker;
+
+ // all sensors and direct channnels used
+ std::unordered_set<int32_t> mSensorHandles;
+ std::unordered_set<int32_t> mDirectChannelHandles;
+};
+
+#endif // ANDROID_SENSORS_HIDL_TEST_BASE_H
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
new file mode 100644
index 0000000..002f42c
--- /dev/null
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SENSORS_TEST_SHARED_MEMORY_H
+#define ANDROID_SENSORS_TEST_SHARED_MEMORY_H
+
+#include "GrallocWrapper.h"
+
+#include <android-base/macros.h>
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <cutils/ashmem.h>
+
+class SensorsTestSharedMemory {
+ using SharedMemType = ::android::hardware::sensors::V1_0::SharedMemType;
+ using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+ using Event = ::android::hardware::sensors::V1_0::Event;
+
+ public:
+ static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
+ SharedMemInfo getSharedMemInfo() const;
+ char* getBuffer() const;
+ size_t getSize() const;
+ std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
+ virtual ~SensorsTestSharedMemory();
+
+ private:
+ SensorsTestSharedMemory(SharedMemType type, size_t size);
+
+ SharedMemType mType;
+ native_handle_t* mNativeHandle;
+ size_t mSize;
+ char* mBuffer;
+ std::unique_ptr<::android::GrallocWrapper> mGrallocWrapper;
+
+ DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
+};
+
+#endif // ANDROID_SENSORS_TEST_SHARED_MEMORY_H
diff --git a/soundtrigger/2.2/Android.bp b/soundtrigger/2.2/Android.bp
new file mode 100644
index 0000000..0a7c2d8
--- /dev/null
+++ b/soundtrigger/2.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.soundtrigger@2.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "ISoundTriggerHw.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@2.0",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
+
diff --git a/soundtrigger/2.2/ISoundTriggerHw.hal b/soundtrigger/2.2/ISoundTriggerHw.hal
new file mode 100644
index 0000000..a26896a
--- /dev/null
+++ b/soundtrigger/2.2/ISoundTriggerHw.hal
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.hardware.soundtrigger@2.2;
+
+import @2.0::SoundModelHandle;
+import @2.1::ISoundTriggerHw;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords
+ * and other sounds.
+ */
+interface ISoundTriggerHw extends @2.1::ISoundTriggerHw {
+
+ /**
+ * Get the state of a given model.
+ * The model state is returned asynchronously as a RecognitionEvent via
+ * the callback that was registered in StartRecognition().
+ * @param modelHandle The handle of the sound model whose state is being
+ * queried.
+ * @return retval Operation completion status: 0 in case of success,
+ * -ENOSYS in case of invalid model handle,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error,
+ * -EINVAL in case where a recognition event is already
+ * being processed.
+ */
+ getModelState(SoundModelHandle modelHandle) generates (int32_t retval);
+};
diff --git a/soundtrigger/2.2/default/Android.bp b/soundtrigger/2.2/default/Android.bp
new file mode 100644
index 0000000..78bb69f
--- /dev/null
+++ b/soundtrigger/2.2/default/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 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.
+
+cc_library_shared {
+ name: "android.hardware.soundtrigger@2.2-impl",
+ relative_install_path: "hw",
+ vendor: true,
+ srcs: [
+ "SoundTriggerHw.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libhidlmemory",
+ "libutils",
+ "libhardware",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.0-core",
+ "android.hardware.soundtrigger@2.1",
+ "android.hardware.soundtrigger@2.2",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ ],
+}
diff --git a/soundtrigger/2.2/default/SoundTriggerHw.cpp b/soundtrigger/2.2/default/SoundTriggerHw.cpp
new file mode 100644
index 0000000..9d930ac
--- /dev/null
+++ b/soundtrigger/2.2/default/SoundTriggerHw.cpp
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SoundTriggerHw"
+
+#include "SoundTriggerHw.h"
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/log.h>
+#include <hidlmemory/mapping.h>
+#include <utility>
+
+using android::hardware::hidl_memory;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_2 {
+namespace implementation {
+
+/**
+ * According to the HIDL C++ Users Guide: client and server implementations
+ * should never directly refer to anything other than the interface header
+ * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so
+ * this V2_2 implementation copies the V2_0 and V2_1 implementations and
+ * then adds the new V2_2 implementation.
+ */
+
+// Begin V2_0 implementation, copied from
+// hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+
+// static
+void soundModelCallback_(struct sound_trigger_model_event* halEvent, void* cookie) {
+ if (halEvent == NULL) {
+ ALOGW("soundModelCallback called with NULL event");
+ return;
+ }
+ sp<SoundTriggerHw::SoundModelClient> client =
+ wp<SoundTriggerHw::SoundModelClient>(static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
+ .promote();
+ if (client == 0) {
+ ALOGW("soundModelCallback called on stale client");
+ return;
+ }
+ if (halEvent->model != client->getHalHandle()) {
+ ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
+ (int)halEvent->model, (int)client->getHalHandle());
+ return;
+ }
+
+ client->soundModelCallback(halEvent);
+}
+
+// static
+void recognitionCallback_(struct sound_trigger_recognition_event* halEvent, void* cookie) {
+ if (halEvent == NULL) {
+ ALOGW("recognitionCallback call NULL event");
+ return;
+ }
+ sp<SoundTriggerHw::SoundModelClient> client =
+ wp<SoundTriggerHw::SoundModelClient>(static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
+ .promote();
+ if (client == 0) {
+ ALOGW("recognitionCallback called on stale client");
+ return;
+ }
+
+ client->recognitionCallback(halEvent);
+}
+
+Return<void> SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) {
+ ALOGV("getProperties() mHwDevice %p", mHwDevice);
+ int ret;
+ struct sound_trigger_properties halProperties;
+ ISoundTriggerHw::Properties properties;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ ret = mHwDevice->get_properties(mHwDevice, &halProperties);
+
+ convertPropertiesFromHal(&properties, &halProperties);
+
+ ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(),
+ properties.recognitionModes);
+
+exit:
+ _hidl_cb(ret, properties);
+ return Void();
+}
+
+int SoundTriggerHw::doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ sp<SoundTriggerHw::SoundModelClient> client) {
+ int32_t ret = 0;
+ struct sound_trigger_sound_model* halSoundModel;
+
+ ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ halSoundModel = convertSoundModelToHal(&soundModel);
+ if (halSoundModel == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ sound_model_handle_t halHandle;
+ ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback_, client.get(),
+ &halHandle);
+
+ free(halSoundModel);
+
+ if (ret != 0) {
+ goto exit;
+ }
+
+ client->setHalHandle(halHandle);
+ {
+ AutoMutex lock(mLock);
+ mClients.add(client->getId(), client);
+ }
+
+exit:
+ return ret;
+}
+
+Return<void> SoundTriggerHw::loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadSoundModel_cb _hidl_cb) {
+ sp<SoundTriggerHw::SoundModelClient> client =
+ new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel(soundModel, client), client->getId());
+ return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel(
+ const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) {
+ sp<SoundTriggerHw::SoundModelClient> client =
+ new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel, client),
+ client->getId());
+ return Void();
+}
+
+Return<int32_t> SoundTriggerHw::unloadSoundModel(int32_t modelHandle) {
+ int32_t ret;
+ sp<SoundTriggerHw::SoundModelClient> client;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle());
+
+ mClients.removeItem(modelHandle);
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition(
+ int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_0::ISoundTriggerHwCallback>& /* callback */, int32_t /* cookie */) {
+ int32_t ret;
+ sp<SoundTriggerHw::SoundModelClient> client;
+ struct sound_trigger_recognition_config* halConfig;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ halConfig =
+ convertRecognitionConfigToHal((const V2_0::ISoundTriggerHw::RecognitionConfig*)&config);
+
+ if (halConfig == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,
+ recognitionCallback_, client.get());
+
+ free(halConfig);
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHw::stopRecognition(int32_t modelHandle) {
+ int32_t ret;
+ sp<SoundTriggerHw::SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle());
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHw::stopAllRecognitions() {
+ int32_t ret;
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
+ mHwDevice->stop_all_recognitions) {
+ ret = mHwDevice->stop_all_recognitions(mHwDevice);
+ } else {
+ ret = -ENOSYS;
+ }
+exit:
+ return ret;
+}
+
+SoundTriggerHw::SoundTriggerHw() : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {}
+
+void SoundTriggerHw::onFirstRef() {
+ const hw_module_t* mod;
+ int rc;
+
+ rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
+ if (rc != 0) {
+ ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID,
+ mModuleName, strerror(-rc));
+ return;
+ }
+ rc = sound_trigger_hw_device_open(mod, &mHwDevice);
+ if (rc != 0) {
+ ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+ mHwDevice = NULL;
+ return;
+ }
+ if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
+ mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+ ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
+ sound_trigger_hw_device_close(mHwDevice);
+ mHwDevice = NULL;
+ return;
+ }
+
+ ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
+}
+
+SoundTriggerHw::~SoundTriggerHw() {
+ if (mHwDevice != NULL) {
+ sound_trigger_hw_device_close(mHwDevice);
+ }
+}
+
+uint32_t SoundTriggerHw::nextUniqueModelId() {
+ uint32_t modelId = 0;
+ {
+ AutoMutex lock(mLock);
+ do {
+ modelId =
+ atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1, memory_order_acq_rel);
+ } while (mClients.valueFor(modelId) != 0 && modelId != 0);
+ }
+ LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu",
+ mClients.size());
+ return modelId;
+}
+
+void SoundTriggerHw::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) {
+ uuid->timeLow = halUuid->timeLow;
+ uuid->timeMid = halUuid->timeMid;
+ uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
+ uuid->variantAndClockSeqHigh = halUuid->clockSeq;
+ memcpy(&uuid->node[0], &halUuid->node[0], 6);
+}
+
+void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) {
+ halUuid->timeLow = uuid->timeLow;
+ halUuid->timeMid = uuid->timeMid;
+ halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
+ halUuid->clockSeq = uuid->variantAndClockSeqHigh;
+ memcpy(&halUuid->node[0], &uuid->node[0], 6);
+}
+
+void SoundTriggerHw::convertPropertiesFromHal(
+ ISoundTriggerHw::Properties* properties, const struct sound_trigger_properties* halProperties) {
+ properties->implementor = halProperties->implementor;
+ properties->description = halProperties->description;
+ properties->version = halProperties->version;
+ convertUuidFromHal(&properties->uuid, &halProperties->uuid);
+ properties->maxSoundModels = halProperties->max_sound_models;
+ properties->maxKeyPhrases = halProperties->max_key_phrases;
+ properties->maxUsers = halProperties->max_users;
+ properties->recognitionModes = halProperties->recognition_modes;
+ properties->captureTransition = halProperties->capture_transition;
+ properties->maxBufferMs = halProperties->max_buffer_ms;
+ properties->concurrentCapture = halProperties->concurrent_capture;
+ properties->triggerInEvent = halProperties->trigger_in_event;
+ properties->powerConsumptionMw = halProperties->power_consumption_mw;
+}
+
+void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+ const ISoundTriggerHw::Phrase* triggerPhrase) {
+ halTriggerPhrase->id = triggerPhrase->id;
+ halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
+ unsigned int i;
+
+ halTriggerPhrase->num_users =
+ std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS);
+ for (i = 0; i < halTriggerPhrase->num_users; i++) {
+ halTriggerPhrase->users[i] = triggerPhrase->users[i];
+ }
+
+ strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
+ strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+}
+
+struct sound_trigger_sound_model* SoundTriggerHw::convertSoundModelToHal(
+ const V2_0::ISoundTriggerHw::SoundModel* soundModel) {
+ struct sound_trigger_sound_model* halModel = NULL;
+ if (soundModel->type == V2_0::SoundModelType::KEYPHRASE) {
+ size_t allocSize =
+ sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
+ struct sound_trigger_phrase_sound_model* halKeyPhraseModel =
+ static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize));
+ LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
+ "malloc failed for size %zu in convertSoundModelToHal PHRASE",
+ allocSize);
+
+ const ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
+ reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel*>(soundModel);
+
+ size_t i;
+ for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+ convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]);
+ }
+ halKeyPhraseModel->num_phrases = (unsigned int)i;
+ halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel);
+ halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
+ } else {
+ size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
+ halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize));
+ LOG_ALWAYS_FATAL_IF(halModel == NULL,
+ "malloc failed for size %zu in convertSoundModelToHal GENERIC",
+ allocSize);
+
+ halModel->data_offset = sizeof(struct sound_trigger_sound_model);
+ }
+ halModel->type = (sound_trigger_sound_model_type_t)soundModel->type;
+ convertUuidToHal(&halModel->uuid, &soundModel->uuid);
+ convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
+ halModel->data_size = soundModel->data.size();
+ uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset;
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]);
+ memcpy(dst, src, soundModel->data.size());
+
+ return halModel;
+}
+
+void SoundTriggerHw::convertPhraseRecognitionExtraToHal(
+ struct sound_trigger_phrase_recognition_extra* halExtra,
+ const V2_0::PhraseRecognitionExtra* extra) {
+ halExtra->id = extra->id;
+ halExtra->recognition_modes = extra->recognitionModes;
+ halExtra->confidence_level = extra->confidenceLevel;
+
+ unsigned int i;
+ for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
+ halExtra->levels[i].user_id = extra->levels[i].userId;
+ halExtra->levels[i].level = extra->levels[i].levelPercent;
+ }
+ halExtra->num_levels = i;
+}
+
+struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfigToHal(
+ const V2_0::ISoundTriggerHw::RecognitionConfig* config) {
+ size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
+ struct sound_trigger_recognition_config* halConfig =
+ static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize));
+
+ LOG_ALWAYS_FATAL_IF(halConfig == NULL,
+ "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize);
+
+ halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
+ halConfig->capture_device = (audio_devices_t)config->captureDevice;
+ halConfig->capture_requested = config->captureRequested;
+
+ unsigned int i;
+ for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+ convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]);
+ }
+ halConfig->num_phrases = i;
+
+ halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
+ halConfig->data_size = config->data.size();
+ uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset;
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]);
+ memcpy(dst, src, config->data.size());
+ return halConfig;
+}
+
+// static
+void SoundTriggerHw::convertSoundModelEventFromHal(
+ V2_0::ISoundTriggerHwCallback::ModelEvent* event,
+ const struct sound_trigger_model_event* halEvent) {
+ event->status = (V2_0::ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
+ // event->model to be remapped by called
+ event->data.setToExternal(
+ const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+ halEvent->data_size);
+}
+
+// static
+void SoundTriggerHw::convertPhaseRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+ const struct sound_trigger_phrase_recognition_event* halEvent) {
+ event->phraseExtras.resize(halEvent->num_phrases);
+ for (unsigned int i = 0; i < halEvent->num_phrases; i++) {
+ convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]);
+ }
+ convertRecognitionEventFromHal(&event->common, &halEvent->common);
+}
+
+// static
+void SoundTriggerHw::convertRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::RecognitionEvent* event,
+ const struct sound_trigger_recognition_event* halEvent) {
+ event->status = static_cast<V2_0::ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
+ event->type = static_cast<V2_0::SoundModelType>(halEvent->type);
+ // event->model to be remapped by called
+ event->captureAvailable = halEvent->capture_available;
+ event->captureSession = halEvent->capture_session;
+ event->captureDelayMs = halEvent->capture_delay_ms;
+ event->capturePreambleMs = halEvent->capture_preamble_ms;
+ event->triggerInData = halEvent->trigger_in_data;
+ event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
+ event->audioConfig.channelMask =
+ (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
+ event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
+ event->data.setToExternal(
+ const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+ halEvent->data_size);
+}
+
+// static
+void SoundTriggerHw::convertPhraseRecognitionExtraFromHal(
+ V2_0::PhraseRecognitionExtra* extra,
+ const struct sound_trigger_phrase_recognition_extra* halExtra) {
+ extra->id = halExtra->id;
+ extra->recognitionModes = halExtra->recognition_modes;
+ extra->confidenceLevel = halExtra->confidence_level;
+
+ extra->levels.resize(halExtra->num_levels);
+ for (unsigned int i = 0; i < halExtra->num_levels; i++) {
+ extra->levels[i].userId = halExtra->levels[i].user_id;
+ extra->levels[i].levelPercent = halExtra->levels[i].level;
+ }
+}
+
+void SoundTriggerHw::SoundModelClient_2_0::recognitionCallback(
+ struct sound_trigger_recognition_event* halEvent) {
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+ convertPhaseRecognitionEventFromHal(
+ &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+ event.common.model = mId;
+ mCallback->phraseRecognitionCallback(event, mCookie);
+ } else {
+ V2_0::ISoundTriggerHwCallback::RecognitionEvent event;
+ convertRecognitionEventFromHal(&event, halEvent);
+ event.model = mId;
+ mCallback->recognitionCallback(event, mCookie);
+ }
+}
+
+void SoundTriggerHw::SoundModelClient_2_0::soundModelCallback(
+ struct sound_trigger_model_event* halEvent) {
+ V2_0::ISoundTriggerHwCallback::ModelEvent event;
+ convertSoundModelEventFromHal(&event, halEvent);
+ event.model = mId;
+ mCallback->soundModelCallback(event, mCookie);
+}
+
+// Begin V2_1 implementation, copied from
+// hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.cpp
+
+namespace {
+
+// Backs up by the vector with the contents of shared memory.
+// It is assumed that the passed hidl_vector is empty, so it's
+// not cleared if the memory is a null object.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
+ sp<IMemory> memory;
+ if (m.size() == 0) {
+ return std::make_pair(true, memory);
+ }
+ memory = mapMemory(m);
+ if (memory != nullptr) {
+ memory->read();
+ vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
+ memory->getSize());
+ return std::make_pair(true, memory);
+ }
+ ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
+ return std::make_pair(false, memory);
+}
+
+// Moves the data from the vector into allocated shared memory,
+// emptying the vector.
+// It is assumed that the passed hidl_memory is a null object, so it's
+// not reset if the vector is empty.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
+ sp<IMemory> memory;
+ if (v->size() == 0) {
+ return std::make_pair(true, memory);
+ }
+ sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+ if (ashmem == 0) {
+ ALOGE("Failed to retrieve ashmem allocator service");
+ return std::make_pair(false, memory);
+ }
+ bool success = false;
+ Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
+ success = s;
+ if (success) *mem = m;
+ });
+ if (r.isOk() && success) {
+ memory = hardware::mapMemory(*mem);
+ if (memory != 0) {
+ memory->update();
+ memcpy(memory->getPointer(), v->data(), v->size());
+ memory->commit();
+ v->resize(0);
+ return std::make_pair(true, memory);
+ } else {
+ ALOGE("Failed to map allocated ashmem");
+ }
+ } else {
+ ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
+ }
+ return std::make_pair(false, memory);
+}
+
+} // namespace
+
+Return<void> SoundTriggerHw::loadSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) {
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header);
+ auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data);
+ if (result.first) {
+ sp<SoundModelClient> client =
+ new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId());
+ return Void();
+ }
+ _hidl_cb(-ENOMEM, 0);
+ return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) {
+ V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0;
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ soundModel_2_0.common = soundModel.common.header;
+ // Avoid copying phrases data.
+ soundModel_2_0.phrases.setToExternal(
+ const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()),
+ soundModel.phrases.size());
+ auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data);
+ if (result.first) {
+ sp<SoundModelClient> client =
+ new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client),
+ client->getId());
+ return Void();
+ }
+ _hidl_cb(-ENOMEM, 0);
+ return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_1(
+ int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie) {
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header);
+ auto result = memoryAsVector(config.data, &config_2_0.data);
+ return result.first ? startRecognition(modelHandle, config_2_0, callback, cookie)
+ : Return<int32_t>(-ENOMEM);
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback(
+ struct sound_trigger_recognition_event* halEvent) {
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
+ convertPhaseRecognitionEventFromHal(
+ &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+ event_2_0.common.model = mId;
+ V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+ event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(),
+ event_2_0.phraseExtras.size());
+ auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data);
+ if (result.first) {
+ // The data vector is now empty, thus copying is cheap.
+ event.common.header = event_2_0.common;
+ mCallback->phraseRecognitionCallback_2_1(event, mCookie);
+ }
+ } else {
+ V2_1::ISoundTriggerHwCallback::RecognitionEvent event;
+ convertRecognitionEventFromHal(&event.header, halEvent);
+ event.header.model = mId;
+ auto result = moveVectorToMemory(&event.header.data, &event.data);
+ if (result.first) {
+ mCallback->recognitionCallback_2_1(event, mCookie);
+ }
+ }
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback(
+ struct sound_trigger_model_event* halEvent) {
+ V2_1::ISoundTriggerHwCallback::ModelEvent event;
+ convertSoundModelEventFromHal(&event.header, halEvent);
+ event.header.model = mId;
+ auto result = moveVectorToMemory(&event.header.data, &event.data);
+ if (result.first) {
+ mCallback->soundModelCallback_2_1(event, mCookie);
+ }
+}
+
+// Begin V2_2 implementation
+
+Return<int32_t> SoundTriggerHw::getModelState(int32_t modelHandle) {
+ sp<SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ return -ENOSYS;
+ }
+ }
+
+ if (mHwDevice->get_model_state == NULL) {
+ ALOGE("Failed to get model state from device, no such method");
+ return -ENODEV;
+ }
+
+ return mHwDevice->get_model_state(mHwDevice, client->getHalHandle());
+}
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
+ return new SoundTriggerHw();
+}
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
diff --git a/soundtrigger/2.2/default/SoundTriggerHw.h b/soundtrigger/2.2/default/SoundTriggerHw.h
new file mode 100644
index 0000000..6676318
--- /dev/null
+++ b/soundtrigger/2.2/default/SoundTriggerHw.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H
+
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
+#include <hardware/sound_trigger.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <stdatomic.h>
+#include <system/sound_trigger.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_2 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V2_0::Uuid;
+using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+
+/**
+ * According to the HIDL C++ Users Guide: client and server implementations
+ * should never directly refer to anything other than the interface header
+ * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so
+ * this V2_2 implementation copies the V2_0 and V2_1 implementations and
+ * then adds the new V2_2 implementation.
+ */
+struct SoundTriggerHw : public ISoundTriggerHw {
+ // Methods from V2_0::ISoundTriggerHw follow.
+ Return<void> getProperties(getProperties_cb _hidl_cb) override;
+ Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ loadSoundModel_cb _hidl_cb) override;
+ Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ int32_t cookie, loadPhraseSoundModel_cb _hidl_cb) override;
+ Return<int32_t> unloadSoundModel(int32_t modelHandle) override;
+ Return<int32_t> startRecognition(int32_t modelHandle,
+ const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ int32_t cookie) override;
+ Return<int32_t> stopRecognition(int32_t modelHandle) override;
+ Return<int32_t> stopAllRecognitions() override;
+
+ // Methods from V2_1::ISoundTriggerHw follow.
+ Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override;
+ Return<void> loadPhraseSoundModel_2_1(const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie,
+ loadPhraseSoundModel_2_1_cb _hidl_cb) override;
+ Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+ const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie) override;
+
+ // Methods from V2_2::ISoundTriggerHw follow.
+ Return<int32_t> getModelState(int32_t modelHandle) override;
+
+ SoundTriggerHw();
+
+ // Copied from hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+ class SoundModelClient : public RefBase {
+ public:
+ SoundModelClient(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie)
+ : mId(id), mCookie(cookie) {}
+ virtual ~SoundModelClient() {}
+
+ uint32_t getId() const { return mId; }
+ sound_model_handle_t getHalHandle() const { return mHalHandle; }
+ void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; }
+
+ virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0;
+ virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0;
+
+ protected:
+ const uint32_t mId;
+ sound_model_handle_t mHalHandle;
+ V2_0::ISoundTriggerHwCallback::CallbackCookie mCookie;
+ };
+
+ protected:
+ static void convertPhaseRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+ const struct sound_trigger_phrase_recognition_event* halEvent);
+ static void convertRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::RecognitionEvent* event,
+ const struct sound_trigger_recognition_event* halEvent);
+ static void convertSoundModelEventFromHal(V2_0::ISoundTriggerHwCallback::ModelEvent* event,
+ const struct sound_trigger_model_event* halEvent);
+
+ virtual ~SoundTriggerHw();
+
+ uint32_t nextUniqueModelId();
+ int doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ sp<SoundModelClient> client);
+
+ // RefBase
+ void onFirstRef() override;
+
+ private:
+ class SoundModelClient_2_0 : public SoundModelClient {
+ public:
+ SoundModelClient_2_0(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+ sp<V2_0::ISoundTriggerHwCallback> callback)
+ : SoundModelClient(id, cookie), mCallback(callback) {}
+
+ void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+ void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+ private:
+ sp<V2_0::ISoundTriggerHwCallback> mCallback;
+ };
+
+ void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid);
+ void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid);
+ void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties,
+ const struct sound_trigger_properties* halProperties);
+ void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+ const V2_0::ISoundTriggerHw::Phrase* triggerPhrase);
+ // returned HAL sound model must be freed by caller
+ struct sound_trigger_sound_model* convertSoundModelToHal(
+ const V2_0::ISoundTriggerHw::SoundModel* soundModel);
+ void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra,
+ const V2_0::PhraseRecognitionExtra* extra);
+ // returned recognition config must be freed by caller
+ struct sound_trigger_recognition_config* convertRecognitionConfigToHal(
+ const V2_0::ISoundTriggerHw::RecognitionConfig* config);
+
+ static void convertPhraseRecognitionExtraFromHal(
+ V2_0::PhraseRecognitionExtra* extra,
+ const struct sound_trigger_phrase_recognition_extra* halExtra);
+
+ static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie);
+ static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie);
+
+ const char* mModuleName;
+ struct sound_trigger_hw_device* mHwDevice;
+ volatile atomic_uint_fast32_t mNextModelId;
+ DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients;
+ Mutex mLock;
+
+ // Copied from hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.h
+ class SoundModelClient_2_1 : public SoundModelClient {
+ public:
+ SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie,
+ sp<V2_1::ISoundTriggerHwCallback> callback)
+ : SoundModelClient(id, cookie), mCallback(callback) {}
+
+ void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+ void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+ private:
+ sp<V2_1::ISoundTriggerHwCallback> mCallback;
+ };
+};
+
+extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name);
+
+} // namespace implementation
+} // namespace V2_2
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H
diff --git a/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
new file mode 100644
index 0000000..0f37816
--- /dev/null
+++ b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SoundTriggerHidlHalTest"
+#include <stdlib.h>
+#include <time.h>
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+#include <log/log.h>
+
+#include <android/hardware/audio/common/2.0/types.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
+using ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
+
+// Test environment for SoundTrigger HIDL HAL.
+class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static SoundTriggerHidlEnvironment* Instance() {
+ static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
+ return instance;
+ }
+
+ void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
+
+ private:
+ SoundTriggerHidlEnvironment() {}
+};
+
+// The main test class for Sound Trigger HIDL HAL.
+class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void SetUp() override {
+ mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
+ SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
+ ASSERT_NE(nullptr, mSoundTriggerHal.get());
+ }
+
+ static void SetUpTestCase() { srand(1234); }
+
+ void TearDown() override {}
+
+ protected:
+ sp<ISoundTriggerHw> mSoundTriggerHal;
+};
+
+/**
+ * Test ISoundTriggerHw::getModelState() method
+ *
+ * Verifies that:
+ * - the implementation returns -ENOSYS with invalid model handle
+ *
+ */
+TEST_F(SoundTriggerHidlTest, GetModelStateInvalidModel) {
+ SoundModelHandle handle = 0;
+ Return<int32_t> hidlReturn = mSoundTriggerHal->getModelState(handle);
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(-ENOSYS, hidlReturn);
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/tests/expression/1.0/IExpression.hal b/tests/expression/1.0/IExpression.hal
index 2db9f61..36aed60 100644
--- a/tests/expression/1.0/IExpression.hal
+++ b/tests/expression/1.0/IExpression.hal
@@ -147,6 +147,28 @@
logand4 = (0 && 1) == 0,
};
+ // Tests for enum tags
+ enum NoElements : uint32_t {};
+ enum OneElement : uint32_t {A};
+ enum TwoElement : uint32_t {A,B};
+ enum TwoCollidingElements : uint32_t {A=1,B=1};
+ enum ThreeFromInheritance : TwoElement {C};
+ enum ThreeFromDoubleInheritance : ThreeFromInheritance {};
+ enum ThreeCollidingFromInheritance : TwoCollidingElements {C};
+
+ enum EnumTagTest : uint32_t {
+ a = NoElements#len == 0,
+ b = OneElement#len == 1,
+ c = TwoElement#len == 2,
+ d = TwoCollidingElements#len == 2,
+ e = ThreeFromInheritance#len == 3,
+ f = ThreeFromDoubleInheritance#len == 3,
+ g = ThreeCollidingFromInheritance#len == 3,
+
+ // fine to reference current enum as well
+ h = EnumTagTest#len == 8,
+ };
+
enum Grayscale : int8_t {
WHITE = 126,
GRAY, // 127
diff --git a/tests/foo/1.0/IFoo.hal b/tests/foo/1.0/IFoo.hal
index f54994f..4c54427 100644
--- a/tests/foo/1.0/IFoo.hal
+++ b/tests/foo/1.0/IFoo.hal
@@ -122,7 +122,14 @@
};
struct WithFmq {
- fmq_sync<uint8_t> descSync;
+ struct ScatterGather {
+ fmq_sync<uint8_t> descSync;
+ } scatterGathered;
+
+ struct ContainsPointer {
+ fmq_sync<uint8_t> descSync;
+ interface foo;
+ } containsPointer;
};
enum Discriminator : uint8_t {
diff --git a/tests/safeunion/1.0/Android.bp b/tests/safeunion/1.0/Android.bp
index ede8401..87edd53 100644
--- a/tests/safeunion/1.0/Android.bp
+++ b/tests/safeunion/1.0/Android.bp
@@ -9,6 +9,7 @@
],
interfaces: [
"android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
],
gen_java: true,
}
diff --git a/tests/safeunion/1.0/ISafeUnion.hal b/tests/safeunion/1.0/ISafeUnion.hal
index f48248b..58c08c6 100644
--- a/tests/safeunion/1.0/ISafeUnion.hal
+++ b/tests/safeunion/1.0/ISafeUnion.hal
@@ -18,6 +18,8 @@
import IOtherInterface;
+import android.hidl.safe_union@1.0::Monostate;
+
interface ISafeUnion {
enum BitField : uint8_t {
@@ -33,14 +35,15 @@
string j3;
};
- safe_union EmptySafeUnion {
- };
-
safe_union SmallSafeUnion {
+ Monostate noinit;
+
uint8_t a;
};
safe_union LargeSafeUnion {
+ Monostate noinit;
+
int8_t a;
uint16_t b;
int32_t c;
@@ -66,6 +69,8 @@
};
safe_union InterfaceTypeSafeUnion {
+ Monostate noinit;
+
uint32_t a;
int8_t[7] b;
IOtherInterface c;
@@ -76,6 +81,8 @@
};
safe_union HandleTypeSafeUnion {
+ Monostate noinit;
+
handle a;
handle[5] b;
vec<handle> c;
diff --git a/tests/safeunion/cpp/1.0/.hidl_for_test b/tests/safeunion/cpp/1.0/.hidl_for_test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/safeunion/cpp/1.0/.hidl_for_test
diff --git a/tests/safeunion/cpp/1.0/Android.bp b/tests/safeunion/cpp/1.0/Android.bp
new file mode 100644
index 0000000..1111719
--- /dev/null
+++ b/tests/safeunion/cpp/1.0/Android.bp
@@ -0,0 +1,14 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.tests.safeunion.cpp@1.0",
+ root: "android.hardware",
+ srcs: [
+ "ICppSafeUnion.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
+
diff --git a/tests/safeunion/cpp/1.0/ICppSafeUnion.hal b/tests/safeunion/cpp/1.0/ICppSafeUnion.hal
new file mode 100644
index 0000000..cc1a91e
--- /dev/null
+++ b/tests/safeunion/cpp/1.0/ICppSafeUnion.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.tests.safeunion.cpp@1.0;
+
+/**
+ * Safe union for cpp-only types.
+ */
+interface ICppSafeUnion {
+ safe_union PointerFmqSafeUnion {
+ interface iface;
+ fmq_sync<uint8_t> fmqSync;
+ fmq_unsync<uint8_t> fmqUnsync;
+ };
+ safe_union FmqSafeUnion {
+ fmq_sync<uint8_t> fmqSync;
+ fmq_unsync<uint8_t> fmqUnsync;
+ };
+
+ repeatPointerFmqSafeUnion(PointerFmqSafeUnion fmq) generates (PointerFmqSafeUnion fmq);
+ repeatFmqSafeUnion(FmqSafeUnion fmq) generates (FmqSafeUnion fmq);
+};
diff --git a/tests/safeunion/cpp/1.0/default/Android.bp b/tests/safeunion/cpp/1.0/default/Android.bp
new file mode 100644
index 0000000..210a639
--- /dev/null
+++ b/tests/safeunion/cpp/1.0/default/Android.bp
@@ -0,0 +1,22 @@
+cc_library {
+ name: "android.hardware.tests.safeunion.cpp@1.0-impl",
+ relative_install_path: "hw",
+ srcs: [
+ "CppSafeUnion.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ ],
+
+ // These are static libs only for testing purposes and portability. Shared
+ // libs should be used on device.
+ static_libs: [
+ "android.hardware.tests.safeunion.cpp@1.0",
+ ],
+}
diff --git a/tests/safeunion/cpp/1.0/default/CppSafeUnion.cpp b/tests/safeunion/cpp/1.0/default/CppSafeUnion.cpp
new file mode 100644
index 0000000..dcbd9d7
--- /dev/null
+++ b/tests/safeunion/cpp/1.0/default/CppSafeUnion.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "CppSafeUnion.h"
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace safeunion {
+namespace cpp {
+namespace V1_0 {
+namespace implementation {
+
+Return<void> CppSafeUnion::repeatPointerFmqSafeUnion(const ICppSafeUnion::PointerFmqSafeUnion& fmq,
+ repeatPointerFmqSafeUnion_cb _hidl_cb) {
+ _hidl_cb(fmq);
+ return Void();
+}
+
+Return<void> CppSafeUnion::repeatFmqSafeUnion(const ICppSafeUnion::FmqSafeUnion& fmq,
+ repeatFmqSafeUnion_cb _hidl_cb) {
+ _hidl_cb(fmq);
+ return Void();
+}
+
+ICppSafeUnion* HIDL_FETCH_ICppSafeUnion(const char* /* name */) {
+ return new CppSafeUnion();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cpp
+} // namespace safeunion
+} // namespace tests
+} // namespace hardware
+} // namespace android
diff --git a/tests/safeunion/cpp/1.0/default/CppSafeUnion.h b/tests/safeunion/cpp/1.0/default/CppSafeUnion.h
new file mode 100644
index 0000000..a128273
--- /dev/null
+++ b/tests/safeunion/cpp/1.0/default/CppSafeUnion.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 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 <android/hardware/tests/safeunion/cpp/1.0/ICppSafeUnion.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace safeunion {
+namespace cpp {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct CppSafeUnion : public ICppSafeUnion {
+ Return<void> repeatPointerFmqSafeUnion(const ICppSafeUnion::PointerFmqSafeUnion& fmq,
+ repeatPointerFmqSafeUnion_cb _hidl_cb) override;
+ Return<void> repeatFmqSafeUnion(const ICppSafeUnion::FmqSafeUnion& fmq,
+ repeatFmqSafeUnion_cb _hidl_cb) override;
+};
+
+extern "C" ICppSafeUnion* HIDL_FETCH_ICppSafeUnion(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cpp
+} // namespace safeunion
+} // namespace tests
+} // namespace hardware
+} // namespace android
diff --git a/thermal/2.0/Android.bp b/thermal/2.0/Android.bp
new file mode 100644
index 0000000..6eb4da0
--- /dev/null
+++ b/thermal/2.0/Android.bp
@@ -0,0 +1,29 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.thermal@2.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IThermal.hal",
+ "IThermalChangedCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.thermal@1.0",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "CoolingDevice",
+ "CoolingType",
+ "Temperature",
+ "TemperatureThreshold",
+ "TemperatureType",
+ "ThrottlingSeverity",
+ "ThrottlingSeverityCount",
+ ],
+ gen_java: true,
+}
+
diff --git a/thermal/2.0/IThermal.hal b/thermal/2.0/IThermal.hal
new file mode 100644
index 0000000..f890694
--- /dev/null
+++ b/thermal/2.0/IThermal.hal
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 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.
+ */
+package android.hardware.thermal@2.0;
+
+import android.hardware.thermal@1.0::IThermal;
+import android.hardware.thermal@1.0::ThermalStatus;
+import IThermalChangedCallback;
+
+interface IThermal extends @1.0::IThermal {
+
+ /**
+ * Retrieves temperatures in Celsius.
+ *
+ * @param filterType whether to filter the result for a given type.
+ * @param type the TemperatureType such as battery or skin.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with a human-readable
+ * error message.
+ *
+ * @return temperatures If status code is SUCCESS, it's filled with the
+ * current temperatures. The order of temperatures of built-in
+ * devices (such as CPUs, GPUs and etc.) in the list must be kept
+ * the same regardless of the number of calls to this method even if
+ * they go offline, if these devices exist on boot. The method
+ * always returns and never removes such temperatures.
+ */
+ getCurrentTemperatures(bool filterType, TemperatureType type)
+ generates (ThermalStatus status, vec<Temperature> temperatures);
+
+ /**
+ * Retrieves static temperature thresholds in Celsius.
+ *
+ * @param filterType whether to filter the result for a given type.
+ * @param type the TemperatureType such as battery or skin.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with a human-readable error message.
+ * @return temperatureThresholds If status code is SUCCESS, it's filled with the
+ * temperatures thresholds. The order of temperatures of built-in
+ * devices (such as CPUs, GPUs and etc.) in the list must be kept
+ * the same regardless of the number of calls to this method even if
+ * they go offline, if these devices exist on boot. The method
+ * always returns and never removes such temperatures. The thresholds
+ * are returned as static values and must not change across calls. The actual
+ * throttling state is determined in driver and HAL and must not be simply
+ * compared with these thresholds. To get accurate throttling status, use
+ * getCurrentTemperatures or registerThermalChangedCallback and listen.
+ */
+ getTemperatureThresholds(bool filterType, TemperatureType type)
+ generates (ThermalStatus status, vec<TemperatureThreshold> temperatureThresholds);
+
+ /**
+ * Register an IThermalChangedCallback, used by the Thermal HAL
+ * to send thermal events when thermal mitigation status changed.
+ * Multiple registrations with different IThermalChangedCallback must be allowed.
+ * Multiple registrations with same IThermalChangedCallback is not allowed, client
+ * should unregister the given IThermalChangedCallback first.
+ *
+ * @param callback the IThermalChangedCallback to use for sending
+ * thermal events (cannot be nullptr).
+ * @param filterType if filter for given sensor type.
+ * @param type the type to be filtered.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with a human-readable error message.
+ */
+ registerThermalChangedCallback(IThermalChangedCallback callback,
+ bool filterType,
+ TemperatureType type)
+ generates (ThermalStatus status);
+
+ /**
+ * Register an IThermalChangedCallback, used by the Thermal HAL
+ * to send thermal events when thermal mitigation status changed.
+ *
+ * @param callback the IThermalChangedCallback to use for sending
+ * thermal events, or nullptr to set no callback.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with a human-readable error message.
+ */
+ unregisterThermalChangedCallback(IThermalChangedCallback callback)
+ generates (ThermalStatus status);
+
+ /**
+ * Retrieves the cooling devices information.
+ *
+ * @param filterType whether to filter the result for a given type.
+ * @param type the CoolingDevice such as CPU/GPU.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with the human-readable
+ * error message.
+ * @return devices If status code is SUCCESS, it's filled with the current
+ * cooling device information. The order of built-in cooling
+ * devices in the list must be kept the same regardless of the number
+ * of calls to this method even if they go offline, if these devices
+ * exist on boot. The method always returns and never removes from
+ * the list such cooling devices.
+ */
+ getCurrentCoolingDevices(bool filterType, CoolingType type)
+ generates (ThermalStatus status, vec<CoolingDevice> devices);
+};
diff --git a/thermal/2.0/IThermalChangedCallback.hal b/thermal/2.0/IThermalChangedCallback.hal
new file mode 100644
index 0000000..b06bfbf
--- /dev/null
+++ b/thermal/2.0/IThermalChangedCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.thermal@2.0;
+
+import android.hardware.thermal@2.0::Temperature;
+
+/**
+ * IThermalChangedCallback send throttling notification to clients.
+ */
+interface IThermalChangedCallback {
+ /**
+ * Send a thermal throttling event to all ThermalHAL
+ * thermal event listeners.
+ *
+ * @param temperature The temperature associated with the
+ * throttling event.
+ */
+ oneway notifyThrottling (Temperature temperature);
+};
diff --git a/thermal/2.0/default/Android.bp b/thermal/2.0/default/Android.bp
new file mode 100644
index 0000000..f620e6e
--- /dev/null
+++ b/thermal/2.0/default/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 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.
+
+cc_binary {
+ name: "android.hardware.thermal@2.0-service",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.thermal@2.0-service.rc"],
+ vintf_fragments: ["android.hardware.thermal@2.0-service.xml"],
+ srcs: [
+ "Thermal.cpp",
+ "service.cpp"
+ ],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "android.hardware.thermal@2.0",
+ "android.hardware.thermal@1.0",
+ ],
+}
diff --git a/thermal/2.0/default/Thermal.cpp b/thermal/2.0/default/Thermal.cpp
new file mode 100644
index 0000000..442af61
--- /dev/null
+++ b/thermal/2.0/default/Thermal.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "android.hardware.thermal@2.0-service-mock"
+
+#include <cmath>
+#include <set>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Thermal.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::interfacesEqual;
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::thermal::V1_0::ThermalStatusCode;
+
+std::set<sp<IThermalChangedCallback>> gCallbacks;
+
+static const Temperature_1_0 kTemp_1_0 = {
+ .type = static_cast<::android::hardware::thermal::V1_0::TemperatureType>(TemperatureType::CPU),
+ .name = "test temperature sensor",
+ .currentValue = 98.6,
+ .throttlingThreshold = 58,
+ .shutdownThreshold = 60.0,
+ .vrThrottlingThreshold = 59.0,
+};
+
+static const Temperature_2_0 kTemp_2_0 = {
+ .type = TemperatureType::SKIN,
+ .name = "test temperature sensor",
+ .value = 98.6,
+ .throttlingStatus = ThrottlingSeverity::CRITICAL,
+};
+
+static const TemperatureThreshold kTempThreshold = {
+ .type = TemperatureType::SKIN,
+ .name = "test temperature sensor",
+ .hotThrottlingThresholds = {{NAN, NAN, NAN, NAN, NAN, NAN, NAN}},
+ .coldThrottlingThresholds = {{NAN, NAN, NAN, NAN, NAN, NAN, NAN}},
+ .vrThrottlingThreshold = NAN,
+};
+
+static const CoolingDevice_1_0 kCooling_1_0 = {
+ .type = ::android::hardware::thermal::V1_0::CoolingType::FAN_RPM,
+ .name = "test cooling device",
+ .currentValue = 100.0,
+};
+
+static const CoolingDevice_2_0 kCooling_2_0 = {
+ .type = CoolingType::CPU,
+ .name = "test cooling device",
+ .value = 1,
+};
+
+static const CpuUsage kCpuUsage = {
+ .name = "cpu_name",
+ .active = 0,
+ .total = 0,
+ .isOnline = true,
+};
+
+// Methods from ::android::hardware::thermal::V1_0::IThermal follow.
+Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ std::vector<Temperature_1_0> temperatures = {kTemp_1_0};
+ _hidl_cb(status, temperatures);
+ return Void();
+}
+
+Return<void> Thermal::getCpuUsages(getCpuUsages_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ std::vector<CpuUsage> cpu_usages = {kCpuUsage};
+ _hidl_cb(status, cpu_usages);
+ return Void();
+}
+
+Return<void> Thermal::getCoolingDevices(getCoolingDevices_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ std::vector<CoolingDevice_1_0> cooling_devices = {kCooling_1_0};
+ _hidl_cb(status, cooling_devices);
+ return Void();
+}
+
+// Methods from ::android::hardware::thermal::V2_0::IThermal follow.
+Return<void> Thermal::getCurrentTemperatures(bool filterType, TemperatureType type,
+ getCurrentTemperatures_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ std::vector<Temperature_2_0> temperatures;
+ if (filterType && type != kTemp_2_0.type) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = "Failed to read data";
+ } else {
+ temperatures = {kTemp_2_0};
+ }
+ _hidl_cb(status, temperatures);
+ return Void();
+}
+
+Return<void> Thermal::getTemperatureThresholds(bool filterType, TemperatureType type,
+ getTemperatureThresholds_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ std::vector<TemperatureThreshold> temperature_thresholds;
+ if (filterType && type != kTempThreshold.type) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = "Failed to read data";
+ } else {
+ temperature_thresholds = {kTempThreshold};
+ }
+ _hidl_cb(status, temperature_thresholds);
+ return Void();
+}
+
+Return<void> Thermal::getCurrentCoolingDevices(bool filterType, CoolingType type,
+ getCurrentCoolingDevices_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ std::vector<CoolingDevice_2_0> cooling_devices;
+ if (filterType && type != kCooling_2_0.type) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = "Failed to read data";
+ } else {
+ cooling_devices = {kCooling_2_0};
+ }
+ _hidl_cb(status, cooling_devices);
+ return Void();
+}
+
+Return<void> Thermal::registerThermalChangedCallback(const sp<IThermalChangedCallback>& callback,
+ bool filterType, TemperatureType type,
+ registerThermalChangedCallback_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
+ if (std::any_of(callbacks_.begin(), callbacks_.end(), [&](const CallbackSetting& c) {
+ return interfacesEqual(c.callback, callback);
+ })) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = "Same callback interface registered already";
+ LOG(ERROR) << status.debugMessage;
+ } else {
+ callbacks_.emplace_back(callback, filterType, type);
+ LOG(INFO) << "A callback has been registered to ThermalHAL, isFilter: " << filterType
+ << " Type: " << android::hardware::thermal::V2_0::toString(type);
+ }
+ _hidl_cb(status);
+ return Void();
+}
+
+Return<void> Thermal::unregisterThermalChangedCallback(
+ const sp<IThermalChangedCallback>& callback, unregisterThermalChangedCallback_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ bool removed = false;
+ std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
+ callbacks_.erase(
+ std::remove_if(callbacks_.begin(), callbacks_.end(),
+ [&](const CallbackSetting& c) {
+ if (interfacesEqual(c.callback, callback)) {
+ LOG(INFO)
+ << "A callback has been unregistered from ThermalHAL, isFilter: "
+ << c.is_filter_type << " Type: "
+ << android::hardware::thermal::V2_0::toString(c.type);
+ removed = true;
+ return true;
+ }
+ return false;
+ }),
+ callbacks_.end());
+ if (!removed) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = "The callback was not registered before";
+ LOG(ERROR) << status.debugMessage;
+ }
+ _hidl_cb(status);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/thermal/2.0/default/Thermal.h b/thermal/2.0/default/Thermal.h
new file mode 100644
index 0000000..5fa1abd
--- /dev/null
+++ b/thermal/2.0/default/Thermal.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_HARDWARE_THERMAL_V2_0_THERMAL_H
+#define ANDROID_HARDWARE_THERMAL_V2_0_THERMAL_H
+
+#include <android/hardware/thermal/2.0/IThermal.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::thermal::V1_0::CpuUsage;
+using ::android::hardware::thermal::V2_0::CoolingType;
+using ::android::hardware::thermal::V2_0::IThermal;
+using CoolingDevice_1_0 = ::android::hardware::thermal::V1_0::CoolingDevice;
+using CoolingDevice_2_0 = ::android::hardware::thermal::V2_0::CoolingDevice;
+using Temperature_1_0 = ::android::hardware::thermal::V1_0::Temperature;
+using Temperature_2_0 = ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::IThermalChangedCallback;
+using ::android::hardware::thermal::V2_0::TemperatureThreshold;
+using ::android::hardware::thermal::V2_0::TemperatureType;
+
+struct CallbackSetting {
+ CallbackSetting(sp<IThermalChangedCallback> callback, bool is_filter_type, TemperatureType type)
+ : callback(callback), is_filter_type(is_filter_type), type(type) {}
+ sp<IThermalChangedCallback> callback;
+ bool is_filter_type;
+ TemperatureType type;
+};
+
+class Thermal : public IThermal {
+ public:
+ // Methods from ::android::hardware::thermal::V1_0::IThermal follow.
+ Return<void> getTemperatures(getTemperatures_cb _hidl_cb) override;
+ Return<void> getCpuUsages(getCpuUsages_cb _hidl_cb) override;
+ Return<void> getCoolingDevices(getCoolingDevices_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::thermal::V2_0::IThermal follow.
+ Return<void> getCurrentTemperatures(bool filterType, TemperatureType type,
+ getCurrentTemperatures_cb _hidl_cb) override;
+ Return<void> getTemperatureThresholds(bool filterType, TemperatureType type,
+ getTemperatureThresholds_cb _hidl_cb) override;
+ Return<void> registerThermalChangedCallback(
+ const sp<IThermalChangedCallback>& callback, bool filterType, TemperatureType type,
+ registerThermalChangedCallback_cb _hidl_cb) override;
+ Return<void> unregisterThermalChangedCallback(
+ const sp<IThermalChangedCallback>& callback,
+ unregisterThermalChangedCallback_cb _hidl_cb) override;
+ Return<void> getCurrentCoolingDevices(bool filterType, CoolingType type,
+ getCurrentCoolingDevices_cb _hidl_cb) override;
+
+ private:
+ std::mutex thermal_callback_mutex_;
+ std::vector<CallbackSetting> callbacks_;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_THERMAL_V2_0_THERMAL_H
diff --git a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
new file mode 100644
index 0000000..de49d20
--- /dev/null
+++ b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
@@ -0,0 +1,5 @@
+service vendor.thermal-hal-2-0-mock /vendor/bin/hw/android.hardware.thermal@2.0-service
+ interface android.hardware.thermal@2.0::IThermal default
+ class hal
+ user system
+ group system
diff --git a/thermal/2.0/default/android.hardware.thermal@2.0-service.xml b/thermal/2.0/default/android.hardware.thermal@2.0-service.xml
new file mode 100644
index 0000000..bcd6344
--- /dev/null
+++ b/thermal/2.0/default/android.hardware.thermal@2.0-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.thermal</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <version>2.0</version>
+ <interface>
+ <name>IThermal</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/thermal/2.0/default/service.cpp b/thermal/2.0/default/service.cpp
new file mode 100644
index 0000000..dd24078
--- /dev/null
+++ b/thermal/2.0/default/service.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "android.hardware.thermal@2.0-service-mock"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include "Thermal.h"
+
+using ::android::OK;
+using ::android::status_t;
+
+// libhwbinder:
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files:
+using ::android::hardware::thermal::V2_0::IThermal;
+using ::android::hardware::thermal::V2_0::implementation::Thermal;
+
+static int shutdown() {
+ LOG(ERROR) << "Thermal Service is shutting down.";
+ return 1;
+}
+
+int main(int /* argc */, char** /* argv */) {
+ status_t status;
+ android::sp<IThermal> service = nullptr;
+
+ LOG(INFO) << "Thermal HAL Service Mock 2.0 starting...";
+
+ service = new Thermal();
+ if (service == nullptr) {
+ LOG(ERROR) << "Error creating an instance of ThermalHAL. Exiting...";
+ return shutdown();
+ }
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ status = service->registerAsService();
+ if (status != OK) {
+ LOG(ERROR) << "Could not register service for ThermalHAL (" << status << ")";
+ return shutdown();
+ }
+
+ LOG(INFO) << "Thermal Service started successfully.";
+ joinRpcThreadpool();
+ // We should not get past the joinRpcThreadpool().
+ return shutdown();
+}
diff --git a/thermal/2.0/types.hal b/thermal/2.0/types.hal
new file mode 100644
index 0000000..4929e44
--- /dev/null
+++ b/thermal/2.0/types.hal
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.thermal@2.0;
+
+import android.hardware.thermal@1.0::types;
+
+/** Device temperature types */
+enum TemperatureType : @1.0::TemperatureType {
+ USB_PORT = 4,
+ POWER_AMPLIFIER = 5,
+ /**
+ * Battery Charge Limit - virtual thermal sensors
+ */
+ BCL_VOLTAGE = 6,
+ BCL_CURRENT = 7,
+ BCL_PERCENTAGE = 8,
+};
+
+
+/** Device cooling device types */
+enum CoolingType : uint32_t {
+ FAN,
+ BATTERY,
+ CPU,
+ GPU,
+ MODEM,
+ NPU,
+ COMPONENT, // for the rest of components
+};
+
+/** Device throttling severity */
+enum ThrottlingSeverity : uint32_t {
+ /**
+ * Not under throttling.
+ */
+ NONE = 0,
+ /**
+ * Light throttling where UX is not impacted.
+ */
+ LIGHT,
+ /**
+ * Moderate throttling where UX is not largily impacted.
+ */
+ MODERATE,
+ /**
+ * Severe throttling where UX is largely impacted.
+ * Similar to 1.0 throttlingThreshold.
+ */
+ SEVERE,
+ /**
+ * Platform has done everything to reduce power.
+ */
+ CRITICAL,
+ /**
+ * User should be warned before shutdown.
+ */
+ WARNING,
+ /**
+ * Need shutdown immediately.
+ */
+ SHUTDOWN,
+};
+
+enum ThrottlingSeverityCount : uint32_t {NUM_THROTTLING_LEVELS = 7};
+
+struct TemperatureThreshold {
+ /**
+ * This temperature's type.
+ */
+ TemperatureType type;
+
+ /**
+ * Name of this temperature matching the Temperature struct.
+ * All temperatures of the same "type" must have a different "name",
+ * e.g., cpu0, battery. Clients use it to match Temperature struct.
+ */
+ string name;
+
+ /**
+ * Hot throttling temperature constant for this temperature sensor in
+ * level defined in ThrottlingSeverity including shutdown. Throttling
+ * happens when temperature >= threshold. If not available, set to NAN.
+ * Unit is same as Temperature's value.
+ */
+ float[ThrottlingSeverityCount:NUM_THROTTLING_LEVELS] hotThrottlingThresholds;
+
+ /**
+ * Cold throttling temperature constant for this temperature sensor in
+ * level defined in ThrottlingSeverity including shutdown. Throttling
+ * happens when temperature <= threshold. If not available, set to NAN.
+ * Unit is same as Temperature's value.
+ */
+ float[ThrottlingSeverityCount:NUM_THROTTLING_LEVELS] coldThrottlingThresholds;
+
+ /**
+ * Threshold temperature above which the VR mode clockrate minimums cannot
+ * be maintained for this device. If not available, set by HAL to NAN.
+ * Unit is same as Temperature's value.
+ */
+ float vrThrottlingThreshold;
+};
+
+struct Temperature {
+ /**
+ * This temperature's type.
+ */
+ TemperatureType type;
+
+ /**
+ * Name of this temperature matching the TemperatureThreshold.
+ * All temperatures of the same "type" must have a different "name",
+ * e.g., cpu0, battery. Clients use it to match with TemperatureThreshold
+ * struct.
+ */
+ string name;
+
+ /**
+ * For BCL, this is the current reading of the virtual sensor and the unit is
+ * millivolt, milliamp, percentage for BCL_VOLTAGE, BCL_CURRENT and BCL_PERCENTAGE
+ * respectively. For everything else, this is the current temperature in Celsius.
+ * If not available set by HAL to NAN.
+ */
+ float value;
+
+ /**
+ * The current throttling level of the sensor.
+ */
+ ThrottlingSeverity throttlingStatus;
+};
+
+struct CoolingDevice {
+ /**
+ * This cooling device type, CPU, GPU, BATTERY, and etc.
+ */
+ CoolingType type;
+
+ /**
+ * Name of this cooling device.
+ * All cooling devices of the same "type" must have a different "name".
+ * The name is usually defined in kernel device tree, and this is for client
+ * logging purpose.
+ */
+ string name;
+
+ /**
+ * Current throttle state of the cooling device. The value can any unsigned integer
+ * numbers between 0 and max_state defined in its driver, usually representing the
+ * associated device's power state. 0 means device is not in throttling, higher value
+ * means deeper throttling.
+ */
+ uint64_t value;
+};
diff --git a/thermal/2.0/vts/functional/Android.bp b/thermal/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..f4e95f8
--- /dev/null
+++ b/thermal/2.0/vts/functional/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 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.
+//
+
+cc_test {
+ name: "VtsHalThermalV2_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalThermalV2_0TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.thermal@1.0",
+ "android.hardware.thermal@2.0",
+ ],
+}
+
diff --git a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
new file mode 100644
index 0000000..cf1956d
--- /dev/null
+++ b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <android/hardware/thermal/2.0/IThermal.h>
+#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
+#include <android/hardware/thermal/2.0/types.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::thermal::V1_0::ThermalStatusCode;
+using ::android::hardware::thermal::V2_0::CoolingDevice;
+using ::android::hardware::thermal::V2_0::CoolingType;
+using ::android::hardware::thermal::V2_0::IThermal;
+using ::android::hardware::thermal::V2_0::IThermalChangedCallback;
+using ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::TemperatureThreshold;
+using ::android::hardware::thermal::V2_0::TemperatureType;
+using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
+using ::android::hardware::thermal::V2_0::ThrottlingSeverityCount;
+
+constexpr char kCallbackNameNotifyThrottling[] = "notifyThrottling";
+static const Temperature kThrottleTemp = {
+ .type = TemperatureType::SKIN,
+ .name = "test temperature sensor",
+ .value = 98.6,
+ .throttlingStatus = ThrottlingSeverity::CRITICAL,
+};
+
+class ThermalCallbackArgs {
+ public:
+ Temperature temperature;
+};
+
+// Callback class for receiving thermal event notifications from main class
+class ThermalCallback : public ::testing::VtsHalHidlTargetCallbackBase<ThermalCallbackArgs>,
+ public IThermalChangedCallback {
+ public:
+ Return<void> notifyThrottling(const Temperature& temperature) override {
+ ThermalCallbackArgs args;
+ args.temperature = temperature;
+ NotifyFromCallback(kCallbackNameNotifyThrottling, args);
+ return Void();
+ }
+};
+
+// Test environment for Thermal HIDL HAL.
+class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static ThermalHidlEnvironment* Instance() {
+ static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
+ return instance;
+ }
+
+ void registerTestServices() override { registerTestService<IThermal>(); }
+
+ private:
+ ThermalHidlEnvironment() {}
+};
+
+// The main test class for THERMAL HIDL HAL 2.0.
+class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
+ ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
+ ASSERT_NE(mThermal, nullptr);
+ mThermalCallback = new (std::nothrow) ThermalCallback();
+ ASSERT_NE(mThermalCallback, nullptr);
+ auto ret = mThermal->registerThermalChangedCallback(
+ mThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail if register again
+ ret = mThermal->registerThermalChangedCallback(
+ mThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ virtual void TearDown() override {
+ auto ret = mThermal->unregisterThermalChangedCallback(
+ mThermalCallback,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail if unregister again
+ ret = mThermal->unregisterThermalChangedCallback(
+ mThermalCallback,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ protected:
+ sp<IThermal> mThermal;
+ sp<ThermalCallback> mThermalCallback;
+}; // class ThermalHidlTest
+
+// Test ThermalChangedCallback::notifyThrottling().
+// This just calls into and back from our local ThermalChangedCallback impl.
+// Note: a real thermal throttling event from the Thermal HAL could be
+// inadvertently received here.
+TEST_F(ThermalHidlTest, NotifyThrottlingTest) {
+ auto ret = mThermalCallback->notifyThrottling(kThrottleTemp);
+ ASSERT_TRUE(ret.isOk());
+ auto res = mThermalCallback->WaitForCallback(kCallbackNameNotifyThrottling);
+ EXPECT_TRUE(res.no_timeout);
+ ASSERT_TRUE(res.args);
+ EXPECT_EQ(kThrottleTemp, res.args->temperature);
+}
+
+// Test Thermal->registerThermalChangedCallback.
+TEST_F(ThermalHidlTest, RegisterThermalChangedCallbackTest) {
+ // Expect to fail with same callback
+ auto ret = mThermal->registerThermalChangedCallback(
+ mThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback();
+ // Expect to succeed with different callback
+ ret = mThermal->registerThermalChangedCallback(
+ localThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Remove the local callback.
+ ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Test Thermal->unregisterThermalChangedCallback.
+TEST_F(ThermalHidlTest, UnregisterThermalChangedCallbackTest) {
+ sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback();
+ // Expect to fail as the callback was not registered before
+ auto ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Register a local callback
+ ret = mThermal->registerThermalChangedCallback(
+ localThermalCallback, false, TemperatureType::SKIN,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to succeed with callback removed
+ ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail as the callback has been unregistered already
+ ret = mThermal->unregisterThermalChangedCallback(
+ localThermalCallback,
+ [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Sanity test for Thermal::getCurrentTemperatures().
+TEST_F(ThermalHidlTest, TemperatureTest) {
+ mThermal->getCurrentTemperatures(false, TemperatureType::SKIN,
+ [](ThermalStatus status, hidl_vec<Temperature> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ });
+ auto types = hidl_enum_range<TemperatureType>();
+ for (const auto& type : types) {
+ mThermal->getCurrentTemperatures(
+ true, type, [&type](ThermalStatus status, hidl_vec<Temperature> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < temperatures.size(); ++i) {
+ EXPECT_EQ(type, temperatures[i].type);
+ }
+ });
+ }
+}
+
+// Sanity test for Thermal::getTemperatureThresholds().
+TEST_F(ThermalHidlTest, TemperatureThresholdTest) {
+ mThermal->getTemperatureThresholds(
+ false, TemperatureType::SKIN,
+ [](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ });
+ for (int i = static_cast<int>(TemperatureType::UNKNOWN);
+ i <= static_cast<int>(TemperatureType::POWER_AMPLIFIER); ++i) {
+ auto type = static_cast<TemperatureType>(i);
+ mThermal->getTemperatureThresholds(
+ true, type, [&type](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) {
+ if (temperatures.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < temperatures.size(); ++i) {
+ EXPECT_EQ(type, temperatures[i].type);
+ }
+ });
+ }
+}
+
+// Sanity test for Thermal::getCurrentCoolingDevices().
+TEST_F(ThermalHidlTest, CoolingDeviceTest) {
+ mThermal->getCurrentCoolingDevices(
+ false, CoolingType::CPU, [](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) {
+ if (cooling_devices.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ });
+ for (int i = 0; i <= static_cast<int>(CoolingType::COMPONENT); ++i) {
+ auto type = static_cast<CoolingType>(i);
+ mThermal->getCurrentCoolingDevices(
+ true, type, [&type](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) {
+ if (cooling_devices.size()) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ } else {
+ EXPECT_NE(ThermalStatusCode::SUCCESS, status.code);
+ }
+ for (int i = 0; i < cooling_devices.size(); ++i) {
+ EXPECT_EQ(type, cooling_devices[i].type);
+ }
+ });
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ ThermalHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ cout << "Test result = " << status << std::endl;
+ return status;
+}
diff --git a/update-base-files.sh b/update-base-files.sh
index 75d2be5..daaa530 100755
--- a/update-base-files.sh
+++ b/update-base-files.sh
@@ -36,6 +36,9 @@
hidl-gen $options \
-o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.1.h \
android.hardware.graphics.common@1.1
+hidl-gen $options \
+ -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.2.h \
+ android.hardware.graphics.common@1.2
# system/media
hidl-gen $options \
diff --git a/update-makefiles.sh b/update-makefiles.sh
index b7e4235..14c5b01 100755
--- a/update-makefiles.sh
+++ b/update-makefiles.sh
@@ -1,4 +1,12 @@
#!/bin/bash
+# Script to update Android make-files for HAL and VTS modules.
+
+set -e
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Missing ANDROID_BUILD_TOP env variable. Run 'lunch' first."
+ exit 1
+fi
source $ANDROID_BUILD_TOP/system/tools/hidl/update-makefiles-helper.sh
@@ -6,3 +14,8 @@
"android.hardware:hardware/interfaces" \
"android.hidl:system/libhidl/transport"
+echo "Updating files at $ANDROID_BUILD_TOP/test/vts-testcase/hal"
+pushd $ANDROID_BUILD_TOP/test/vts-testcase/hal
+./script/update_makefiles.py
+popd
+
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 6522f4d..d0dd915 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -45,6 +45,8 @@
static_libs: [
"VtsHalWifiV1_0TargetTestUtil",
"android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
],
}
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index d16f1e7..a3fdf27 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -735,10 +735,10 @@
* CreateRttController
*/
TEST_F(WifiChipHidlTest, CreateRttController) {
- configureChipForIfaceType(IfaceType::AP, true);
+ configureChipForIfaceType(IfaceType::STA, true);
- sp<IWifiApIface> iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
+ sp<IWifiStaIface> iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface));
EXPECT_NE(nullptr, iface.get());
const auto& status_and_rtt_controller =
diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
index a341028..a22cd72 100644
--- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -17,6 +17,7 @@
#include <android-base/logging.h>
#include <android/hardware/wifi/1.0/IWifiStaIface.h>
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
#include <VtsHalHidlTargetTestBase.h>
@@ -143,6 +144,14 @@
return;
}
+ sp<::android::hardware::wifi::V1_3::IWifiStaIface> iface_converted =
+ ::android::hardware::wifi::V1_3::IWifiStaIface::castFrom(
+ wifi_sta_iface_);
+ if (iface_converted != nullptr) {
+ // Skip this test since this API is deprecated in this newer HAL version
+ return;
+ }
+
// Enable link layer stats collection.
EXPECT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true)
diff --git a/wifi/1.3/default/Android.mk b/wifi/1.3/default/Android.mk
index 541e5f0..e05d2f0 100644
--- a/wifi/1.3/default/Android.mk
+++ b/wifi/1.3/default/Android.mk
@@ -30,6 +30,8 @@
ifdef WIFI_HIDL_FEATURE_DISABLE_AP
LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
endif
+# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
+LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
LOCAL_SRC_FILES := \
hidl_struct_util.cpp \
hidl_sync_util.cpp \
diff --git a/wifi/supplicant/1.2/Android.bp b/wifi/supplicant/1.2/Android.bp
new file mode 100644
index 0000000..93ce573
--- /dev/null
+++ b/wifi/supplicant/1.2/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.supplicant@1.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "ISupplicant.hal",
+ "ISupplicantStaIface.hal",
+ "ISupplicantStaNetwork.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
+
diff --git a/wifi/supplicant/1.2/ISupplicant.hal b/wifi/supplicant/1.2/ISupplicant.hal
new file mode 100644
index 0000000..b0ec65d
--- /dev/null
+++ b/wifi/supplicant/1.2/ISupplicant.hal
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.2;
+
+import @1.1::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.2 features you must cast specific interfaces returned from the
+ * 1.1 HAL. For example V1_1::ISupplicant::addIface() adds V1_1::ISupplicantIface,
+ * which can be cast to V1_2::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.1::ISupplicant {
+};
diff --git a/wifi/supplicant/1.2/ISupplicantStaIface.hal b/wifi/supplicant/1.2/ISupplicantStaIface.hal
new file mode 100644
index 0000000..a338c6a
--- /dev/null
+++ b/wifi/supplicant/1.2/ISupplicantStaIface.hal
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.2;
+
+import @1.0::SupplicantStatus;
+import @1.1::ISupplicantStaIface;
+import @1.2::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+interface ISupplicantStaIface extends @1.1::ISupplicantStaIface {
+
+ /**
+ * Get Key management capabilities of the device
+ *
+ * @return status Status of the operation, and a bitmap of key management mask.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ getKeyMgmtCapabilities()
+ generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+};
+
diff --git a/wifi/supplicant/1.2/ISupplicantStaNetwork.hal b/wifi/supplicant/1.2/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..6fd0d51
--- /dev/null
+++ b/wifi/supplicant/1.2/ISupplicantStaNetwork.hal
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.2;
+
+import @1.0::ISupplicantStaNetworkCallback;
+import @1.0::ISupplicantStaNetwork;
+import @1.0::SupplicantStatus;
+import @1.1::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.1::ISupplicantStaNetwork {
+ /** Possble mask of values for KeyMgmt param. */
+ enum KeyMgmtMask : @1.0::ISupplicantStaNetwork.KeyMgmtMask {
+ /** WPA3-Personal SAE Key management */
+ SAE = 1 << 10,
+
+ /** WPA3-Enterprise Suite-B Key management */
+ SUITE_B_192 = 1 << 17,
+
+ /** Enhacned Open (OWE) Key management */
+ OWE = 1 << 22,
+ };
+
+ /** Possble mask of values for PairwiseCipher param. */
+ enum PairwiseCipherMask : @1.0::ISupplicantStaNetwork.PairwiseCipherMask {
+ /** GCMP-256 Pairwise Cipher */
+ GCMP_256 = 1 << 8,
+ };
+
+ /** Possble mask of values for GroupCipher param. */
+ enum GroupCipherMask : @1.0::ISupplicantStaNetwork.GroupCipherMask {
+ /** GCMP-256 Group Cipher */
+ GCMP_256 = 1 << 8,
+ };
+
+ /** Possble mask of values for GroupMgmtCipher param. */
+ enum GroupMgmtCipherMask : uint32_t {
+ /** BIP_GMAC-128 Group Management Cipher */
+ BIP_GMAC_128 = 1 << 11,
+
+ /** BIP_GMAC-256 Group Management Cipher */
+ BIP_GMAC_256 = 1 << 12,
+
+ /** BIP_CMAC-256 Group Management Cipher */
+ BIP_CMAC_256 = 1 << 13,
+ };
+
+ /**
+ * Set key management mask for the network.
+ *
+ * @param keyMgmtMask value to set.
+ * Combination of |KeyMgmtMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setKeyMgmt_1_2(bitfield<KeyMgmtMask> keyMgmtMask) generates (SupplicantStatus status);
+
+ /**
+ * Get the key mgmt mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return keyMgmtMask Combination of |KeyMgmtMask| values.
+ */
+ getKeyMgmt_1_2()
+ generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+
+ /**
+ * Set pairwise cipher mask for the network.
+ *
+ * @param pairwiseCipherMask value to set.
+ * Combination of |PairwiseCipherMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setPairwiseCipher_1_2(bitfield<PairwiseCipherMask> pairwiseCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the pairwise cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values.
+ */
+ getPairwiseCipher_1_2()
+ generates (SupplicantStatus status,
+ bitfield<PairwiseCipherMask> pairwiseCipherMask);
+
+ /**
+ * Set group cipher mask for the network.
+ *
+ * @param groupCipherMask value to set.
+ * Combination of |GroupCipherMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setGroupCipher_1_2(bitfield<GroupCipherMask> groupCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the group cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return groupCipherMask Combination of |GroupCipherMask| values.
+ */
+ getGroupCipher_1_2()
+ generates (SupplicantStatus status,
+ bitfield<GroupCipherMask> groupCipherMask);
+
+ /**
+ * Set group management cipher mask for the network.
+ *
+ * @param groupMgmtCipherMask value to set.
+ * Combination of |GroupMgmtCipherMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setGroupMgmtCipher(bitfield<GroupMgmtCipherMask> groupMgmtCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the group management cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return groupMgmtCipherMask Combination of |GroupMgmtCipherMask| values.
+ */
+ getGroupMgmtCipher()
+ generates (SupplicantStatus status,
+ bitfield<GroupMgmtCipherMask> groupMgmtCipherMask);
+
+ /**
+ * Enable TLS Suite-B in EAP Phase1
+ *
+ * @param enable Set to true to enable TLS Suite-B in EAP phase1
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ enableTlsSuiteBEapPhase1Param(bool enable)
+ generates (SupplicantStatus status);
+
+ /**
+ * Set EAP OpenSSL Suite-B-192 ciphers for WPA3-Enterprise
+ * Supported option:
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ enableSuiteBEapOpenSslCiphers()
+ generates (SupplicantStatus status);
+
+ /**
+ * Get SAE password for WPA3-Personal
+ *
+ * @return status Status of the operation, and a string.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ getSaePassword()
+ generates (SupplicantStatus status, string saePassword);
+
+ /**
+ * Get SAE password ID for WPA3-Personal
+ *
+ * @return status Status of the operation, and a string.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ getSaePasswordId()
+ generates (SupplicantStatus status, string saePasswordId);
+
+ /**
+ * Set SAE password for WPA3-Personal
+ *
+ * @param saePassword string with the above option
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setSaePassword(string saePassword)
+ generates (SupplicantStatus status);
+
+ /**
+ * Set SAE password ID for WPA3-Personal
+ *
+ * @param sae_password_id string with the above option
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setSaePasswordId(string saePasswordId)
+ generates (SupplicantStatus status);
+};