Merge "Revert "Provide explicitly versioned NNAPI AIDL utils libs -- HAL.""
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index e1b9729..c33a2e7 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -79,19 +79,24 @@
using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+namespace {
+
/*
* Plese note that this is different from what is defined in
* libhardware/modules/camera/3_4/metadata/types.h; this has one additional
* field to store a framerate.
*/
-const size_t kStreamCfgSz = 5;
typedef struct {
+ int32_t id;
int32_t width;
int32_t height;
int32_t format;
int32_t direction;
int32_t framerate;
} RawStreamConfig;
+constexpr const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
+
+} // anonymous namespace
// The main test class for EVS
@@ -236,6 +241,28 @@
return physicalCameras;
}
+ Stream getFirstStreamConfiguration(camera_metadata_t* metadata) {
+ Stream targetCfg = {};
+ camera_metadata_entry_t streamCfgs;
+ if (!find_camera_metadata_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+ for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+ targetCfg.format = static_cast<PixelFormat>(ptr->format);
+ break;
+ }
+ ++ptr;
+ }
+ }
+
+ return targetCfg;
+ }
sp<IEvsEnumerator> pEnumerator; // Every test needs access to the service
std::vector<CameraDesc> cameraInfo; // Empty unless/until loadCameraList() is called
@@ -265,10 +292,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
bool isLogicalCam = false;
@@ -278,8 +301,14 @@
continue;
}
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
for (int pass = 0; pass < 2; pass++) {
- sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg);
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
for (auto&& devName : devices) {
@@ -343,10 +372,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
bool isLogicalCam = false;
@@ -356,10 +381,14 @@
continue;
}
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
activeCameras.clear();
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
// Store a camera handle for a clean-up
@@ -372,9 +401,7 @@
}
);
- sp<IEvsCamera_1_1> pCam2 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam2 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam2, nullptr);
// Store a camera handle for a clean-up
@@ -422,10 +449,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
bool isLogicalCam = false;
@@ -435,9 +458,13 @@
continue;
}
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
// Store a camera handle for a clean-up
@@ -519,10 +546,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
bool isLogicalCam = false;
@@ -532,9 +555,13 @@
continue;
}
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
// Store a camera handle for a clean-up
@@ -601,10 +628,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Request available display IDs
uint8_t targetDisplayId = 0;
pEnumerator->getDisplayIdList([&targetDisplayId](auto ids) {
@@ -642,9 +665,13 @@
continue;
}
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
// Store a camera handle for a clean-up
@@ -708,24 +735,22 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
// Create two camera clients.
- sp<IEvsCamera_1_1> pCam0 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam0, nullptr);
// Store a camera handle for a clean-up
activeCameras.push_back(pCam0);
- sp<IEvsCamera_1_1> pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam1, nullptr);
// Store a camera handle for a clean-up
@@ -812,10 +837,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Test each reported camera
Return<EvsResult> result = EvsResult::OK;
for (auto&& cam: cameraInfo) {
@@ -828,10 +849,14 @@
continue;
}
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
// Create a camera client
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
// Store a camera
@@ -961,10 +986,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
bool isLogicalCam = false;
@@ -976,18 +997,20 @@
continue;
}
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
// Create two camera clients.
- sp<IEvsCamera_1_1> pCamPrimary =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCamPrimary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCamPrimary, nullptr);
// Store a camera handle for a clean-up
activeCameras.push_back(pCamPrimary);
- sp<IEvsCamera_1_1> pCamSecondary =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCamSecondary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCamSecondary, nullptr);
// Store a camera handle for a clean-up
@@ -1142,10 +1165,6 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
bool isLogicalCam = false;
@@ -1157,18 +1176,20 @@
continue;
}
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
// Create two camera clients.
- sp<IEvsCamera_1_1> pCamPrimary =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCamPrimary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCamPrimary, nullptr);
// Store a camera handle for a clean-up
activeCameras.push_back(pCamPrimary);
- sp<IEvsCamera_1_1> pCamSecondary =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCamSecondary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCamSecondary, nullptr);
// Store a camera handle for a clean-up
@@ -1615,28 +1636,26 @@
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Request exclusive access to the EVS display
sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
ASSERT_NE(pDisplay, nullptr);
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
+
// Create two clients
- sp<IEvsCamera_1_1> pCam0 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam0, nullptr);
// Store a camera handle for a clean-up
activeCameras.push_back(pCam0);
- sp<IEvsCamera_1_1> pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam1, nullptr);
// Store a camera handle for a clean-up
@@ -2001,7 +2020,7 @@
&streamCfgs)) {
// Stream configurations are found in metadata
RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
- for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
@@ -2026,9 +2045,7 @@
continue;
}
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
// Store a camera handle for a clean-up
@@ -2106,7 +2123,7 @@
&streamCfgs)) {
// Stream configurations are found in metadata
RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
- for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
@@ -2132,9 +2149,7 @@
}
// Create the first camera client with a selected stream configuration.
- sp<IEvsCamera_1_1> pCam0 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam0, nullptr);
// Store a camera handle for a clean-up
@@ -2144,9 +2159,7 @@
// configuration.
int32_t id = targetCfg.id;
targetCfg.id += 1; // EVS manager sees only the stream id.
- sp<IEvsCamera_1_1> pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_EQ(pCam1, nullptr);
// Store a camera handle for a clean-up
@@ -2154,9 +2167,7 @@
// Try again with same stream configuration.
targetCfg.id = id;
- pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
- .withDefault(nullptr);
+ pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam1, nullptr);
// Set up per-client frame receiver objects which will fire up its own thread
@@ -2258,52 +2269,23 @@
LOG(INFO) << "Starting CameraStreamExternalBuffering test";
// Arbitrary constant (should be > 1 and not too big)
- static const unsigned int kBuffersToHold = 6;
+ static const unsigned int kBuffersToHold = 3;
// Get the camera list
loadCameraList();
- // Using null stream configuration makes EVS uses the default resolution and
- // output format.
- Stream nullCfg = {};
-
// Acquire the graphics buffer allocator
android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
const auto usage =
GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
- const auto format = HAL_PIXEL_FORMAT_RGBA_8888;
- uint32_t width = 640;
- uint32_t height = 360;
- camera_metadata_entry_t streamCfgs;
// Test each reported camera
for (auto&& cam : cameraInfo) {
- bool foundCfg = false;
- if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()),
- ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
- &streamCfgs)) {
- // Stream configurations are found in metadata
- RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
-
- LOG(DEBUG) << __LINE__ << " start searching " << streamCfgs.count;
- for (unsigned idx = 0; idx < streamCfgs.count; idx++) {
- LOG(DEBUG) << "ptr->direction= " << ptr->direction
- << " ptr->format= " << ptr->format;
- if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
- width = ptr->width;
- height = ptr->height;
- foundCfg = true;
- // Always use the 1st available configuration
- break;
- }
- ++ptr;
- }
- }
-
- if (!foundCfg) {
- LOG(INFO) << "No configuration found. Use default stream configurations.";
- }
+ // Read a target resolution from the metadata
+ Stream targetCfg =
+ getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+ ASSERT_GT(targetCfg.width, 0);
+ ASSERT_GT(targetCfg.height, 0);
// Allocate buffers to use
hidl_vec<BufferDesc> buffers;
@@ -2312,8 +2294,11 @@
unsigned pixelsPerLine;
buffer_handle_t memHandle = nullptr;
android::status_t result =
- alloc.allocate(width, height, format, 1, usage, &memHandle, &pixelsPerLine, 0,
- "CameraStreamExternalBufferingTest");
+ alloc.allocate(targetCfg.width, targetCfg.height,
+ (android::PixelFormat)targetCfg.format,
+ /* layerCount = */ 1, usage, &memHandle, &pixelsPerLine,
+ /* graphicBufferId = */ 0,
+ /* requestorName = */ "CameraStreamExternalBufferingTest");
if (result != android::NO_ERROR) {
LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
// Release previous allocated buffers
@@ -2325,10 +2310,10 @@
BufferDesc buf;
AHardwareBuffer_Desc* pDesc =
reinterpret_cast<AHardwareBuffer_Desc*>(&buf.buffer.description);
- pDesc->width = width;
- pDesc->height = height;
+ pDesc->width = targetCfg.width;
+ pDesc->height = targetCfg.height;
pDesc->layers = 1;
- pDesc->format = format;
+ pDesc->format = static_cast<uint32_t>(targetCfg.format);
pDesc->usage = usage;
pDesc->stride = pixelsPerLine;
buf.buffer.nativeHandle = memHandle;
@@ -2340,9 +2325,7 @@
bool isLogicalCam = false;
getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
ASSERT_NE(pCam, nullptr);
// Store a camera handle for a clean-up
@@ -2362,7 +2345,7 @@
}
EXPECT_EQ(result, EvsResult::OK);
- EXPECT_GE(delta, 0);
+ EXPECT_GE(delta, kBuffersToHold);
// Set up a frame receiver object which will fire up its own thread.
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
@@ -2378,7 +2361,7 @@
sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case
unsigned framesReceived = 0;
frameHandler->getFramesCounters(&framesReceived, nullptr);
- ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+ ASSERT_LE(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
// Give back one buffer
@@ -2387,9 +2370,10 @@
// Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
// filled since we require 10fps minimum -- but give a 10% allowance just in case.
+ unsigned framesReceivedAfter = 0;
usleep(110 * kMillisecondsToMicroseconds);
- frameHandler->getFramesCounters(&framesReceived, nullptr);
- EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed";
+ frameHandler->getFramesCounters(&framesReceivedAfter, nullptr);
+ EXPECT_EQ(framesReceived + 1, framesReceivedAfter) << "Stream should've resumed";
// Even when the camera pointer goes out of scope, the FrameHandler object will
// keep the stream alive unless we tell it to shutdown.
diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.cpp b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
index abf59b7..dccdb2b 100644
--- a/automotive/vehicle/2.0/utils/UserHalHelper.cpp
+++ b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
@@ -60,11 +60,22 @@
<< int32Values.size();
}
userInfo->userId = int32Values[startPos];
- auto userFlags = verifyAndCast<UserFlags>(int32Values[startPos + 1]);
- if (!userFlags.ok()) {
- return Error() << "Invalid user flags: " << userFlags.error();
+ int32_t intUserFlags = int32Values[startPos + 1];
+ int32_t expectedUserFlags = 0;
+ for (const auto& v : hidl_enum_range<UserFlags>()) {
+ int32_t intEnumUserFlag = static_cast<int32_t>(v);
+ if ((intUserFlags & intEnumUserFlag) != 0) {
+ expectedUserFlags |= intEnumUserFlag;
+ }
}
- userInfo->flags = *userFlags;
+ if (intUserFlags != expectedUserFlags) {
+ return Error() << "Invalid user flags: " << intUserFlags << ", must be '|' of UserFlags";
+ }
+ // intUserFlags is actually not a valid UserFlags enum, instead, it is a 'bit or' of possible
+ // multiple UserFlags. However, because the HAL interface was defined incorrectly, we have to
+ // cast it to UserFlags here, which is defined behavior because the underlying type for
+ // UserFlags is int32_t and our intUserFlags is within the range of int32_t.
+ userInfo->flags = static_cast<UserFlags>(intUserFlags);
return {};
}
diff --git a/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp
index 7da87a2..0562a54 100644
--- a/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp
+++ b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp
@@ -54,6 +54,10 @@
constexpr int32_t GUEST_USER = static_cast<int32_t>(UserFlags::GUEST);
constexpr int32_t NONE_USER = static_cast<int32_t>(UserFlags::NONE);
constexpr int32_t SYSTEM_USER = static_cast<int32_t>(UserFlags::SYSTEM);
+constexpr int32_t ADMIN_USER = static_cast<int32_t>(UserFlags::ADMIN);
+constexpr int32_t SYSTEM_ADMIN_USER = static_cast<int32_t>(UserFlags::SYSTEM | UserFlags::ADMIN);
+// 0x1111 is not a valid UserFlags combination.
+constexpr int32_t INVALID_USER_FLAG = 0x1111;
constexpr int32_t USER_ID_ASSOC_KEY_FOB =
static_cast<int32_t>(UserIdentificationAssociationType::KEY_FOB);
@@ -72,7 +76,7 @@
} // namespace
-TEST(UserHalHelperTest, TestToInitialUserInfoRequest) {
+TEST(UserHalHelperTest, TestToInitialUserInfoRequestSystemUser) {
VehiclePropValue propValue{
.prop = INITIAL_USER_INFO,
.value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER,
@@ -92,6 +96,58 @@
EXPECT_THAT(actual.value(), Eq(expected));
}
+TEST(UserHalHelperTest, TestToInitialUserInfoRequestAdminUser) {
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, ADMIN_USER, 10,
+ NONE_USER}},
+ };
+ InitialUserInfoRequest expected{
+ .requestId = 23,
+ .requestType = InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA,
+ .usersInfo = {{10, UserFlags::NONE}, 2, {{0, UserFlags::ADMIN}, {10, UserFlags::NONE}}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestToInitialUserInfoRequestUserFlagsBitCombination) {
+ // SYSTEM_ADMIN_USER is two UserFlags combined and is itself not a defined UserFlags enum.
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0,
+ SYSTEM_ADMIN_USER, 10, NONE_USER}},
+ };
+ InitialUserInfoRequest expected{
+ .requestId = 23,
+ .requestType = InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA,
+ .usersInfo = {{10, UserFlags::NONE},
+ 2,
+ {{0, static_cast<UserFlags>(SYSTEM_ADMIN_USER)}, {10, UserFlags::NONE}}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValue);
+
+ ASSERT_TRUE(actual.ok()) << actual.error().message();
+ EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestToInitialUserInfoRequestUserInvalidUserFlag) {
+ // 0x1111 is not a valid UserFlags flag combination.
+ VehiclePropValue propValue{
+ .prop = INITIAL_USER_INFO,
+ .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0,
+ INVALID_USER_FLAG, 10, NONE_USER}},
+ };
+
+ auto actual = toInitialUserInfoRequest(propValue);
+
+ EXPECT_FALSE(actual.ok()) << "No error returned on invalid user flags";
+}
+
TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithMismatchingPropType) {
VehiclePropValue propValue{
.prop = INT32_MAX,
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 4820fd4..9924581 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -8,6 +8,12 @@
},
{
"name": "VehicleHalVehicleUtilsTest"
+ },
+ {
+ "name": "FakeVehicleHardwareTest"
+ },
+ {
+ "name": "FakeVehicleHalValueGeneratorsTest"
}
]
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl
new file mode 100644
index 0000000..177966b
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@VintfStability
+parcelable GetValueRequest {
+ long requestId;
+ android.hardware.automotive.vehicle.VehiclePropValue prop;
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl
index c263a9d..5ecf4dd 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl
@@ -34,7 +34,6 @@
package android.hardware.automotive.vehicle;
@VintfStability
parcelable GetValueRequests {
- android.hardware.automotive.vehicle.VehiclePropValue[] payloads;
- long[] requestId;
+ android.hardware.automotive.vehicle.GetValueRequest[] payloads;
@nullable ParcelFileDescriptor sharedMemoryFd;
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 82e7551..d6cddb6 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -34,6 +34,6 @@
package android.hardware.automotive.vehicle;
@VintfStability
parcelable SetValueRequest {
- android.hardware.automotive.vehicle.VehiclePropValue value;
long requestId;
+ android.hardware.automotive.vehicle.VehiclePropValue value;
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 4af3e5b..3fc9353 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -105,7 +105,7 @@
EV_BATTERY_DISPLAY_UNITS = 289408515,
FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364,
VEHICLE_SPEED_DISPLAY_UNITS = 289408517,
- EPOCH_TIME = 290457094,
+ ANDROID_EPOCH_TIME = 290457094,
STORAGE_ENCRYPTION_BINDING_SEED = 292554247,
ENV_OUTSIDE_TEMPERATURE = 291505923,
AP_POWER_STATE_REQ = 289475072,
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl
new file mode 100644
index 0000000..43a89d0
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+import android.hardware.automotive.vehicle.VehiclePropValue;
+
+@VintfStability
+parcelable GetValueRequest {
+ // A unique request ID. For every client, the request ID must start with 1
+ // and monotonically increase for every SetValueRequest. If it hits
+ // LONG_MAX (very unlikely), it must loop back to 0.
+ long requestId;
+ // The property to get, for most properties, only the property ID or area
+ // ID would be used to identify the property, but for some properties, other
+ // fields might be used.
+ VehiclePropValue prop;
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl
index 149799e..6601233 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl
@@ -16,18 +16,14 @@
package android.hardware.automotive.vehicle;
-import android.hardware.automotive.vehicle.VehiclePropValue;
+import android.hardware.automotive.vehicle.GetValueRequest;
import android.os.ParcelFileDescriptor;
@VintfStability
parcelable GetValueRequests {
- // The list of properties to get if they fit the binder memory limitation.
- VehiclePropValue[] payloads;
- // A list of request IDs, one for each VehiclePropValue. For every client,
- // the request ID must start with 1 and monotonically increase for every
- // VehiclePropValue in GetValueRequests. If it hits LONG_MAX (very
- // unlikely), it must loop back to 0.
- long[] requestId;
+ // A list of GetValueRequest to get if they fit the binder memory
+ // limitation.
+ GetValueRequest[] payloads;
// Shared memory file to store requests if they exceed binder memory
// limitation. Created by client, readable only at VHAL during the call.
// Caller could close it after the call.
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 1771c63..f2b0e27 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -20,10 +20,10 @@
@VintfStability
parcelable SetValueRequest {
- // The value to set.
- VehiclePropValue value;
// A unique request ID. For every client, the request ID must start with 1
// and monotonically increase for every SetValueRequest. If it hits
// LONG_MAX (very unlikely), it must loop back to 0.
long requestId;
+ // The value to set.
+ VehiclePropValue value;
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 65a22db..e3b5a38 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -1035,24 +1035,32 @@
VEHICLE_SPEED_DISPLAY_UNITS = 0x0605 + 0x10000000 + 0x01000000
+ 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
/**
- * Current date and time, encoded as Unix time (in milliseconds).
+ * Current date and time, encoded as Epoch time (in milliseconds).
* This value denotes the number of milliseconds seconds that have
* elapsed since 1/1/1970 UTC.
*
- * Reading this value will give you the system’s time. This can be
- * useful to synchronize other vehicle systems (dash clock etc).
+ * CarServices will write to this value to give VHAL the Android system's
+ * time, if the VHAL supports this property. This can be useful to
+ * synchronize other vehicle systems (dash clock etc) with Android's time.
*
- * Writing this value will update the ‘ExternalTimeSuggestion’
- * value (if enabled). This value may be consumed by the “Time
- * Detector Service”, if other sources do not have a higher
- * priority. For information on how to adjust time source
- * priorities see Time Detector Service documentation.
+ * AAOS writes to this property once during boot, and
+ * will thereafter write only when some time-source changes are propagated.
+ * AAOS will fill in VehiclePropValue.timestamp correctly.
+ * Note that AAOS will not send updates for natural elapse of time.
+ * int64Values[0] = provided Unix time (in milliseconds)
+ *
+ * Note that the property may take >0 ms to get propagated through the stack
+ * and, having a timestamped property helps reduce any time drift. So,
+ * for all writes to the property, the timestamp can be used to negate this
+ * drift:
+ * drift = elapsedTime - PropValue.timestamp
+ * effectiveTime = PropValue.value.int64Values[0] + drift
*
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
- * @access VehiclePropertyAccess:READ_WRITE
+ * @access VehiclePropertyAccess:WRITE_ONLY
* @unit VehicleUnit:MILLI_SECS
*/
- EPOCH_TIME = 0x0606 + 0x10000000 + 0x01000000
+ ANDROID_EPOCH_TIME = 0x0606 + 0x10000000 + 0x01000000
+ 0x00500000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64
/**
* External encryption binding seed.
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index 12a5691..d2b69af 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -1016,8 +1016,8 @@
{
.config =
{
- .prop = toInt(VehicleProperty::EPOCH_TIME),
- .access = VehiclePropertyAccess::READ_WRITE,
+ .prop = toInt(VehicleProperty::ANDROID_EPOCH_TIME),
+ .access = VehiclePropertyAccess::WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
},
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
new file mode 100644
index 0000000..4735313
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "FakeVehicleHalValueGenerators",
+ vendor: true,
+ srcs: ["src/*.cpp"],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ defaults: ["VehicleHalDefaults"],
+ static_libs: ["VehicleHalUtils"],
+ shared_libs: [
+ "libjsoncpp",
+ ],
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/FakeValueGenerator.h b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/FakeValueGenerator.h
new file mode 100644
index 0000000..93ffebf
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/FakeValueGenerator.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_
+#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_
+
+#include <VehicleHalTypes.h>
+
+#include <optional>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+// A abstract class for all fake value generators.
+class FakeValueGenerator {
+ public:
+ virtual ~FakeValueGenerator() = default;
+
+ // Returns the next event if there is one or {@code std::nullopt} if there is none.
+ virtual std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
+ nextEvent() = 0;
+};
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/GeneratorHub.h b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/GeneratorHub.h
new file mode 100644
index 0000000..ad04d23
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/GeneratorHub.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_
+#define android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_
+
+#include "FakeValueGenerator.h"
+
+#include <android-base/thread_annotations.h>
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <iostream>
+#include <mutex>
+#include <optional>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+// This is the scheduler for all VHAL event generators. It manages all generators and uses priority
+// queue to maintain generated events ordered by timestamp. The scheduler uses a single thread to
+// keep querying and updating the event queue to make sure events from all generators are produced
+// in order.
+class GeneratorHub {
+ public:
+ using OnHalEvent = std::function<void(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& event)>;
+
+ explicit GeneratorHub(OnHalEvent&& onHalEvent);
+ ~GeneratorHub();
+
+ // Register a new generator. The generator will be discarded if it could not produce next event.
+ // The existing generator will be overridden if it has the same generatorId.
+ void registerGenerator(int32_t generatorId, std::unique_ptr<FakeValueGenerator> generator);
+
+ // Unregister a generator with the generatorId. If no registered generator is found, this
+ // function does nothing.
+ void unregisterGenerator(int32_t generatorId);
+
+ private:
+ struct VhalEvent {
+ int32_t generatorId;
+ ::aidl::android::hardware::automotive::vehicle::VehiclePropValue val;
+ };
+
+ // Comparator used by priority queue to keep track of soonest event.
+ struct GreaterByTime {
+ bool operator()(const VhalEvent& lhs, const VhalEvent& rhs) const {
+ return lhs.val.timestamp > rhs.val.timestamp;
+ }
+ };
+
+ std::priority_queue<VhalEvent, std::vector<VhalEvent>, GreaterByTime> mEventQueue;
+ std::mutex mGeneratorsLock;
+ std::unordered_map<int32_t, std::unique_ptr<FakeValueGenerator>> mGenerators
+ GUARDED_BY(mGeneratorsLock);
+ OnHalEvent mOnHalEvent;
+ std::condition_variable mCond;
+ std::thread mThread;
+ std::atomic<bool> mShuttingDownFlag{false};
+
+ // Main loop of the single thread to producing event and updating event queue.
+ void run();
+};
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h
new file mode 100644
index 0000000..8116ed2
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_
+#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_
+
+#include "FakeValueGenerator.h"
+
+#include <json/json.h>
+
+#include <iostream>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+class JsonFakeValueGenerator : public FakeValueGenerator {
+ public:
+ // Create a new JSON fake value generator. {@code request.value.stringValue} is the JSON file
+ // name. {@code request.value.int32Values[1]} if exists, is the number of iterations. If
+ // {@code int32Values} has less than 2 elements, number of iterations would be set to -1, which
+ // means iterate indefinitely.
+ explicit JsonFakeValueGenerator(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request);
+ // Create a new JSON fake value generator using the specified JSON file path. All the events
+ // in the JSON file would be generated for number of {@code iteration}. If iteration is 0, no
+ // value would be generated. If iteration is less than 0, it would iterate indefinitely.
+ explicit JsonFakeValueGenerator(const std::string& path, int32_t iteration);
+ // Create a new JSON fake value generator using the specified JSON file path. All the events
+ // in the JSON file would be generated once.
+ explicit JsonFakeValueGenerator(const std::string& path);
+
+ ~JsonFakeValueGenerator() = default;
+
+ std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent()
+ override;
+ const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
+ getAllEvents();
+
+ private:
+ size_t mEventIndex = 0;
+ std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> mEvents;
+ long mLastEventTimestamp = 0;
+ int32_t mNumOfIterations = 0;
+
+ void setBit(std::vector<uint8_t>& bytes, size_t idx);
+ void init(const std::string& path, int32_t iteration);
+};
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h
new file mode 100644
index 0000000..bd004f3
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_
+#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_
+
+#include "FakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+class LinearFakeValueGenerator : public FakeValueGenerator {
+ public:
+ // A linear value generator initialized using values in request.
+ // int32Values[1]: propId
+ // floatValues[0]: middleValue and currentValue
+ // floatValues[1]: dispersion
+ // floatValues[2]: increment
+ // int64Values[0]: interval
+ // {@code propId} must be INT32 or INT64 or FLOAT type.
+ explicit LinearFakeValueGenerator(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request);
+ // A linear value generator in range [middleValue - dispersion, middleValue + dispersion),
+ // starts at 'currentValue' and at each 'interval', increase by 'increment' and loop back if
+ // exceeds middleValue + dispersion. {@code propId} must be INT32 or INT64 or FLOAT type.
+ explicit LinearFakeValueGenerator(int32_t propId, float middleValue, float initValue,
+ float dispersion, float increment, int64_t interval);
+ ~LinearFakeValueGenerator() = default;
+
+ std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent()
+ override;
+
+ private:
+ // In every timer tick we may want to generate new value based on initial value for debug
+ // purpose. It's better to have sequential values to see if events gets delivered in order
+ // to the client.
+ struct GeneratorCfg {
+ int32_t propId;
+ float middleValue;
+ float currentValue; // Should be in range (middleValue +/- dispersion).
+ float dispersion; // Defines minimum and maximum value based on initial value.
+ float increment; // Value that we will be added to currentValue with each timer tick.
+ int64_t interval;
+ long lastEventTimestamp;
+ };
+
+ GeneratorCfg mGenCfg;
+
+ void initGenCfg(int32_t propId, float middleValue, float initValue, float dispersion,
+ float increment, int64_t interval);
+};
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/GeneratorHub.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/GeneratorHub.cpp
new file mode 100644
index 0000000..0c182d9
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/GeneratorHub.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GeneratorHub"
+
+#include "GeneratorHub.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+using ::android::base::ScopedLockAssertion;
+
+GeneratorHub::GeneratorHub(OnHalEvent&& onHalEvent)
+ : mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {}
+
+GeneratorHub::~GeneratorHub() {
+ mShuttingDownFlag.store(true);
+ mCond.notify_all();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void GeneratorHub::registerGenerator(int32_t id, std::unique_ptr<FakeValueGenerator> generator) {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mGeneratorsLock);
+ auto maybeNextEvent = generator->nextEvent();
+ // Register only if the generator can produce at least one event.
+ if (maybeNextEvent.has_value()) {
+ // Push the next event if it is a new generator
+ if (mGenerators.find(id) == mGenerators.end()) {
+ ALOGI("%s: Registering new generator, id: %d", __func__, id);
+ mEventQueue.push({id, maybeNextEvent.value()});
+ }
+ mGenerators[id] = std::move(generator);
+ ALOGI("%s: Registered generator, id: %d", __func__, id);
+ }
+ }
+ mCond.notify_one();
+}
+
+void GeneratorHub::unregisterGenerator(int32_t id) {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mGeneratorsLock);
+ mGenerators.erase(id);
+ }
+ mCond.notify_one();
+ ALOGI("%s: Unregistered generator, id: %d", __func__, id);
+}
+
+void GeneratorHub::run() {
+ while (!mShuttingDownFlag.load()) {
+ std::unique_lock<std::mutex> lock(mGeneratorsLock);
+ ScopedLockAssertion lock_assertion(mGeneratorsLock);
+ // Pop events whose generator does not exist (may be already unregistered)
+ while (!mEventQueue.empty() &&
+ mGenerators.find(mEventQueue.top().generatorId) == mGenerators.end()) {
+ mEventQueue.pop();
+ }
+ // Wait until event queue is not empty or shutting down flag is set.
+ // This would unlock mGeneratorsLock and reacquire later.
+ mCond.wait(lock, [this] { return !mEventQueue.empty() || mShuttingDownFlag.load(); });
+ if (mShuttingDownFlag.load()) {
+ break;
+ }
+
+ const VhalEvent& curEvent = mEventQueue.top();
+ long currentTime = elapsedRealtimeNano();
+ long waitTime =
+ curEvent.val.timestamp > currentTime ? curEvent.val.timestamp - currentTime : 0;
+ if (waitTime != 0) {
+ // Wait until the soonest event happen
+ if (mCond.wait_for(lock, std::chrono::nanoseconds(waitTime)) !=
+ std::cv_status::timeout) {
+ // It is possible that a new generator is registered and produced a sooner event, or
+ // current generator is unregistered, in this case the thread will re-evaluate the
+ // soonest event
+ ALOGI("Something happened while waiting");
+ continue;
+ }
+ }
+ // Now it's time to handle current event.
+ mOnHalEvent(curEvent.val);
+ // Update queue by popping current event and producing next event from the same generator
+ int32_t id = curEvent.generatorId;
+ mEventQueue.pop();
+ if (mGenerators.find(id) != mGenerators.end()) {
+ auto maybeNextEvent = mGenerators[id]->nextEvent();
+ if (maybeNextEvent.has_value()) {
+ mEventQueue.push({id, maybeNextEvent.value()});
+ continue;
+ }
+ }
+
+ ALOGI("%s: Generator ended, unregister it, id: %d", __func__, id);
+ mGenerators.erase(id);
+ }
+}
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp
new file mode 100644
index 0000000..521ce45
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "JsonFakeValueGenerator"
+
+#include "JsonFakeValueGenerator.h"
+
+#include <fstream>
+#include <type_traits>
+#include <typeinfo>
+
+#include <VehicleUtils.h>
+#include <android/binder_enums.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+namespace {
+
+using ::aidl::android::hardware::automotive::vehicle::DiagnosticFloatSensorIndex;
+using ::aidl::android::hardware::automotive::vehicle::DiagnosticIntegerSensorIndex;
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+template <class T>
+int getLastIndex() {
+ auto range = ::ndk::enum_range<T>();
+ auto it = range.begin();
+ while (std::next(it) != range.end()) {
+ it++;
+ }
+ return toInt(*it);
+}
+
+bool isDiagnosticProperty(int32_t prop) {
+ return prop == toInt(VehicleProperty::OBD2_LIVE_FRAME) ||
+ prop == toInt(VehicleProperty::OBD2_FREEZE_FRAME);
+}
+
+void setBit(std::vector<uint8_t>& bytes, size_t idx) {
+ uint8_t mask = 1 << (idx % 8);
+ bytes[idx / 8] |= mask;
+}
+
+template <typename T>
+void copyJsonArray(const Json::Value& jsonArray, std::vector<T>& dest) {
+ dest.resize(jsonArray.size());
+ for (Json::Value::ArrayIndex i = 0; i < jsonArray.size(); i++) {
+ if (std::is_same<T, int32_t>::value) {
+ dest[i] = jsonArray[i].asInt();
+ } else if (std::is_same<T, int64_t>::value) {
+ dest[i] = jsonArray[i].asInt64();
+ } else if (std::is_same<T, float>::value) {
+ dest[i] = jsonArray[i].asFloat();
+ }
+ }
+}
+
+void copyMixedValueJson(const Json::Value& jsonValue, RawPropValues& dest) {
+ copyJsonArray(jsonValue["int32Values"], dest.int32Values);
+ copyJsonArray(jsonValue["int64Values"], dest.int64Values);
+ copyJsonArray(jsonValue["floatValues"], dest.floatValues);
+ dest.stringValue = jsonValue["stringValue"].asString();
+}
+
+std::vector<uint8_t> generateDiagnosticBytes(const RawPropValues& diagnosticValue) {
+ size_t lastIntegerSensorIndex =
+ static_cast<size_t>(getLastIndex<DiagnosticIntegerSensorIndex>());
+ size_t lastFloatSensorIndex = static_cast<size_t>(getLastIndex<DiagnosticFloatSensorIndex>());
+
+ size_t byteSize = (lastIntegerSensorIndex + lastFloatSensorIndex + 2);
+ std::vector<uint8_t> bytes((byteSize + 7) / 8);
+
+ auto& int32Values = diagnosticValue.int32Values;
+ for (size_t i = 0; i < int32Values.size(); i++) {
+ if (int32Values[i] != 0) {
+ setBit(bytes, i);
+ }
+ }
+
+ auto& floatValues = diagnosticValue.floatValues;
+ for (size_t i = 0; i < floatValues.size(); i++) {
+ if (floatValues[i] != 0.0) {
+ setBit(bytes, i + lastIntegerSensorIndex + 1);
+ }
+ }
+ return bytes;
+}
+
+std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is) {
+ std::vector<VehiclePropValue> fakeVhalEvents;
+
+ Json::CharReaderBuilder builder;
+ Json::Value rawEvents;
+ std::string errorMessage;
+ if (!Json::parseFromStream(builder, is, &rawEvents, &errorMessage)) {
+ ALOGE("%s: Failed to parse fake data JSON file. Error: %s", __func__, errorMessage.c_str());
+ return fakeVhalEvents;
+ }
+
+ for (Json::Value::ArrayIndex i = 0; i < rawEvents.size(); i++) {
+ Json::Value rawEvent = rawEvents[i];
+ if (!rawEvent.isObject()) {
+ ALOGE("%s: VHAL JSON event should be an object, %s", __func__,
+ rawEvent.toStyledString().c_str());
+ continue;
+ }
+ if (rawEvent["prop"].empty() || rawEvent["areaId"].empty() || rawEvent["value"].empty() ||
+ rawEvent["timestamp"].empty()) {
+ ALOGE("%s: VHAL JSON event has missing fields, skip it, %s", __func__,
+ rawEvent.toStyledString().c_str());
+ continue;
+ }
+ VehiclePropValue event = {
+ .timestamp = rawEvent["timestamp"].asInt64(),
+ .areaId = rawEvent["areaId"].asInt(),
+ .prop = rawEvent["prop"].asInt(),
+ };
+
+ Json::Value rawEventValue = rawEvent["value"];
+ auto& value = event.value;
+ int32_t count;
+ switch (getPropType(event.prop)) {
+ case VehiclePropertyType::BOOLEAN:
+ case VehiclePropertyType::INT32:
+ value.int32Values.resize(1);
+ value.int32Values[0] = rawEventValue.asInt();
+ break;
+ case VehiclePropertyType::INT64:
+ value.int64Values.resize(1);
+ value.int64Values[0] = rawEventValue.asInt64();
+ break;
+ case VehiclePropertyType::FLOAT:
+ value.floatValues.resize(1);
+ value.floatValues[0] = rawEventValue.asFloat();
+ break;
+ case VehiclePropertyType::STRING:
+ value.stringValue = rawEventValue.asString();
+ break;
+ case VehiclePropertyType::INT32_VEC:
+ value.int32Values.resize(rawEventValue.size());
+ count = 0;
+ for (auto& it : rawEventValue) {
+ value.int32Values[count++] = it.asInt();
+ }
+ break;
+ case VehiclePropertyType::MIXED:
+ copyMixedValueJson(rawEventValue, value);
+ if (isDiagnosticProperty(event.prop)) {
+ value.byteValues = generateDiagnosticBytes(value);
+ }
+ break;
+ default:
+ ALOGE("%s: unsupported type for property: 0x%x", __func__, event.prop);
+ continue;
+ }
+ fakeVhalEvents.push_back(event);
+ }
+ return fakeVhalEvents;
+}
+
+} // namespace
+
+JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path) {
+ init(path, 1);
+}
+
+JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path, int32_t iteration) {
+ init(path, iteration);
+}
+
+JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) {
+ const auto& v = request.value;
+ // Iterate infinitely if iteration number is not provided
+ int32_t numOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1];
+
+ init(v.stringValue, numOfIterations);
+}
+
+void JsonFakeValueGenerator::init(const std::string& path, int32_t iteration) {
+ std::ifstream ifs(path);
+ if (!ifs) {
+ ALOGE("%s: couldn't open %s for parsing.", __func__, path.c_str());
+ return;
+ }
+ mEvents = parseFakeValueJson(ifs);
+ mNumOfIterations = iteration;
+}
+
+const std::vector<VehiclePropValue>& JsonFakeValueGenerator::getAllEvents() {
+ return mEvents;
+}
+
+std::optional<VehiclePropValue> JsonFakeValueGenerator::nextEvent() {
+ if (mNumOfIterations == 0 || mEvents.size() == 0) {
+ return std::nullopt;
+ }
+
+ VehiclePropValue generatedValue = mEvents[mEventIndex];
+
+ if (mLastEventTimestamp == 0) {
+ mLastEventTimestamp = elapsedRealtimeNano();
+ } else {
+ long nextEventTime = 0;
+ if (mEventIndex > 0) {
+ // All events (start from 2nd one) are supposed to happen in the future with a delay
+ // equals to the duration between previous and current event.
+ nextEventTime = mLastEventTimestamp +
+ (mEvents[mEventIndex].timestamp - mEvents[mEventIndex - 1].timestamp);
+ } else {
+ // We are starting another iteration, immediately send the next event after 1ms.
+ nextEventTime = mLastEventTimestamp + 1000000;
+ }
+ // Prevent overflow.
+ assert(nextEventTime > mLastEventTimestamp);
+ mLastEventTimestamp = nextEventTime;
+ }
+
+ mEventIndex++;
+ if (mEventIndex == mEvents.size()) {
+ mEventIndex = 0;
+ if (mNumOfIterations > 0) {
+ mNumOfIterations--;
+ }
+ }
+
+ generatedValue.timestamp = mLastEventTimestamp;
+
+ return generatedValue;
+}
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp
new file mode 100644
index 0000000..9133144
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LinearFakeValueGenerator"
+
+#include "LinearFakeValueGenerator.h"
+
+#include <VehicleUtils.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+LinearFakeValueGenerator::LinearFakeValueGenerator(int32_t propId, float middleValue,
+ float initValue, float dispersion,
+ float increment, int64_t interval) {
+ initGenCfg(propId, middleValue, initValue, dispersion, increment, interval);
+}
+
+LinearFakeValueGenerator::LinearFakeValueGenerator(const VehiclePropValue& request) {
+ const auto& v = request.value;
+ initGenCfg(v.int32Values[1], v.floatValues[0], v.floatValues[0], v.floatValues[1],
+ v.floatValues[2], v.int64Values[0]);
+}
+
+void LinearFakeValueGenerator::initGenCfg(int32_t propId, float middleValue, float initValue,
+ float dispersion, float increment, int64_t interval) {
+ // Other types are not supported.
+ assert(getPropType(propId) == VehicleProperty::INT32 ||
+ getPropType(propId) == VehicleProperty::INT64 ||
+ getPropType(propId) == VehicleProperty::FLOAT);
+
+ if (initValue < middleValue - dispersion || initValue >= middleValue + dispersion) {
+ ALOGW("%s: invalid initValue: %f, out of range, default to %f", __func__, initValue,
+ middleValue);
+ initValue = middleValue;
+ }
+ mGenCfg = GeneratorCfg{
+ .propId = propId,
+ .middleValue = middleValue,
+ .currentValue = initValue,
+ .dispersion = dispersion,
+ .increment = increment,
+ .interval = interval,
+ };
+}
+
+std::optional<VehiclePropValue> LinearFakeValueGenerator::nextEvent() {
+ VehiclePropValue event = {
+ .prop = mGenCfg.propId,
+ };
+ auto& value = event.value;
+ switch (getPropType(event.prop)) {
+ case VehiclePropertyType::INT32:
+ value.int32Values = {static_cast<int32_t>(mGenCfg.currentValue)};
+ break;
+ case VehiclePropertyType::INT64:
+ value.int64Values = {static_cast<int64_t>(mGenCfg.currentValue)};
+ break;
+ case VehiclePropertyType::FLOAT:
+ value.floatValues = {mGenCfg.currentValue};
+ break;
+ default:
+ ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop);
+ }
+ if (mGenCfg.lastEventTimestamp == 0) {
+ mGenCfg.lastEventTimestamp = elapsedRealtimeNano();
+ } else {
+ long nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval;
+ // Prevent overflow.
+ assert(nextEventTime > mGenCfg.lastEventTimestamp);
+ mGenCfg.lastEventTimestamp = nextEventTime;
+ }
+ event.timestamp = mGenCfg.lastEventTimestamp;
+
+ mGenCfg.currentValue += mGenCfg.increment;
+ if (mGenCfg.currentValue >= mGenCfg.middleValue + mGenCfg.dispersion) {
+ // Wrap around, (i - d) + c - (i + d) = c - 2 * d
+ mGenCfg.currentValue = mGenCfg.currentValue - 2 * mGenCfg.dispersion;
+ }
+ return event;
+}
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
new file mode 100644
index 0000000..d3d3a10
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "FakeVehicleHalValueGeneratorsTest",
+ vendor: true,
+ srcs: ["*.cpp"],
+ defaults: ["VehicleHalDefaults"],
+ static_libs: [
+ "VehicleHalUtils",
+ "FakeVehicleHalValueGenerators",
+ ],
+ shared_libs: [
+ "libjsoncpp",
+ ],
+ data: [
+ ":FakeVehicleHalValueGeneratorsTestFiles",
+ ],
+ test_suites: ["device-tests"],
+}
+
+filegroup {
+ name: "FakeVehicleHalValueGeneratorsTestFiles",
+ srcs: [
+ "prop.json",
+ "prop_invalid.json",
+ ],
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/FakeVehicleHalValueGeneratorsTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/FakeVehicleHalValueGeneratorsTest.cpp
new file mode 100644
index 0000000..21aa680
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/FakeVehicleHalValueGeneratorsTest.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GeneratorHub.h>
+#include <JsonFakeValueGenerator.h>
+#include <LinearFakeValueGenerator.h>
+#include <VehicleUtils.h>
+#include <android-base/file.h>
+#include <android-base/thread_annotations.h>
+#include <gtest/gtest.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <thread>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+class FakeVehicleHalValueGeneratorsTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ mHub = std::make_unique<GeneratorHub>(
+ [this](const VehiclePropValue& event) { return onHalEvent(event); });
+ }
+
+ GeneratorHub* getHub() { return mHub.get(); }
+
+ std::vector<VehiclePropValue> getEvents() {
+ std::scoped_lock<std::mutex> lockGuard(mEventsLock);
+ return mEvents;
+ }
+
+ void clearEvents() {
+ std::scoped_lock<std::mutex> lockGuard(mEventsLock);
+ mEvents.clear();
+ }
+
+ void TearDown() override {
+ // Generator callback uses mEvents, must stop generator before destroying mEvents.
+ mHub.reset();
+ }
+
+ static std::string getTestFilePath(const char* filename) {
+ static std::string baseDir = android::base::GetExecutableDirectory();
+ return baseDir + "/" + filename;
+ }
+
+ private:
+ void onHalEvent(const VehiclePropValue& event) {
+ VehiclePropValue eventCopy = event;
+ std::scoped_lock<std::mutex> lockGuard(mEventsLock);
+ mEvents.push_back(std::move(eventCopy));
+ }
+
+ std::unique_ptr<GeneratorHub> mHub;
+ std::mutex mEventsLock;
+ std::vector<VehiclePropValue> mEvents GUARDED_BY(mEventsLock);
+};
+
+class TestFakeValueGenerator : public FakeValueGenerator {
+ public:
+ void setEvents(const std::vector<VehiclePropValue>& events) {
+ mEvents = events;
+ mEventIndex = 0;
+ }
+
+ std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent()
+ override {
+ if (mEventIndex == mEvents.size()) {
+ return std::nullopt;
+ }
+ return mEvents[mEventIndex++];
+ }
+
+ private:
+ std::vector<VehiclePropValue> mEvents;
+ size_t mEventIndex = 0;
+};
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testRegisterTestFakeValueGenerator) {
+ auto generator = std::make_unique<TestFakeValueGenerator>();
+ std::vector<VehiclePropValue> events;
+ size_t eventCount = 10;
+ int64_t timestamp = elapsedRealtimeNano();
+ for (size_t i = 0; i < eventCount; i++) {
+ events.push_back(VehiclePropValue{
+ .prop = static_cast<int32_t>(i),
+ .timestamp = timestamp + static_cast<int64_t>(50 * i),
+ });
+ }
+ generator->setEvents(events);
+
+ getHub()->registerGenerator(0, std::move(generator));
+
+ // All the events require 500ms to generate, so waiting for 1000ms should be enough.
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+
+ ASSERT_EQ(getEvents(), events);
+
+ getHub()->unregisterGenerator(0);
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testUnregisterGeneratorStopGeneration) {
+ auto generator = std::make_unique<TestFakeValueGenerator>();
+ std::vector<VehiclePropValue> events;
+ size_t eventCount = 10;
+ int64_t timestamp = elapsedRealtimeNano();
+ for (size_t i = 0; i < eventCount; i++) {
+ events.push_back(VehiclePropValue{
+ .prop = static_cast<int32_t>(i),
+ .timestamp = timestamp + static_cast<int64_t>(50 * i),
+ });
+ }
+ generator->setEvents(events);
+
+ getHub()->registerGenerator(0, std::move(generator));
+ getHub()->unregisterGenerator(0);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+
+ ASSERT_LT(getEvents().size(), static_cast<size_t>(10))
+ << "Must stop generating event after generator is unregistered";
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testLinerFakeValueGeneratorFloat) {
+ std::unique_ptr<LinearFakeValueGenerator> generator =
+ std::make_unique<LinearFakeValueGenerator>(toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+ /*middleValue=*/50.0,
+ /*initValue=*/30.0,
+ /*dispersion=*/50.0,
+ /*increment=*/20.0,
+ /*interval=*/10000000);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ auto events = getEvents();
+ // We should get 10 events ideally, but let's be safe here.
+ ASSERT_LE((size_t)5, events.size());
+ int value = 30;
+ for (size_t i = 0; i < 5; i++) {
+ EXPECT_EQ(std::vector<float>({static_cast<float>(value)}), events[i].value.floatValues);
+ value = (value + 20) % 100;
+ }
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testLinerFakeValueGeneratorInt32) {
+ std::unique_ptr<LinearFakeValueGenerator> generator =
+ std::make_unique<LinearFakeValueGenerator>(toInt(VehicleProperty::INFO_MODEL_YEAR),
+ /*middleValue=*/50.0,
+ /*initValue=*/30.0,
+ /*dispersion=*/50.0,
+ /*increment=*/20.0,
+ /*interval=*/10000000);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ auto events = getEvents();
+ // We should get 10 events ideally, but let's be safe here.
+ ASSERT_LE((size_t)5, events.size());
+ int value = 30;
+ for (size_t i = 0; i < 5; i++) {
+ EXPECT_EQ(std::vector<int32_t>({value}), events[i].value.int32Values);
+ value = (value + 20) % 100;
+ }
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testLinerFakeValueGeneratorInt64) {
+ std::unique_ptr<LinearFakeValueGenerator> generator =
+ std::make_unique<LinearFakeValueGenerator>(toInt(VehicleProperty::ANDROID_EPOCH_TIME),
+ /*middleValue=*/50.0,
+ /*initValue=*/30.0,
+ /*dispersion=*/50.0,
+ /*increment=*/20.0,
+ /*interval=*/10000000);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ auto events = getEvents();
+ // We should get 10 events ideally, but let's be safe here.
+ ASSERT_LE((size_t)5, events.size());
+ int value = 30;
+ for (size_t i = 0; i < 5; i++) {
+ EXPECT_EQ(std::vector<int64_t>({value}), events[i].value.int64Values);
+ value = (value + 20) % 100;
+ }
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testLinerFakeValueGeneratorUsingRequest) {
+ VehiclePropValue request;
+ request.value.int32Values = {0, toInt(VehicleProperty::PERF_VEHICLE_SPEED)};
+ request.value.floatValues = {/*middleValue=*/50.0, /*dispersion=*/50.0, /*increment=*/20.0};
+ request.value.int64Values = {/*interval=*/10000000};
+
+ std::unique_ptr<LinearFakeValueGenerator> generator =
+ std::make_unique<LinearFakeValueGenerator>(request);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ auto events = getEvents();
+ // We should get 10 events ideally, but let's be safe here.
+ ASSERT_LE((size_t)5, events.size());
+ int value = 50;
+ for (size_t i = 0; i < 5; i++) {
+ EXPECT_EQ(std::vector<float>({static_cast<float>(value)}), events[i].value.floatValues);
+ value = (value + 20) % 100;
+ }
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testLinerFakeValueGeneratorInvalidInitValue) {
+ std::unique_ptr<LinearFakeValueGenerator> generator =
+ std::make_unique<LinearFakeValueGenerator>(toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+ /*middleValue=*/50.0,
+ // Out of range
+ /*initValue=*/110.0,
+ /*dispersion=*/50.0,
+ /*increment=*/20.0,
+ /*interval=*/10000000);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ auto events = getEvents();
+ // We should get 10 events ideally, but let's be safe here.
+ ASSERT_LE((size_t)5, events.size());
+
+ // Init value would be set to middleValue if given initValue is not valid.
+ int value = 50;
+ for (size_t i = 0; i < 5; i++) {
+ EXPECT_EQ(std::vector<float>({static_cast<float>(value)}), events[i].value.floatValues);
+ value = (value + 20) % 100;
+ }
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGenerator) {
+ long currentTime = elapsedRealtimeNano();
+
+ std::unique_ptr<JsonFakeValueGenerator> generator =
+ std::make_unique<JsonFakeValueGenerator>(getTestFilePath("prop.json"), 2);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ // wait for some time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ std::vector<VehiclePropValue> expectedValues = {
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {8},
+ .prop = 289408000,
+ },
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {4},
+ .prop = 289408000,
+ },
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {16},
+ .prop = 289408000,
+ },
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {10},
+ .prop = 289408000,
+ },
+ };
+
+ // We have two iterations.
+ for (size_t i = 0; i < 4; i++) {
+ expectedValues.push_back(expectedValues[i]);
+ }
+
+ auto events = getEvents();
+
+ long lastEventTime = currentTime;
+ for (auto& event : events) {
+ EXPECT_GT(event.timestamp, lastEventTime);
+ lastEventTime = event.timestamp;
+ event.timestamp = 0;
+ }
+
+ EXPECT_EQ(events, expectedValues);
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGeneratorIterateIndefinitely) {
+ std::unique_ptr<JsonFakeValueGenerator> generator =
+ std::make_unique<JsonFakeValueGenerator>(getTestFilePath("prop.json"), -1);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ // wait for some time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ auto events = getEvents();
+
+ // Send 1 iteration takes 4ms + 1ms interval between iteration, so for 100ms we should get about
+ // 20 iteration, which is 80 events.
+ EXPECT_GT(events.size(), static_cast<size_t>(50));
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGeneratorUsingRequest) {
+ long currentTime = elapsedRealtimeNano();
+
+ VehiclePropValue request = {.value = {
+ .stringValue = getTestFilePath("prop.json"),
+ .int32Values = {0, 2},
+ }};
+
+ std::unique_ptr<JsonFakeValueGenerator> generator =
+ std::make_unique<JsonFakeValueGenerator>(request);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ // wait for some time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ std::vector<VehiclePropValue> expectedValues = {
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {8},
+ .prop = 289408000,
+ },
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {4},
+ .prop = 289408000,
+ },
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {16},
+ .prop = 289408000,
+ },
+ VehiclePropValue{
+ .areaId = 0,
+ .value.int32Values = {10},
+ .prop = 289408000,
+ },
+ };
+
+ // We have two iterations.
+ for (size_t i = 0; i < 4; i++) {
+ expectedValues.push_back(expectedValues[i]);
+ }
+
+ auto events = getEvents();
+
+ long lastEventTime = currentTime;
+ for (auto& event : events) {
+ EXPECT_GT(event.timestamp, lastEventTime);
+ lastEventTime = event.timestamp;
+ event.timestamp = 0;
+ }
+
+ EXPECT_EQ(events, expectedValues);
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGeneratorInvalidFile) {
+ VehiclePropValue request = {.value = {
+ .stringValue = getTestFilePath("prop_invalid.json"),
+ .int32Values = {0, 2},
+ }};
+
+ std::unique_ptr<JsonFakeValueGenerator> generator =
+ std::make_unique<JsonFakeValueGenerator>(request);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ // wait for some time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ ASSERT_TRUE(getEvents().empty());
+}
+
+TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGeneratorNonExistingFile) {
+ VehiclePropValue request = {.value = {
+ .stringValue = "non_existing_file",
+ .int32Values = {0, 2},
+ }};
+
+ std::unique_ptr<JsonFakeValueGenerator> generator =
+ std::make_unique<JsonFakeValueGenerator>(request);
+ getHub()->registerGenerator(0, std::move(generator));
+
+ // wait for some time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ ASSERT_TRUE(getEvents().empty());
+}
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop.json b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop.json
new file mode 100644
index 0000000..b881109
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop.json
@@ -0,0 +1,26 @@
+[
+ {
+ "timestamp": 1000000,
+ "areaId": 0,
+ "value": 8,
+ "prop": 289408000
+ },
+ {
+ "timestamp": 2000000,
+ "areaId": 0,
+ "value": 4,
+ "prop": 289408000
+ },
+ {
+ "timestamp": 3000000,
+ "areaId": 0,
+ "value": 16,
+ "prop": 289408000
+ },
+ {
+ "timestamp": 4000000,
+ "areaId": 0,
+ "value": 10,
+ "prop": 289408000
+ }
+]
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop_invalid.json b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop_invalid.json
new file mode 100644
index 0000000..98232c6
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop_invalid.json
@@ -0,0 +1 @@
+{
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
new file mode 100644
index 0000000..d614c6b
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "FakeVehicleHardware",
+ vendor: true,
+ srcs: ["src/*.cpp"],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ defaults: ["VehicleHalDefaults"],
+ header_libs: [
+ "IVehicleHardware",
+ "VehicleHalDefaultConfig",
+ ],
+ export_header_lib_headers: ["IVehicleHardware"],
+ static_libs: ["VehicleHalUtils"],
+ export_static_lib_headers: ["VehicleHalUtils"],
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
new file mode 100644
index 0000000..dee36f4
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
+#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
+
+#include <DefaultConfig.h>
+#include <IVehicleHardware.h>
+#include <VehicleHalTypes.h>
+#include <VehiclePropertyStore.h>
+#include <android-base/thread_annotations.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+class FakeVehicleHardware final : public IVehicleHardware {
+ public:
+ using SetValuesCallback = std::function<void(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>&)>;
+ using GetValuesCallback = std::function<void(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>&)>;
+ using OnPropertyChangeCallback = std::function<void(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&)>;
+ using OnPropertySetErrorCallback = std::function<void(const std::vector<SetValueErrorEvent>&)>;
+
+ FakeVehicleHardware();
+
+ explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
+
+ // Get all the property configs.
+ std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+ getAllPropertyConfigs() const override;
+
+ // Set property values asynchronously. Server could return before the property set requests
+ // are sent to vehicle bus or before property set confirmation is received. The callback is
+ // safe to be called after the function returns and is safe to be called in a different thread.
+ ::aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+ SetValuesCallback&& callback,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+ requests) override;
+
+ // Get property values asynchronously. Server could return before the property values are ready.
+ // The callback is safe to be called after the function returns and is safe to be called in a
+ // different thread.
+ ::aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+ GetValuesCallback&& callback,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+ requests) const override;
+
+ // Dump debug information in the server.
+ DumpResult dump(const std::vector<std::string>& options) override;
+
+ // Check whether the system is healthy, return {@code StatusCode::OK} for healthy.
+ ::aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override;
+
+ // Register a callback that would be called when there is a property change event from vehicle.
+ void registerOnPropertyChangeEvent(OnPropertyChangeCallback&& callback) override;
+
+ // Register a callback that would be called when there is a property set error event from
+ // vehicle.
+ void registerOnPropertySetErrorEvent(OnPropertySetErrorCallback&& callback) override;
+
+ private:
+ void storePropInitialValue(const defaultconfig::ConfigDeclaration& config);
+ void init(std::shared_ptr<VehiclePropValuePool> valuePool);
+ void onValueChangeCallback(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+
+ std::unique_ptr<VehiclePropertyStore> mServerSidePropStore;
+ // mValuePool is also used in mServerSidePropStore.
+ std::shared_ptr<VehiclePropValuePool> mValuePool;
+ std::mutex mCallbackLock;
+ OnPropertyChangeCallback mOnPropertyChangeCallback GUARDED_BY(mCallbackLock);
+ OnPropertySetErrorCallback mOnPropertySetErrorCallback GUARDED_BY(mCallbackLock);
+};
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
new file mode 100644
index 0000000..f8bf7de
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FakeVehicleHardware.h"
+
+#include <DefaultConfig.h>
+#include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
+ const VehiclePropConfig& vehiclePropConfig = config.config;
+ int propId = vehiclePropConfig.prop;
+
+ // A global property will have only a single area
+ bool globalProp = isGlobalProp(propId);
+ size_t numAreas = globalProp ? 1 : vehiclePropConfig.areaConfigs.size();
+
+ for (size_t i = 0; i < numAreas; i++) {
+ int32_t curArea = globalProp ? 0 : vehiclePropConfig.areaConfigs[i].areaId;
+
+ // Create a separate instance for each individual zone
+ VehiclePropValue prop = {
+ .areaId = curArea,
+ .prop = propId,
+ .timestamp = elapsedRealtimeNano(),
+ };
+
+ if (config.initialAreaValues.empty()) {
+ if (config.initialValue == RawPropValues{}) {
+ // Skip empty initial values.
+ continue;
+ }
+ prop.value = config.initialValue;
+ } else if (auto valueForAreaIt = config.initialAreaValues.find(curArea);
+ valueForAreaIt != config.initialAreaValues.end()) {
+ prop.value = valueForAreaIt->second;
+ } else {
+ ALOGW("failed to get default value for prop 0x%x area 0x%x", propId, curArea);
+ continue;
+ }
+
+ auto result =
+ mServerSidePropStore->writeValue(mValuePool->obtain(prop), /*updateStatus=*/true);
+ if (!result.ok()) {
+ ALOGE("failed to write default config value, error: %s",
+ result.error().message().c_str());
+ }
+ }
+}
+
+FakeVehicleHardware::FakeVehicleHardware() {
+ mValuePool = std::make_shared<VehiclePropValuePool>();
+ init(mValuePool);
+}
+
+FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool)
+ : mValuePool(std::move(valuePool)) {
+ init(mValuePool);
+}
+
+void FakeVehicleHardware::init(std::shared_ptr<VehiclePropValuePool> valuePool) {
+ mServerSidePropStore.reset(new VehiclePropertyStore(valuePool));
+ for (auto& it : defaultconfig::getDefaultConfigs()) {
+ VehiclePropConfig cfg = it.config;
+ mServerSidePropStore->registerProperty(cfg);
+ storePropInitialValue(it);
+ }
+
+ mServerSidePropStore->setOnValueChangeCallback(
+ [this](const VehiclePropValue& value) { return onValueChangeCallback(value); });
+}
+
+std::vector<VehiclePropConfig> FakeVehicleHardware::getAllPropertyConfigs() const {
+ return mServerSidePropStore->getAllConfigs();
+}
+
+StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback&& callback,
+ const std::vector<SetValueRequest>& requests) {
+ std::vector<VehiclePropValue> updatedValues;
+ std::vector<SetValueResult> results;
+ for (auto& request : requests) {
+ const VehiclePropValue* value = &request.value;
+ ALOGD("setValues(%d)", value->prop);
+
+ auto updatedValue = mValuePool->obtain(*value);
+ int64_t timestamp = elapsedRealtimeNano();
+ updatedValue->timestamp = timestamp;
+
+ auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+ SetValueResult setValueResult;
+ setValueResult.requestId = request.requestId;
+ if (!writeResult.ok()) {
+ ALOGE("failed to write value into property store, error: %s, code: %d",
+ writeResult.error().message().c_str(), writeResult.error().code());
+ setValueResult.status = StatusCode::INVALID_ARG;
+ } else {
+ setValueResult.status = StatusCode::OK;
+ }
+ results.push_back(std::move(setValueResult));
+ }
+
+ // In the real vhal, the values will be sent to Car ECU. We just pretend it is done here and
+ // send back the updated property values to client.
+ callback(std::move(results));
+
+ return StatusCode::OK;
+}
+
+StatusCode FakeVehicleHardware::getValues(FakeVehicleHardware::GetValuesCallback&& callback,
+ const std::vector<GetValueRequest>& requests) const {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ const VehiclePropValue* value = &request.prop;
+ ALOGD("getValues(%d)", value->prop);
+
+ auto readResult = mServerSidePropStore->readValue(*value);
+ GetValueResult getValueResult;
+ getValueResult.requestId = request.requestId;
+ if (!readResult.ok()) {
+ auto error = readResult.error();
+ if (error.code() == toInt(StatusCode::NOT_AVAILABLE)) {
+ ALOGW("%s", "value has not been set yet");
+ getValueResult.status = StatusCode::NOT_AVAILABLE;
+ } else {
+ ALOGE("failed to get value, error: %s, code: %d", error.message().c_str(),
+ error.code());
+ getValueResult.status = StatusCode::INVALID_ARG;
+ }
+ } else {
+ getValueResult.status = StatusCode::OK;
+ getValueResult.prop = *readResult.value();
+ }
+ results.push_back(std::move(getValueResult));
+ }
+
+ callback(std::move(results));
+
+ return StatusCode::OK;
+}
+
+DumpResult FakeVehicleHardware::dump(const std::vector<std::string>&) {
+ DumpResult result;
+ // TODO(b/201830716): Implement this.
+ return result;
+}
+
+StatusCode FakeVehicleHardware::checkHealth() {
+ // TODO(b/201830716): Implement this.
+ return StatusCode::OK;
+}
+
+void FakeVehicleHardware::registerOnPropertyChangeEvent(OnPropertyChangeCallback&& callback) {
+ std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
+ mOnPropertyChangeCallback = std::move(callback);
+}
+
+void FakeVehicleHardware::registerOnPropertySetErrorEvent(OnPropertySetErrorCallback&& callback) {
+ std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
+ mOnPropertySetErrorCallback = std::move(callback);
+}
+
+void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
+ std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
+ if (mOnPropertyChangeCallback != nullptr) {
+ std::vector<VehiclePropValue> updatedValues;
+ updatedValues.push_back(value);
+ mOnPropertyChangeCallback(std::move(updatedValues));
+ }
+}
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
new file mode 100644
index 0000000..9f76d09
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "FakeVehicleHardwareTest",
+ vendor: true,
+ srcs: ["*.cpp"],
+ header_libs: [
+ "IVehicleHardware",
+ "VehicleHalDefaultConfig",
+ ],
+ static_libs: [
+ "VehicleHalUtils",
+ "FakeVehicleHardware",
+ "libgtest",
+ "libgmock",
+ ],
+ defaults: ["VehicleHalDefaults"],
+ test_suites: ["device-tests"],
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
new file mode 100644
index 0000000..53e647d
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <DefaultConfig.h>
+#include <FakeVehicleHardware.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace fake {
+
+namespace {
+
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::testing::ContainerEq;
+using ::testing::Eq;
+using ::testing::WhenSortedBy;
+
+constexpr int INVALID_PROP_ID = 0;
+
+} // namespace
+
+class FakeVehicleHardwareTest : public ::testing::Test {
+ protected:
+ void SetUp() override {}
+
+ FakeVehicleHardware* getHardware() { return &mHardware; }
+
+ StatusCode setValues(const std::vector<SetValueRequest>& requests) {
+ return getHardware()->setValues(
+ [this](const std::vector<SetValueResult> results) { return onSetValues(results); },
+ requests);
+ }
+
+ StatusCode getValues(const std::vector<GetValueRequest>& requests) {
+ return getHardware()->getValues(
+ [this](const std::vector<GetValueResult> results) { return onGetValues(results); },
+ requests);
+ }
+
+ void onSetValues(const std::vector<SetValueResult> results) {
+ for (auto& result : results) {
+ mSetValueResults.push_back(result);
+ }
+ }
+
+ const std::vector<SetValueResult>& getSetValueResults() { return mSetValueResults; }
+
+ void onGetValues(const std::vector<GetValueResult> results) {
+ for (auto& result : results) {
+ mGetValueResults.push_back(result);
+ }
+ }
+
+ const std::vector<GetValueResult>& getGetValueResults() { return mGetValueResults; }
+
+ void onPropertyChangeEvent(const std::vector<VehiclePropValue>& values) {
+ for (auto& value : values) {
+ mChangedProperties.push_back(value);
+ }
+ }
+
+ const std::vector<VehiclePropValue>& getChangedProperties() { return mChangedProperties; }
+
+ static void addSetValueRequest(std::vector<SetValueRequest>& requests,
+ std::vector<SetValueResult>& expectedResults, int64_t requestId,
+ const VehiclePropValue& value, StatusCode expectedStatus) {
+ SetValueRequest request;
+ request.requestId = requestId;
+ request.value = value;
+ request.value.timestamp = elapsedRealtimeNano();
+ requests.push_back(std::move(request));
+
+ SetValueResult result;
+ result.requestId = requestId;
+ result.status = expectedStatus;
+ expectedResults.push_back(std::move(result));
+ }
+
+ static void addGetValueRequest(std::vector<GetValueRequest>& requests,
+ std::vector<GetValueResult>& expectedResults, int64_t requestId,
+ const VehiclePropValue& value, StatusCode expectedStatus) {
+ GetValueRequest request;
+ request.requestId = requestId;
+ request.prop.prop = value.prop;
+ request.prop.areaId = value.areaId;
+ requests.push_back(std::move(request));
+
+ GetValueResult result;
+ result.requestId = requestId;
+ result.status = expectedStatus;
+ if (expectedStatus == StatusCode::OK) {
+ result.prop = value;
+ }
+ expectedResults.push_back(std::move(result));
+ }
+
+ std::vector<VehiclePropValue> getTestPropValues() {
+ VehiclePropValue fuelCapacity = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .value = {.floatValues = {1.0}},
+ };
+
+ VehiclePropValue leftTirePressure = {
+ .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+ .value = {.floatValues = {170.0}},
+ .areaId = WHEEL_FRONT_LEFT,
+ };
+
+ VehiclePropValue rightTirePressure = {
+ .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+ .value = {.floatValues = {180.0}},
+ .areaId = WHEEL_FRONT_RIGHT,
+ };
+
+ return {fuelCapacity, leftTirePressure, rightTirePressure};
+ }
+
+ struct PropValueCmp {
+ bool operator()(const VehiclePropValue& a, const VehiclePropValue& b) const {
+ return (a.prop < b.prop) || ((a.prop == b.prop) && (a.value < b.value)) ||
+ ((a.prop == b.prop) && (a.value == b.value) && (a.areaId < b.areaId));
+ }
+ } mPropValueCmp;
+
+ private:
+ FakeVehicleHardware mHardware;
+ std::vector<SetValueResult> mSetValueResults;
+ std::vector<GetValueResult> mGetValueResults;
+ std::vector<VehiclePropValue> mChangedProperties;
+};
+
+TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
+ std::vector<VehiclePropConfig> configs = getHardware()->getAllPropertyConfigs();
+
+ ASSERT_EQ(configs.size(), defaultconfig::getDefaultConfigs().size());
+}
+
+TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ int64_t requestId = 1;
+
+ for (auto& config : defaultconfig::getDefaultConfigs()) {
+ int propId = config.config.prop;
+ if (isGlobalProp(propId)) {
+ if (config.initialValue == RawPropValues{}) {
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++,
+ VehiclePropValue{.prop = propId}, StatusCode::NOT_AVAILABLE);
+ continue;
+ }
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++,
+ VehiclePropValue{
+ .prop = propId,
+ .value = config.initialValue,
+ },
+ StatusCode::OK);
+ continue;
+ }
+ for (auto areaConfig : config.config.areaConfigs) {
+ StatusCode status = StatusCode::OK;
+ VehiclePropValue propValue{
+ .prop = propId,
+ .areaId = areaConfig.areaId,
+ };
+ if (config.initialAreaValues.empty()) {
+ if (config.initialValue == RawPropValues{}) {
+ status = StatusCode::NOT_AVAILABLE;
+ } else {
+ propValue.value = config.initialValue;
+ }
+ } else if (auto valueForAreaIt = config.initialAreaValues.find(areaConfig.areaId);
+ valueForAreaIt != config.initialAreaValues.end()) {
+ propValue.value = valueForAreaIt->second;
+ } else {
+ status = StatusCode::NOT_AVAILABLE;
+ }
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++, propValue,
+ status);
+ }
+ }
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueResult> getValueResultsWithNoTimestamp;
+ for (auto& result : getGetValueResults()) {
+ GetValueResult resultCopy = result;
+ resultCopy.prop->timestamp = 0;
+ getValueResultsWithNoTimestamp.push_back(std::move(resultCopy));
+ }
+ ASSERT_THAT(getValueResultsWithNoTimestamp, ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetValues) {
+ std::vector<SetValueRequest> requests;
+ std::vector<SetValueResult> expectedResults;
+
+ int64_t requestId = 1;
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
+ }
+
+ StatusCode status = setValues(requests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ // Although callback might be called asynchronously, in our implementation, the callback would
+ // be called before setValues returns.
+ ASSERT_THAT(getSetValueResults(), ContainerEq(expectedResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetValuesError) {
+ std::vector<SetValueRequest> requests;
+ std::vector<SetValueResult> expectedResults;
+
+ int64_t requestId = 1;
+
+ VehiclePropValue invalidProp = {
+ .prop = INVALID_PROP_ID,
+ };
+ addSetValueRequest(requests, expectedResults, requestId++, invalidProp,
+ StatusCode::INVALID_ARG);
+
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
+ }
+
+ StatusCode status = setValues(requests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ // Although callback might be called asynchronously, in our implementation, the callback would
+ // be called before setValues returns.
+ ASSERT_THAT(getSetValueResults(), ContainerEq(expectedResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testRegisterOnPropertyChangeEvent) {
+ getHardware()->registerOnPropertyChangeEvent(std::bind(
+ &FakeVehicleHardwareTest_testRegisterOnPropertyChangeEvent_Test::onPropertyChangeEvent,
+ this, std::placeholders::_1));
+
+ auto testValues = getTestPropValues();
+ std::vector<SetValueRequest> requests;
+ std::vector<SetValueResult> expectedResults;
+ int64_t requestId = 1;
+ for (auto& value : testValues) {
+ addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
+ }
+ int64_t timestamp = elapsedRealtimeNano();
+
+ StatusCode status = setValues(requests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ auto updatedValues = getChangedProperties();
+ std::vector<VehiclePropValue> updatedValuesWithNoTimestamp;
+ for (auto& value : updatedValues) {
+ ASSERT_GE(value.timestamp, timestamp);
+ VehiclePropValue valueCopy = value;
+ valueCopy.timestamp = 0;
+ updatedValuesWithNoTimestamp.push_back(std::move(valueCopy));
+ }
+
+ ASSERT_THAT(updatedValuesWithNoTimestamp, WhenSortedBy(mPropValueCmp, Eq(testValues)));
+}
+
+TEST_F(FakeVehicleHardwareTest, testReadValues) {
+ std::vector<SetValueRequest> setValueRequests;
+ std::vector<SetValueResult> expectedSetValueResults;
+
+ int64_t requestId = 1;
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(setValueRequests, expectedSetValueResults, requestId++, value,
+ StatusCode::OK);
+ }
+ int64_t timestamp = elapsedRealtimeNano();
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ for (auto& value : getTestPropValues()) {
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++, value,
+ StatusCode::OK);
+ }
+
+ // In our implementation, this would finish immediately.
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueResult> getValueResultsWithNoTimestamp;
+ for (auto& result : getGetValueResults()) {
+ ASSERT_GE(result.prop->timestamp, timestamp);
+ GetValueResult resultCopy = result;
+ resultCopy.prop->timestamp = 0;
+ getValueResultsWithNoTimestamp.push_back(std::move(resultCopy));
+ }
+ ASSERT_THAT(getValueResultsWithNoTimestamp, ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testReadValuesErrorInvalidProp) {
+ std::vector<SetValueRequest> setValueRequests;
+ std::vector<SetValueResult> expectedSetValueResults;
+
+ int64_t requestId = 1;
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(setValueRequests, expectedSetValueResults, requestId++, value,
+ StatusCode::OK);
+ }
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ VehiclePropValue invalidProp = {
+ .prop = INVALID_PROP_ID,
+ };
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++, invalidProp,
+ StatusCode::INVALID_ARG);
+
+ // In our implementation, this would finish immediately.
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_THAT(getGetValueResults(), ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testReadValuesErrorNotAvailable) {
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ // VEHICLE_MAP_SERVICE does not have initial value, 'get' must always return
+ // StatusCode::NOT_AVAILABLE.
+ addGetValueRequest(getValueRequests, expectedGetValueResults, 0,
+ VehiclePropValue{
+ .prop = VEHICLE_MAP_SERVICE,
+ },
+ StatusCode::NOT_AVAILABLE);
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_THAT(getGetValueResults(), ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetStatusMustIgnore) {
+ VehiclePropValue testValue = getTestPropValues()[0];
+ testValue.status = VehiclePropertyStatus::UNAVAILABLE;
+
+ std::vector<SetValueRequest> setValueRequests;
+ std::vector<SetValueResult> expectedSetValueResults;
+
+ int64_t requestId = 1;
+ addSetValueRequest(setValueRequests, expectedSetValueResults, requestId++, testValue,
+ StatusCode::OK);
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_THAT(getSetValueResults(), ContainerEq(expectedSetValueResults));
+
+ std::vector<GetValueRequest> getValueRequests;
+ getValueRequests.push_back(GetValueRequest{
+ .requestId = requestId++,
+ .prop = testValue,
+ });
+
+ // In our implementation, this would finish immediately.
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_EQ(getGetValueResults().size(), static_cast<size_t>(1));
+ ASSERT_EQ(getGetValueResults()[0].status, StatusCode::OK);
+ // The status should be by-default AVAILABLE for new status.
+ ASSERT_EQ(getGetValueResults()[0].prop->status, VehiclePropertyStatus::AVAILABLE);
+
+ // Try to set the property again. The status should not be overwritten.
+ status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_EQ(getGetValueResults().size(), static_cast<size_t>(2));
+ ASSERT_EQ(getGetValueResults()[1].status, StatusCode::OK);
+ ASSERT_EQ(getGetValueResults()[1].prop->status, VehiclePropertyStatus::AVAILABLE);
+}
+
+} // namespace fake
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index d5f2373..c742db5 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -45,7 +45,7 @@
std::vector<aidl_vehicle::VehiclePropValue> prepareTestValues() {
std::vector<aidl_vehicle::VehiclePropValue> values;
- long timestamp = 1;
+ int64_t timestamp = 1;
for (auto& property : defaultconfig::getDefaultConfigs()) {
values.push_back({
.timestamp = timestamp,
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index 981088a..2e12327 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -36,14 +36,6 @@
std::string buffer;
};
-// A request type for 'setValues' or 'getValues' method.
-struct VehiclePropValueRequest {
- // A unique request ID set by the sender.
- int requestId;
- // The property to get/set.
- ::aidl::android::hardware::automotive::vehicle::VehiclePropValue value;
-};
-
// A structure to represent a set value error event reported from vehicle.
struct SetValueErrorEvent {
::aidl::android::hardware::automotive::vehicle::StatusCode errorCode;
@@ -70,7 +62,8 @@
std::function<void(const std::vector<
::aidl::android::hardware::automotive::vehicle::SetValueResult>&)>&&
callback,
- const std::vector<VehiclePropValueRequest>& requests) = 0;
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+ requests) = 0;
// Get property values asynchronously. Server could return before the property values are ready.
// The callback is safe to be called after the function returns and is safe to be called in a
@@ -79,7 +72,8 @@
std::function<void(const std::vector<
::aidl::android::hardware::automotive::vehicle::GetValueResult>&)>&&
callback,
- const std::vector<VehiclePropValueRequest>& requests) const = 0;
+ const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+ requests) const = 0;
// Dump debug information in the server.
virtual DumpResult dump(const std::vector<std::string>& options) = 0;
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
new file mode 100644
index 0000000..9a8f19b
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_utils_common_include_ConcurrentQueue_H_
+#define android_hardware_automotive_vehicle_aidl_impl_utils_common_include_ConcurrentQueue_H_
+
+#include <android-base/thread_annotations.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <iostream>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+template <typename T>
+class ConcurrentQueue {
+ public:
+ void waitForItems() {
+ std::unique_lock<std::mutex> lockGuard(mLock);
+ ::android::base::ScopedLockAssertion lockAssertion(mLock);
+ while (mQueue.empty() && mIsActive) {
+ mCond.wait(lockGuard);
+ }
+ }
+
+ std::vector<T> flush() {
+ std::vector<T> items;
+
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mQueue.empty()) {
+ return items;
+ }
+ while (!mQueue.empty()) {
+ // Even if the queue is deactivated, we should still flush all the remaining values
+ // in the queue.
+ items.push_back(std::move(mQueue.front()));
+ mQueue.pop();
+ }
+ return items;
+ }
+
+ void push(T&& item) {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (!mIsActive) {
+ return;
+ }
+ mQueue.push(std::move(item));
+ }
+ mCond.notify_one();
+ }
+
+ // Deactivates the queue, thus no one can push items to it, also notifies all waiting thread.
+ // The items already in the queue could still be flushed even after the queue is deactivated.
+ void deactivate() {
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mIsActive = false;
+ }
+ // To unblock all waiting consumers.
+ mCond.notify_all();
+ }
+
+ ConcurrentQueue() = default;
+
+ ConcurrentQueue(const ConcurrentQueue&) = delete;
+ ConcurrentQueue& operator=(const ConcurrentQueue&) = delete;
+
+ private:
+ mutable std::mutex mLock;
+ bool mIsActive GUARDED_BY(mLock) = true;
+ std::condition_variable mCond;
+ std::queue<T> mQueue GUARDED_BY(mLock);
+};
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_utils_common_include_ConcurrentQueue_H_
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 99f6431..9da2b14 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -17,12 +17,16 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleHalTypes_H_
#define android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleHalTypes_H_
+#include <aidl/android/hardware/automotive/vehicle/DiagnosticFloatSensorIndex.h>
+#include <aidl/android/hardware/automotive/vehicle/DiagnosticIntegerSensorIndex.h>
#include <aidl/android/hardware/automotive/vehicle/EvConnectorType.h>
#include <aidl/android/hardware/automotive/vehicle/EvsServiceState.h>
#include <aidl/android/hardware/automotive/vehicle/EvsServiceType.h>
#include <aidl/android/hardware/automotive/vehicle/FuelType.h>
+#include <aidl/android/hardware/automotive/vehicle/GetValueRequest.h>
#include <aidl/android/hardware/automotive/vehicle/GetValueResult.h>
#include <aidl/android/hardware/automotive/vehicle/PortLocationType.h>
+#include <aidl/android/hardware/automotive/vehicle/SetValueRequest.h>
#include <aidl/android/hardware/automotive/vehicle/SetValueResult.h>
#include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReport.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
index 61e475a..4b2a11a 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
@@ -80,7 +80,7 @@
virtual ~ObjectPool() = default;
virtual recyclable_ptr<T> obtain() {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock<std::mutex> lock(mLock);
INC_METRIC_IF_DEBUG(Obtained)
if (mObjects.empty()) {
INC_METRIC_IF_DEBUG(Created)
@@ -100,7 +100,7 @@
virtual T* createObject() = 0;
virtual void recycle(T* o) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock<std::mutex> lock(mLock);
size_t objectSize = mGetSizeFunc(*o);
if (objectSize > mMaxPoolObjectsSize ||
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
index ababf5e..dcc7031 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
@@ -40,11 +40,17 @@
// to get value for all areas for particular property.
//
// This class is thread-safe, however it uses blocking synchronization across all methods.
-class VehiclePropertyStore {
+class VehiclePropertyStore final {
public:
explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
: mValuePool(valuePool) {}
+ ~VehiclePropertyStore();
+
+ // Callback when a property value has been updated or a new value added.
+ using OnValueChangeCallback = std::function<void(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue&)>;
+
// Function that used to calculate unique token for given VehiclePropValue.
using TokenFunction = ::std::function<int64_t(
const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)>;
@@ -80,11 +86,15 @@
::android::base::Result<std::vector<VehiclePropValuePool::RecyclableType>>
readValuesForProperty(int32_t propId) const;
- // Read the value for the requested property.
+ // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
+ // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
+ // not configured.
::android::base::Result<VehiclePropValuePool::RecyclableType> readValue(
const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request) const;
- // Read the value for the requested property.
+ // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
+ // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
+ // not configured.
::android::base::Result<VehiclePropValuePool::RecyclableType> readValue(
int32_t prop, int32_t area = 0, int64_t token = 0) const;
@@ -97,6 +107,9 @@
const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
getConfig(int32_t propId) const;
+ // Set a callback that would be called when a property value has been updated.
+ void setOnValueChangeCallback(const OnValueChangeCallback& callback);
+
private:
struct RecordId {
int32_t area;
@@ -117,10 +130,11 @@
std::unordered_map<RecordId, VehiclePropValuePool::RecyclableType, RecordIdHash> values;
};
- mutable std::mutex mLock;
- std::unordered_map<int32_t, Record> mRecordsByPropId GUARDED_BY(mLock);
// {@code VehiclePropValuePool} is thread-safe.
std::shared_ptr<VehiclePropValuePool> mValuePool;
+ mutable std::mutex mLock;
+ std::unordered_map<int32_t, Record> mRecordsByPropId GUARDED_BY(mLock);
+ OnValueChangeCallback mOnValueChangeCallback GUARDED_BY(mLock);
const Record* getRecordLocked(int32_t propId) const;
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
index 0ff58f7..1cdc461 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
@@ -101,7 +101,7 @@
VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainRecyclable(
VehiclePropertyType type, size_t vectorSize) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock<std::mutex> lock(mLock);
assert(vectorSize > 0);
// VehiclePropertyType is not overlapping with vectorSize.
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 2869d1d..1a79230 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -19,6 +19,7 @@
#include "VehiclePropertyStore.h"
+#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
#include <android-base/format.h>
#include <math/HashCombine.h>
@@ -28,10 +29,12 @@
namespace automotive {
namespace vehicle {
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
using ::android::base::Result;
bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
@@ -49,6 +52,14 @@
return res;
}
+VehiclePropertyStore::~VehiclePropertyStore() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ // Recycling record requires mValuePool, so need to recycle them before destroying mValuePool.
+ mRecordsByPropId.clear();
+ mValuePool.reset();
+}
+
const VehiclePropertyStore::Record* VehiclePropertyStore::getRecordLocked(int32_t propId) const
REQUIRES(mLock) {
auto RecordIt = mRecordsByPropId.find(propId);
@@ -75,16 +86,16 @@
Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
const RecordId& recId, const Record& record) const REQUIRES(mLock) {
- auto it = record.values.find(recId);
- if (it == record.values.end()) {
- return Errorf("Record ID: {} is not found", recId.toString());
+ if (auto it = record.values.find(recId); it != record.values.end()) {
+ return mValuePool->obtain(*(it->second));
}
- return mValuePool->obtain(*(it->second));
+ return Error(toInt(StatusCode::NOT_AVAILABLE))
+ << "Record ID: " << recId.toString() << " is not found";
}
void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
VehiclePropertyStore::TokenFunction tokenFunc) {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
mRecordsByPropId[config.prop] = Record{
.propConfig = config,
@@ -94,45 +105,52 @@
Result<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
bool updateStatus) {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
- VehiclePropertyStore::Record* record = getRecordLocked(propValue->prop);
+ int32_t propId = propValue->prop;
+
+ VehiclePropertyStore::Record* record = getRecordLocked(propId);
if (record == nullptr) {
- return Errorf("property: {:d} not registered", propValue->prop);
+ return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
}
- if (!isGlobalProp(propValue->prop) &&
- getAreaConfig(*propValue, record->propConfig) == nullptr) {
- return Errorf("no config for property: {:d} area: {:d}", propValue->prop,
- propValue->areaId);
+ if (!isGlobalProp(propId) && getAreaConfig(*propValue, record->propConfig) == nullptr) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << "no config for property: " << propId << " area: " << propValue->areaId;
}
VehiclePropertyStore::RecordId recId = getRecordIdLocked(*propValue, *record);
- auto it = record->values.find(recId);
- if (it == record->values.end()) {
- record->values[recId] = std::move(propValue);
- if (!updateStatus) {
- record->values[recId]->status = VehiclePropertyStatus::AVAILABLE;
+ bool valueUpdated = true;
+ if (auto it = record->values.find(recId); it != record->values.end()) {
+ const VehiclePropValue* valueToUpdate = it->second.get();
+ int64_t oldTimestamp = valueToUpdate->timestamp;
+ VehiclePropertyStatus oldStatus = valueToUpdate->status;
+ // propValue is outdated and drops it.
+ if (oldTimestamp > propValue->timestamp) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << "outdated timestamp: " << propValue->timestamp;
}
- return {};
- }
- const VehiclePropValue* valueToUpdate = it->second.get();
- long oldTimestamp = valueToUpdate->timestamp;
- VehiclePropertyStatus oldStatus = valueToUpdate->status;
- // propValue is outdated and drops it.
- if (oldTimestamp > propValue->timestamp) {
- return Errorf("outdated timestamp: {:d}", propValue->timestamp);
- }
- record->values[recId] = std::move(propValue);
- if (!updateStatus) {
- record->values[recId]->status = oldStatus;
+ if (!updateStatus) {
+ propValue->status = oldStatus;
+ }
+
+ valueUpdated = (valueToUpdate->value != propValue->value ||
+ valueToUpdate->status != propValue->status ||
+ valueToUpdate->prop != propValue->prop ||
+ valueToUpdate->areaId != propValue->areaId);
+ } else if (!updateStatus) {
+ propValue->status = VehiclePropertyStatus::AVAILABLE;
}
+ record->values[recId] = std::move(propValue);
+ if (valueUpdated && mOnValueChangeCallback != nullptr) {
+ mOnValueChangeCallback(*(record->values[recId]));
+ }
return {};
}
void VehiclePropertyStore::removeValue(const VehiclePropValue& propValue) {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
VehiclePropertyStore::Record* record = getRecordLocked(propValue.prop);
if (record == nullptr) {
@@ -146,7 +164,7 @@
}
void VehiclePropertyStore::removeValuesForProperty(int32_t propId) {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
VehiclePropertyStore::Record* record = getRecordLocked(propId);
if (record == nullptr) {
@@ -157,7 +175,7 @@
}
std::vector<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readAllValues() const {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
std::vector<VehiclePropValuePool::RecyclableType> allValues;
@@ -172,13 +190,13 @@
Result<std::vector<VehiclePropValuePool::RecyclableType>>
VehiclePropertyStore::readValuesForProperty(int32_t propId) const {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
std::vector<VehiclePropValuePool::RecyclableType> values;
const VehiclePropertyStore::Record* record = getRecordLocked(propId);
if (record == nullptr) {
- return Errorf("property: {:d} not registered", propId);
+ return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
}
for (auto const& [_, value] : record->values) {
@@ -189,11 +207,12 @@
Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValue(
const VehiclePropValue& propValue) const {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
- const VehiclePropertyStore::Record* record = getRecordLocked(propValue.prop);
+ int32_t propId = propValue.prop;
+ const VehiclePropertyStore::Record* record = getRecordLocked(propId);
if (record == nullptr) {
- return Errorf("property: {:d} not registered", propValue.prop);
+ return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
}
VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
@@ -203,11 +222,11 @@
Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValue(int32_t propId,
int32_t areaId,
int64_t token) const {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
const VehiclePropertyStore::Record* record = getRecordLocked(propId);
if (record == nullptr) {
- return Errorf("property: {:d} not registered", propId);
+ return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
}
VehiclePropertyStore::RecordId recId{.area = isGlobalProp(propId) ? 0 : areaId, .token = token};
@@ -215,7 +234,7 @@
}
std::vector<VehiclePropConfig> VehiclePropertyStore::getAllConfigs() const {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
std::vector<VehiclePropConfig> configs;
configs.reserve(mRecordsByPropId.size());
@@ -226,16 +245,23 @@
}
Result<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId) const {
- std::lock_guard<std::mutex> g(mLock);
+ std::scoped_lock<std::mutex> g(mLock);
const VehiclePropertyStore::Record* record = getRecordLocked(propId);
if (record == nullptr) {
- return Errorf("property: {:d} not registered", propId);
+ return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
}
return &record->propConfig;
}
+void VehiclePropertyStore::setOnValueChangeCallback(
+ const VehiclePropertyStore::OnValueChangeCallback& callback) {
+ std::scoped_lock<std::mutex> g(mLock);
+
+ mOnValueChangeCallback = callback;
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index f1d218d..1f230e7 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -15,6 +15,7 @@
*/
#include <PropertyUtils.h>
+#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
#include <VehicleUtils.h>
#include <gmock/gmock.h>
@@ -27,6 +28,7 @@
namespace {
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
@@ -111,7 +113,8 @@
TEST_F(VehiclePropertyStoreTest, testGetConfigWithInvalidPropId) {
Result<const VehiclePropConfig*> result = mStore->getConfig(INVALID_PROP_ID);
- ASSERT_FALSE(result.ok()) << "expect error when getting a config for an invalid property ID";
+ EXPECT_FALSE(result.ok()) << "expect error when getting a config for an invalid property ID";
+ EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
}
std::vector<VehiclePropValue> getTestPropValues() {
@@ -180,7 +183,8 @@
TEST_F(VehiclePropertyStoreTest, testReadValuesForPropertyError) {
auto result = mStore->readValuesForProperty(INVALID_PROP_ID);
- ASSERT_FALSE(result.ok()) << "expect error when reading values for an invalid property";
+ EXPECT_FALSE(result.ok()) << "expect error when reading values for an invalid property";
+ EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
}
TEST_F(VehiclePropertyStoreTest, testReadValueOk) {
@@ -219,15 +223,19 @@
auto result = mStore->readValue(toInt(VehicleProperty::TIRE_PRESSURE), WHEEL_REAR_LEFT);
- ASSERT_FALSE(result.ok()) << "expect error when reading a value that has not been written";
+ EXPECT_FALSE(result.ok()) << "expect error when reading a value that has not been written";
+ EXPECT_EQ(result.error().code(), toInt(StatusCode::NOT_AVAILABLE));
}
TEST_F(VehiclePropertyStoreTest, testWriteValueError) {
auto v = mValuePool->obtain(VehiclePropertyType::FLOAT);
v->prop = INVALID_PROP_ID;
v->value.floatValues = {1.0};
- ASSERT_FALSE(mStore->writeValue(std::move(v)).ok())
- << "expect error when writing value for an invalid property ID";
+
+ auto result = mStore->writeValue(std::move(v));
+
+ EXPECT_FALSE(result.ok()) << "expect error when writing value for an invalid property ID";
+ EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
}
TEST_F(VehiclePropertyStoreTest, testWriteValueNoAreaConfig) {
@@ -236,8 +244,11 @@
v->value.floatValues = {1.0};
// There is no config for ALL_WHEELS.
v->areaId = ALL_WHEELS;
- ASSERT_FALSE(mStore->writeValue(std::move(v)).ok())
- << "expect error when writing value for an area without config";
+
+ auto result = mStore->writeValue(std::move(v));
+
+ EXPECT_FALSE(result.ok()) << "expect error when writing value for an area without config";
+ EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
}
TEST_F(VehiclePropertyStoreTest, testWriteOutdatedValue) {
@@ -254,8 +265,11 @@
v2->prop = toInt(VehicleProperty::TIRE_PRESSURE);
v2->value.floatValues = {180.0};
v2->areaId = WHEEL_FRONT_LEFT;
- ASSERT_FALSE(mStore->writeValue(std::move(v2)).ok())
- << "expect error when writing an outdated value";
+
+ auto result = mStore->writeValue(std::move(v2));
+
+ EXPECT_FALSE(result.ok()) << "expect error when writing an outdated value";
+ EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
}
TEST_F(VehiclePropertyStoreTest, testToken) {
@@ -300,8 +314,10 @@
}
mStore->removeValue(values[0]);
+ auto result = mStore->readValue(values[0]);
- ASSERT_FALSE(mStore->readValue(values[0]).ok()) << "expect error when reading a removed value";
+ EXPECT_FALSE(result.ok()) << "expect error when reading a removed value";
+ EXPECT_EQ(result.error().code(), toInt(StatusCode::NOT_AVAILABLE));
auto leftTirePressureResult = mStore->readValue(values[1]);
@@ -382,6 +398,57 @@
ASSERT_EQ(result.value()->status, VehiclePropertyStatus::AVAILABLE);
}
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNewValue) {
+ VehiclePropValue updatedValue;
+ mStore->setOnValueChangeCallback(
+ [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+ VehiclePropValue fuelCapacity = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .value = {.floatValues = {1.0}},
+ };
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ ASSERT_EQ(updatedValue, fuelCapacity);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackUpdateValue) {
+ VehiclePropValue updatedValue;
+ VehiclePropValue fuelCapacity = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .value = {.floatValues = {1.0}},
+ };
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ mStore->setOnValueChangeCallback(
+ [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+ fuelCapacity.value.floatValues[0] = 2.0;
+ fuelCapacity.timestamp = 1;
+
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ ASSERT_EQ(updatedValue, fuelCapacity);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNoUpdate) {
+ VehiclePropValue updatedValue{
+ .prop = INVALID_PROP_ID,
+ };
+ VehiclePropValue fuelCapacity = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .value = {.floatValues = {1.0}},
+ };
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ mStore->setOnValueChangeCallback(
+ [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+ // Write the same value again should succeed but should not trigger callback.
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 7ad3d31..131eb3b 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -14,10 +14,14 @@
* limitations under the License.
*/
+#include <ConcurrentQueue.h>
#include <PropertyUtils.h>
#include <VehicleUtils.h>
#include <gtest/gtest.h>
+
+#include <atomic>
+#include <thread>
#include <vector>
namespace android {
@@ -231,7 +235,7 @@
<< "vector size should always be 1 for single value type";
}
-TEST(VehicleUtilsTest, testCreateVehiclePropValueFloVecatVec) {
+TEST(VehicleUtilsTest, testCreateVehiclePropValueFloatVecMultiValues) {
std::unique_ptr<VehiclePropValue> value =
createVehiclePropValueVec(VehiclePropertyType::FLOAT_VEC, /*vecSize=*/2);
@@ -247,6 +251,90 @@
ASSERT_EQ(2u, value->value.byteValues.size());
}
+TEST(VehicleUtilsTest, testConcurrentQueueOneThread) {
+ ConcurrentQueue<int> queue;
+
+ queue.push(1);
+ queue.push(2);
+ auto result = queue.flush();
+
+ ASSERT_EQ(result, std::vector<int>({1, 2}));
+}
+
+TEST(VehicleUtilsTest, testConcurrentQueueMultipleThreads) {
+ ConcurrentQueue<int> queue;
+ std::vector<int> results;
+ std::atomic<bool> stop = false;
+
+ std::thread t1([&queue]() {
+ for (int i = 0; i < 100; i++) {
+ queue.push(0);
+ }
+ });
+ std::thread t2([&queue]() {
+ for (int i = 0; i < 100; i++) {
+ queue.push(1);
+ }
+ });
+ std::thread t3([&queue, &results, &stop]() {
+ while (!stop) {
+ queue.waitForItems();
+ for (int i : queue.flush()) {
+ results.push_back(i);
+ }
+ }
+
+ // After we stop, get all the remaining values in the queue.
+ for (int i : queue.flush()) {
+ results.push_back(i);
+ }
+ });
+
+ t1.join();
+ t2.join();
+
+ stop = true;
+ queue.deactivate();
+ t3.join();
+
+ size_t zeroCount = 0;
+ size_t oneCount = 0;
+ for (int i : results) {
+ if (i == 0) {
+ zeroCount++;
+ }
+ if (i == 1) {
+ oneCount++;
+ }
+ }
+
+ EXPECT_EQ(results.size(), static_cast<size_t>(200));
+ EXPECT_EQ(zeroCount, static_cast<size_t>(100));
+ EXPECT_EQ(oneCount, static_cast<size_t>(100));
+}
+
+TEST(VehicleUtilsTest, testConcurrentQueuePushAfterDeactivate) {
+ ConcurrentQueue<int> queue;
+
+ queue.deactivate();
+ queue.push(1);
+
+ ASSERT_TRUE(queue.flush().empty());
+}
+
+TEST(VehicleUtilsTest, testConcurrentQueueDeactivateNotifyWaitingThread) {
+ ConcurrentQueue<int> queue;
+
+ std::thread t([&queue]() {
+ // This would block until queue is deactivated.
+ queue.waitForItems();
+ });
+
+ queue.deactivate();
+
+ t.join();
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
new file mode 100644
index 0000000..dcee775
--- /dev/null
+++ b/camera/metadata/3.8/types.hal
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.8;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+import android.hardware.camera.metadata@3.5;
+import android.hardware.camera.metadata@3.6;
+import android.hardware.camera.metadata@3.7;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.7::CameraMetadataTag {
+ /** android.flash.info.strengthMaximumLevel [static, int32, public]
+ *
+ * <p>Maximum flashlight brightness level.</p>
+ */
+ ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_FLASH_INFO_END,
+
+ /** android.flash.info.strengthDefaultLevel [static, int32, public]
+ *
+ * <p>Default flashlight brightness level to be set via
+ * {android.hardware.camera2.CameraManager#setTorchStrengthLevel}.</p>
+ */
+ ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
+
+ ANDROID_FLASH_INFO_END_3_8,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index d8c9170..1def738 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -57,6 +57,7 @@
"android.hardware.graphics.common",
"android.hardware.keymaster",
"android.hardware.radio",
+ "android.hardware.uwb.fira_android",
// Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
// does not depend on this HAL, hence it is not declared in any manifests or matrices.
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index 1a33a9e..f254cd5 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 156070
#Context Hub team
arthuri@google.com
bduddie@google.com
stange@google.com
-
-#VTS team
-dshi@google.com
diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS
index 1a33a9e..2cf5bca 100644
--- a/contexthub/1.1/vts/functional/OWNERS
+++ b/contexthub/1.1/vts/functional/OWNERS
@@ -1,7 +1,2 @@
-#Context Hub team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-#VTS team
-dshi@google.com
+# Bug component: 156070
+include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.2/vts/functional/OWNERS b/contexthub/1.2/vts/functional/OWNERS
index 1a33a9e..2cf5bca 100644
--- a/contexthub/1.2/vts/functional/OWNERS
+++ b/contexthub/1.2/vts/functional/OWNERS
@@ -1,7 +1,2 @@
-#Context Hub team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-#VTS team
-dshi@google.com
+# Bug component: 156070
+include ../../../1.0/vts/functional/OWNERS
diff --git a/current.txt b/current.txt
index cb91843..1dbf5ab 100644
--- a/current.txt
+++ b/current.txt
@@ -906,7 +906,7 @@
# ABI preserving changes to HALs during Android T
62ace52d9c3ff1f60f94118557a2aaf0b953513e59dcd34d5f94ae28d4c7e780 android.hardware.fastboot@1.0::IFastboot
-b4a59462aa7d1346ee3eaa06a8e13682462746cf1be62ed2a2bd46bf404d01b7 android.hardware.graphics.composer@2.4::IComposerClient
+f767a132ef28275294db15353f14f3876a4048770751931a77d038d4228f2cb7 android.hardware.graphics.composer@2.4::IComposerClient
ca62a2a95d173ed323309e5e00f653ad3cceec82a6e5e4976a249cb5aafe2515 android.hardware.neuralnetworks@1.2::types
fa76bced6b1b71c40fc706c508a9011284c57f57831cd0cf5f45653ed4ea463e android.hardware.neuralnetworks@1.3::types
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
index ea06752..31b0dc7 100644
--- a/graphics/composer/2.2/vts/functional/OWNERS
+++ b/graphics/composer/2.2/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 25423
# Graphics team
adyabr@google.com
lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS
index ea06752..31b0dc7 100644
--- a/graphics/composer/2.3/vts/functional/OWNERS
+++ b/graphics/composer/2.3/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 25423
# Graphics team
adyabr@google.com
lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index e27fd6e..476302f 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -34,9 +34,7 @@
/**
* The configuration group ID (as int32_t) this config is associated to.
* Switching between configurations within the same group may be done seamlessly
- * in some conditions via setActiveConfigWithConstraints. Configurations which
- * share the same config group are similar in all attributes except for the
- * vsync period.
+ * in some conditions via setActiveConfigWithConstraints.
*/
CONFIG_GROUP = 7,
};
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
index ea06752..31b0dc7 100644
--- a/graphics/composer/2.4/vts/functional/OWNERS
+++ b/graphics/composer/2.4/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 25423
# Graphics team
adyabr@google.com
lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 5aceda7..b071f71 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -19,8 +19,6 @@
#include <algorithm>
#include <regex>
#include <thread>
-#include <unordered_map>
-#include <utility>
#include <android-base/logging.h>
#include <android-base/properties.h>
@@ -317,59 +315,6 @@
}
}
-TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4_ConfigsInAGroupDifferOnlyByVsyncPeriod) {
- struct Resolution {
- int32_t width, height;
- };
- struct Dpi {
- int32_t x, y;
- };
- for (const auto& display : mDisplays) {
- std::vector<Config> configs = mComposerClient->getDisplayConfigs(display.get());
- std::unordered_map<int32_t, Resolution> configGroupToResolutionMap;
- std::unordered_map<int32_t, Dpi> configGroupToDpiMap;
- for (auto config : configs) {
- const auto configGroup = mComposerClient->getDisplayAttribute_2_4(
- display.get(), config, IComposerClient::Attribute::CONFIG_GROUP);
- const auto width = mComposerClient->getDisplayAttribute_2_4(
- display.get(), config, IComposerClient::Attribute::WIDTH);
- const auto height = mComposerClient->getDisplayAttribute_2_4(
- display.get(), config, IComposerClient::Attribute::HEIGHT);
- if (configGroupToResolutionMap.find(configGroup) == configGroupToResolutionMap.end()) {
- configGroupToResolutionMap[configGroup] = {width, height};
- }
- EXPECT_EQ(configGroupToResolutionMap[configGroup].width, width);
- EXPECT_EQ(configGroupToResolutionMap[configGroup].height, height);
-
- int32_t dpiX = -1;
- mComposerClient->getRaw()->getDisplayAttribute_2_4(
- display.get(), config, IComposerClient::Attribute::DPI_X,
- [&](const auto& tmpError, const auto& value) {
- if (tmpError == Error::NONE) {
- dpiX = value;
- }
- });
- int32_t dpiY = -1;
- mComposerClient->getRaw()->getDisplayAttribute_2_4(
- display.get(), config, IComposerClient::Attribute::DPI_Y,
- [&](const auto& tmpError, const auto& value) {
- if (tmpError == Error::NONE) {
- dpiY = value;
- }
- });
- if (dpiX == -1 && dpiY == -1) {
- continue;
- }
-
- if (configGroupToDpiMap.find(configGroup) == configGroupToDpiMap.end()) {
- configGroupToDpiMap[configGroup] = {dpiX, dpiY};
- }
- EXPECT_EQ(configGroupToDpiMap[configGroup].x, dpiX);
- EXPECT_EQ(configGroupToDpiMap[configGroup].y, dpiY);
- }
- }
-}
-
TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) {
VsyncPeriodNanos vsyncPeriodNanos;
EXPECT_EQ(Error::BAD_DISPLAY,
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 5006185..e33c653 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -67,3 +67,22 @@
],
export_include_dirs: ["include"],
}
+
+cc_library_headers {
+ name: "android.hardware.graphics.composer3-command-buffer",
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
+ "libbase",
+ "libfmq",
+ "libsync",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+ export_shared_lib_headers: [
+ "libfmq",
+ "libsync",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/aidl/OWNERS b/graphics/composer/aidl/OWNERS
new file mode 100644
index 0000000..9028d9d
--- /dev/null
+++ b/graphics/composer/aidl/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 1075131
+
+# Graphics team
+adyabr@google.com
+alecmouri@google.com
+sumir@google.com
\ No newline at end of file
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
index 557b3f8..9c49583 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
@@ -38,4 +38,5 @@
SIDEBAND_STREAM = 1,
SKIP_CLIENT_COLOR_TRANSFORM = 2,
PRESENT_FENCE_IS_NOT_RELIABLE = 3,
+ SKIP_VALIDATE = 4,
}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index 8824f5a..5c37018 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -40,7 +40,6 @@
void destroyVirtualDisplay(long display);
android.hardware.graphics.composer3.ExecuteCommandsStatus executeCommands(int inLength, in android.hardware.common.NativeHandle[] inHandles);
int getActiveConfig(long display);
- void getClientTargetSupport(long display, int width, int height, in android.hardware.graphics.composer3.ClientTargetProperty clientTargetProperty);
android.hardware.graphics.composer3.ColorMode[] getColorModes(long display);
float[] getDataspaceSaturationMatrix(android.hardware.graphics.common.Dataspace dataspace);
int getDisplayAttribute(long display, int config, android.hardware.graphics.composer3.DisplayAttribute attribute);
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
index 028b6f5..ea619ae 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
@@ -46,4 +46,15 @@
* representation of the actual present time of a frame.
*/
PRESENT_FENCE_IS_NOT_RELIABLE = 3,
+ /**
+ * Specifies that a device is able to skip the validateDisplay call before
+ * receiving a call to presentDisplay. The client will always skip
+ * validateDisplay and try to call presentDisplay regardless of the changes
+ * in the properties of the layers. If the device returns anything else than
+ * no error, it will call validateDisplay then presentDisplay again.
+ * For this capability to be worthwhile the device implementation of
+ * presentDisplay should fail as fast as possible in the case a
+ * validateDisplay step is needed.
+ */
+ SKIP_VALIDATE = 4,
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 20a6ffc..2a9545d 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -189,25 +189,6 @@
int getActiveConfig(long display);
/**
- * 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 clientTargetProperty is the client target format and dataspace.
- * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
- * @exception EX_UNSUPPORTED when the given configuration is not supported.
- */
- void getClientTargetSupport(
- long display, int width, int height, in ClientTargetProperty clientTargetProperty);
-
- /**
* Returns the color modes supported on this display.
*
* All devices must support at least ColorMode::NATIVE.
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
index a593e90..d59190d 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
@@ -70,6 +70,9 @@
static_cast<aidl::android::hardware::graphics::composer3::Capability>(
::android::hardware::graphics::composer::V2_1::IComposer::Capability::
PRESENT_FENCE_IS_NOT_RELIABLE));
+// HWC2_CAPABILITY_SKIP_VALIDATE was never defined for HIDL, so we just hardcode its value
+static_assert(aidl::android::hardware::graphics::composer3::Capability::SKIP_VALIDATE ==
+ static_cast<aidl::android::hardware::graphics::composer3::Capability>(4));
static_assert(aidl::android::hardware::graphics::composer3::LayerRequest::CLEAR_CLIENT_TARGET ==
static_cast<aidl::android::hardware::graphics::composer3::LayerRequest>(
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
index d892681..40dfe06 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -13,17 +13,15 @@
#undef LOG_TAG
#define LOG_TAG "VtsHalGraphicsComposer3_TargetTest"
-typedef uint64_t DisplayId;
-
namespace aidl::android::hardware::graphics::composer3::vts {
namespace {
class VtsDisplay {
public:
- VtsDisplay(DisplayId displayId, int32_t displayWidth, int32_t displayHeight)
+ VtsDisplay(uint64_t displayId, int32_t displayWidth, int32_t displayHeight)
: mDisplayId(displayId), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight) {}
- DisplayId get() const { return mDisplayId; }
+ uint64_t get() const { return mDisplayId; }
void setDimensions(int32_t displayWidth, int32_t displayHeight) {
mDisplayWidth = displayWidth;
@@ -31,7 +29,7 @@
}
private:
- const DisplayId mDisplayId;
+ const uint64_t mDisplayId;
int32_t mDisplayWidth;
int32_t mDisplayHeight;
};
@@ -51,7 +49,7 @@
// 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
- DisplayId GetInvalidDisplayId() {
+ uint64_t GetInvalidDisplayId() {
uint64_t id = std::numeric_limits<uint64_t>::max();
while (id > 0) {
if (std::none_of(mDisplays.begin(), mDisplays.end(),
@@ -65,8 +63,8 @@
}
std::shared_ptr<IComposer> mComposer;
- std::shared_ptr<IComposerClient> mComposerClient{};
- DisplayId mInvalidDisplayId;
+ std::shared_ptr<IComposerClient> mComposerClient;
+ uint64_t mInvalidDisplayId;
std::vector<VtsDisplay>
mDisplays; // TODO(b/202401906) populate all the displays available for test.
};
@@ -74,15 +72,16 @@
TEST_P(GraphicsComposerAidlTest, getDisplayCapabilitiesBadDisplay) {
std::vector<DisplayCapability> capabilities;
const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
+
+ EXPECT_FALSE(error.isOk());
EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
}
TEST_P(GraphicsComposerAidlTest, getDisplayCapabilities) {
for (const auto& display : mDisplays) {
std::vector<DisplayCapability> capabilities;
- const auto error = mComposerClient->getDisplayCapabilities(display.get(), &capabilities);
- EXPECT_NE(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+ EXPECT_TRUE(mComposerClient->getDisplayCapabilities(display.get(), &capabilities).isOk());
}
}
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h
new file mode 100644
index 0000000..d02cf9c
--- /dev/null
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h
@@ -0,0 +1,895 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <aidl/android/hardware/graphics/composer3/BlendMode.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetProperty.h>
+#include <aidl/android/hardware/graphics/composer3/Color.h>
+#include <aidl/android/hardware/graphics/composer3/Command.h>
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/FloatColor.h>
+#include <aidl/android/hardware/graphics/composer3/HandleIndex.h>
+#include <aidl/android/hardware/graphics/composer3/IComposer.h>
+#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
+#include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
+
+#include <aidl/android/hardware/graphics/common/ColorTransform.h>
+#include <aidl/android/hardware/graphics/common/FRect.h>
+#include <aidl/android/hardware/graphics/common/Rect.h>
+#include <aidl/android/hardware/graphics/common/Transform.h>
+
+#include <fmq/AidlMessageQueue.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+using aidl::android::hardware::graphics::common::ColorTransform;
+using aidl::android::hardware::graphics::common::Dataspace;
+using aidl::android::hardware::graphics::common::FRect;
+using aidl::android::hardware::graphics::common::Rect;
+using aidl::android::hardware::graphics::common::Transform;
+
+using aidl::android::hardware::graphics::composer3::BlendMode;
+using aidl::android::hardware::graphics::composer3::ClientTargetProperty;
+using aidl::android::hardware::graphics::composer3::Color;
+using aidl::android::hardware::graphics::composer3::Command;
+using aidl::android::hardware::graphics::composer3::Composition;
+using aidl::android::hardware::graphics::composer3::FloatColor;
+using aidl::android::hardware::graphics::composer3::HandleIndex;
+using aidl::android::hardware::graphics::composer3::PerFrameMetadata;
+using aidl::android::hardware::graphics::composer3::PerFrameMetadataBlob;
+
+using aidl::android::hardware::common::NativeHandle;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using android::AidlMessageQueue;
+using CommandQueueType = AidlMessageQueue<int32_t, SynchronizedReadWrite>;
+using aidl::android::hardware::common::fmq::MQDescriptor;
+using DescriptorType = MQDescriptor<int32_t, SynchronizedReadWrite>;
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+// This class helps build a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase {
+ public:
+ CommandWriterBase(uint32_t initialMaxSize) : mDataMaxSize(initialMaxSize) {
+ mData = std::make_unique<int32_t[]>(mDataMaxSize);
+ reset();
+ }
+
+ virtual ~CommandWriterBase() { reset(); }
+
+ void reset() {
+ mDataWritten = 0;
+ mCommandEnd = 0;
+
+ // handles in mDataHandles are owned by the caller
+ mDataHandles.clear();
+
+ // handles in mTemporaryHandles are owned by the writer
+ for (auto handle : mTemporaryHandles) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ mTemporaryHandles.clear();
+ }
+
+ Command getCommand(uint32_t offset) {
+ uint32_t val = (offset < mDataWritten) ? mData[offset] : 0;
+ return static_cast<Command>(val & static_cast<uint32_t>(Command::OPCODE_MASK));
+ }
+
+ bool writeQueue(bool* outQueueChanged, int32_t* outCommandLength,
+ std::vector<NativeHandle>* outCommandHandles) {
+ if (mDataWritten == 0) {
+ *outQueueChanged = false;
+ *outCommandLength = 0;
+ outCommandHandles->clear();
+ return true;
+ }
+
+ // After data are written to the queue, it may not be read by the
+ // remote reader when
+ //
+ // - the writer does not send them (because of other errors)
+ // - the hwbinder transaction fails
+ // - the reader does not read them (because of other errors)
+ //
+ // Discard the stale data here.
+ size_t staleDataSize = mQueue ? mQueue->availableToRead() : 0;
+ if (staleDataSize > 0) {
+ ALOGW("discarding stale data from message queue");
+ CommandQueueType::MemTransaction tx;
+ if (mQueue->beginRead(staleDataSize, &tx)) {
+ mQueue->commitRead(staleDataSize);
+ }
+ }
+
+ // write data to queue, optionally resizing it
+ if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) {
+ if (!mQueue->write(mData.get(), mDataWritten)) {
+ ALOGE("failed to write commands to message queue");
+ return false;
+ }
+
+ *outQueueChanged = false;
+ } else {
+ auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize);
+ if (!newQueue->isValid() || !newQueue->write(mData.get(), mDataWritten)) {
+ ALOGE("failed to prepare a new message queue ");
+ return false;
+ }
+
+ mQueue = std::move(newQueue);
+ *outQueueChanged = true;
+ }
+
+ *outCommandLength = mDataWritten;
+ *outCommandHandles = std::move(mDataHandles);
+
+ return true;
+ }
+
+ DescriptorType getMQDescriptor() const {
+ return (mQueue) ? mQueue->dupeDesc() : DescriptorType{};
+ }
+
+ static constexpr uint16_t kSelectDisplayLength = 2;
+ void selectDisplay(int64_t display) {
+ beginCommand(Command::SELECT_DISPLAY, kSelectDisplayLength);
+ write64(display);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSelectLayerLength = 2;
+ void selectLayer(int64_t layer) {
+ beginCommand(Command::SELECT_LAYER, kSelectLayerLength);
+ write64(layer);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetErrorLength = 2;
+ void setError(uint32_t location, int32_t error) {
+ beginCommand(Command::SET_ERROR, kSetErrorLength);
+ write(location);
+ writeSigned(error);
+ endCommand();
+ }
+
+ static constexpr uint32_t kPresentOrValidateDisplayResultLength = 1;
+ void setPresentOrValidateResult(uint32_t state) {
+ beginCommand(Command::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT,
+ kPresentOrValidateDisplayResultLength);
+ write(state);
+ endCommand();
+ }
+
+ void setChangedCompositionTypes(const std::vector<int64_t>& layers,
+ const std::vector<Composition>& types) {
+ size_t totalLayers = std::min(layers.size(), types.size());
+ size_t currentLayer = 0;
+
+ while (currentLayer < totalLayers) {
+ size_t count =
+ std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
+
+ beginCommand(Command::SET_CHANGED_COMPOSITION_TYPES, count * 3);
+ for (size_t i = 0; i < count; i++) {
+ write64(layers[currentLayer + i]);
+ writeSigned(static_cast<int32_t>(types[currentLayer + i]));
+ }
+ endCommand();
+
+ currentLayer += count;
+ }
+ }
+
+ void setDisplayRequests(uint32_t displayRequestMask, const std::vector<int64_t>& layers,
+ const std::vector<uint32_t>& layerRequestMasks) {
+ size_t totalLayers = std::min(layers.size(), layerRequestMasks.size());
+ size_t currentLayer = 0;
+
+ while (currentLayer < totalLayers) {
+ size_t count =
+ std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength - 1) / 3);
+
+ beginCommand(Command::SET_DISPLAY_REQUESTS, 1 + count * 3);
+ write(displayRequestMask);
+ for (size_t i = 0; i < count; i++) {
+ write64(layers[currentLayer + i]);
+ write(static_cast<int32_t>(layerRequestMasks[currentLayer + i]));
+ }
+ endCommand();
+
+ currentLayer += count;
+ }
+ }
+
+ static constexpr uint16_t kSetPresentFenceLength = 1;
+ void setPresentFence(int presentFence) {
+ beginCommand(Command::SET_PRESENT_FENCE, kSetPresentFenceLength);
+ writeFence(presentFence);
+ endCommand();
+ }
+
+ void setReleaseFences(const std::vector<int64_t>& layers,
+ const std::vector<int>& releaseFences) {
+ size_t totalLayers = std::min(layers.size(), releaseFences.size());
+ size_t currentLayer = 0;
+
+ while (currentLayer < totalLayers) {
+ size_t count =
+ std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
+
+ beginCommand(Command::SET_RELEASE_FENCES, count * 3);
+ for (size_t i = 0; i < count; i++) {
+ write64(layers[currentLayer + i]);
+ writeFence(releaseFences[currentLayer + i]);
+ }
+ endCommand();
+
+ currentLayer += count;
+ }
+ }
+
+ static constexpr uint16_t kSetColorTransformLength = 17;
+ void setColorTransform(const float* matrix, ColorTransform hint) {
+ beginCommand(Command::SET_COLOR_TRANSFORM, kSetColorTransformLength);
+ for (int i = 0; i < 16; i++) {
+ writeFloat(matrix[i]);
+ }
+ writeSigned(static_cast<int32_t>(hint));
+ endCommand();
+ }
+
+ void setClientTarget(uint32_t slot, const native_handle_t* target, int acquireFence,
+ Dataspace dataspace, const std::vector<Rect>& damage) {
+ setClientTargetInternal(slot, target, acquireFence, static_cast<int32_t>(dataspace),
+ damage);
+ }
+
+ static constexpr uint16_t kSetOutputBufferLength = 3;
+ void setOutputBuffer(uint32_t slot, const native_handle_t* buffer, int releaseFence) {
+ beginCommand(Command::SET_OUTPUT_BUFFER, kSetOutputBufferLength);
+ write(slot);
+ writeHandle(buffer, true);
+ writeFence(releaseFence);
+ endCommand();
+ }
+
+ static constexpr uint16_t kValidateDisplayLength = 0;
+ void validateDisplay() {
+ beginCommand(Command::VALIDATE_DISPLAY, kValidateDisplayLength);
+ endCommand();
+ }
+
+ static constexpr uint16_t kPresentOrValidateDisplayLength = 0;
+ void presentOrvalidateDisplay() {
+ beginCommand(Command::PRESENT_OR_VALIDATE_DISPLAY, kPresentOrValidateDisplayLength);
+ endCommand();
+ }
+
+ static constexpr uint16_t kAcceptDisplayChangesLength = 0;
+ void acceptDisplayChanges() {
+ beginCommand(Command::ACCEPT_DISPLAY_CHANGES, kAcceptDisplayChangesLength);
+ endCommand();
+ }
+
+ static constexpr uint16_t kPresentDisplayLength = 0;
+ void presentDisplay() {
+ beginCommand(Command::PRESENT_DISPLAY, kPresentDisplayLength);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerCursorPositionLength = 2;
+ void setLayerCursorPosition(int32_t x, int32_t y) {
+ beginCommand(Command::SET_LAYER_CURSOR_POSITION, kSetLayerCursorPositionLength);
+ writeSigned(x);
+ writeSigned(y);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerBufferLength = 3;
+ void setLayerBuffer(uint32_t slot, const native_handle_t* buffer, int acquireFence) {
+ beginCommand(Command::SET_LAYER_BUFFER, kSetLayerBufferLength);
+ write(slot);
+ writeHandle(buffer, true);
+ writeFence(acquireFence);
+ endCommand();
+ }
+
+ void setLayerSurfaceDamage(const std::vector<Rect>& damage) {
+ bool doWrite = (damage.size() <= kMaxLength / 4);
+ size_t length = (doWrite) ? damage.size() * 4 : 0;
+
+ beginCommand(Command::SET_LAYER_SURFACE_DAMAGE, length);
+ // When there are too many rectangles in the damage region and doWrite
+ // is false, we write no rectangle at all which means the entire
+ // layer is damaged.
+ if (doWrite) {
+ writeRegion(damage);
+ }
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerBlendModeLength = 1;
+ void setLayerBlendMode(BlendMode mode) {
+ beginCommand(Command::SET_LAYER_BLEND_MODE, kSetLayerBlendModeLength);
+ writeSigned(static_cast<int32_t>(mode));
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerColorLength = 1;
+ void setLayerColor(Color color) {
+ beginCommand(Command::SET_LAYER_COLOR, kSetLayerColorLength);
+ writeColor(color);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerCompositionTypeLength = 1;
+ void setLayerCompositionType(Composition type) {
+ beginCommand(Command::SET_LAYER_COMPOSITION_TYPE, kSetLayerCompositionTypeLength);
+ writeSigned(static_cast<int32_t>(type));
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerDataspaceLength = 1;
+ void setLayerDataspace(Dataspace dataspace) {
+ setLayerDataspaceInternal(static_cast<int32_t>(dataspace));
+ }
+
+ static constexpr uint16_t kSetLayerDisplayFrameLength = 4;
+ void setLayerDisplayFrame(const Rect& frame) {
+ beginCommand(Command::SET_LAYER_DISPLAY_FRAME, kSetLayerDisplayFrameLength);
+ writeRect(frame);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerPlaneAlphaLength = 1;
+ void setLayerPlaneAlpha(float alpha) {
+ beginCommand(Command::SET_LAYER_PLANE_ALPHA, kSetLayerPlaneAlphaLength);
+ writeFloat(alpha);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerSidebandStreamLength = 1;
+ void setLayerSidebandStream(const native_handle_t* stream) {
+ beginCommand(Command::SET_LAYER_SIDEBAND_STREAM, kSetLayerSidebandStreamLength);
+ writeHandle(stream);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerSourceCropLength = 4;
+ void setLayerSourceCrop(const FRect& crop) {
+ beginCommand(Command::SET_LAYER_SOURCE_CROP, kSetLayerSourceCropLength);
+ writeFRect(crop);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerTransformLength = 1;
+ void setLayerTransform(Transform transform) {
+ beginCommand(Command::SET_LAYER_TRANSFORM, kSetLayerTransformLength);
+ writeSigned(static_cast<int32_t>(transform));
+ endCommand();
+ }
+
+ void setLayerVisibleRegion(const std::vector<Rect>& visible) {
+ bool doWrite = (visible.size() <= kMaxLength / 4);
+ size_t length = (doWrite) ? visible.size() * 4 : 0;
+
+ beginCommand(Command::SET_LAYER_VISIBLE_REGION, length);
+ // When there are too many rectangles in the visible region and
+ // doWrite is false, we write no rectangle at all which means the
+ // entire layer is visible.
+ if (doWrite) {
+ writeRegion(visible);
+ }
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerZOrderLength = 1;
+ void setLayerZOrder(uint32_t z) {
+ beginCommand(Command::SET_LAYER_Z_ORDER, kSetLayerZOrderLength);
+ write(z);
+ endCommand();
+ }
+
+ void setLayerPerFrameMetadata(const std::vector<PerFrameMetadata>& metadataVec) {
+ beginCommand(Command::SET_LAYER_PER_FRAME_METADATA, metadataVec.size() * 2);
+ for (const auto& metadata : metadataVec) {
+ writeSigned(static_cast<int32_t>(metadata.key));
+ writeFloat(metadata.value);
+ }
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerColorTransformLength = 16;
+ void setLayerColorTransform(const float* matrix) {
+ beginCommand(Command::SET_LAYER_COLOR_TRANSFORM, kSetLayerColorTransformLength);
+ for (int i = 0; i < 16; i++) {
+ writeFloat(matrix[i]);
+ }
+ endCommand();
+ }
+
+ void setLayerPerFrameMetadataBlobs(const std::vector<PerFrameMetadataBlob>& metadata) {
+ // in units of uint32_t's
+ size_t commandLength = 0;
+
+ if (metadata.size() > std::numeric_limits<uint32_t>::max()) {
+ LOG_FATAL("too many metadata blobs - dynamic metadata size is too large");
+ return;
+ }
+
+ // space for numElements
+ commandLength += 1;
+
+ for (auto metadataBlob : metadata) {
+ commandLength += 1; // key of metadata blob
+ commandLength += 1; // size information of metadata blob
+
+ // metadata content size
+ size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t);
+ commandLength += metadataSize;
+ commandLength +=
+ (metadataBlob.blob.size() - (metadataSize * sizeof(uint32_t)) > 0) ? 1 : 0;
+ }
+
+ if (commandLength > std::numeric_limits<uint16_t>::max()) {
+ LOG_FATAL("dynamic metadata size is too large");
+ return;
+ }
+
+ // Blobs are written as:
+ // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...}
+ uint16_t length = static_cast<uint16_t>(commandLength);
+ beginCommand(Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
+ write(static_cast<uint32_t>(metadata.size()));
+ for (auto metadataBlob : metadata) {
+ writeSigned(static_cast<int32_t>(metadataBlob.key));
+ write(static_cast<uint32_t>(metadataBlob.blob.size()));
+ writeBlob(static_cast<uint32_t>(metadataBlob.blob.size()), metadataBlob.blob.data());
+ }
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerFloatColorLength = 4;
+ void setLayerFloatColor(FloatColor color) {
+ beginCommand(Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength);
+ writeFloatColor(color);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetClientTargetPropertyLength = 2;
+ void setClientTargetProperty(const ClientTargetProperty& clientTargetProperty) {
+ beginCommand(Command::SET_CLIENT_TARGET_PROPERTY, kSetClientTargetPropertyLength);
+ writeSigned(static_cast<int32_t>(clientTargetProperty.pixelFormat));
+ writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
+ endCommand();
+ }
+
+ void setLayerGenericMetadata(const std::string& key, const bool mandatory,
+ const std::vector<uint8_t>& value) {
+ const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
+ if (commandSize > std::numeric_limits<uint16_t>::max()) {
+ LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
+ return;
+ }
+
+ beginCommand(Command::SET_LAYER_GENERIC_METADATA, static_cast<uint16_t>(commandSize));
+ write(key.size());
+ writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
+ write(mandatory);
+ write(value.size());
+ writeBlob(value.size(), value.data());
+ endCommand();
+ }
+
+ protected:
+ template <typename T>
+ void beginCommand(T command, uint16_t length) {
+ beginCommandBase(static_cast<Command>(command), length);
+ }
+
+ void setClientTargetInternal(uint32_t slot, const native_handle_t* target, int acquireFence,
+ int32_t dataspace, const std::vector<Rect>& damage) {
+ bool doWrite = (damage.size() <= (kMaxLength - 4) / 4);
+ size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0);
+
+ beginCommand(Command::SET_CLIENT_TARGET, length);
+ write(slot);
+ writeHandle(target, true);
+ writeFence(acquireFence);
+ writeSigned(dataspace);
+ // When there are too many rectangles in the damage region and doWrite
+ // is false, we write no rectangle at all which means the entire
+ // client target is damaged.
+ if (doWrite) {
+ writeRegion(damage);
+ }
+ endCommand();
+ }
+
+ void setLayerDataspaceInternal(int32_t dataspace) {
+ beginCommand(Command::SET_LAYER_DATASPACE, kSetLayerDataspaceLength);
+ writeSigned(dataspace);
+ endCommand();
+ }
+
+ void beginCommandBase(Command command, uint16_t length) {
+ if (mCommandEnd) {
+ LOG_FATAL("endCommand was not called before command 0x%x", command);
+ }
+
+ growData(1 + length);
+ write(static_cast<uint32_t>(command) | length);
+
+ mCommandEnd = mDataWritten + length;
+ }
+
+ void endCommand() {
+ if (!mCommandEnd) {
+ LOG_FATAL("beginCommand was not called");
+ } else if (mDataWritten > mCommandEnd) {
+ LOG_FATAL("too much data written");
+ mDataWritten = mCommandEnd;
+ } else if (mDataWritten < mCommandEnd) {
+ LOG_FATAL("too little data written");
+ while (mDataWritten < mCommandEnd) {
+ write(0);
+ }
+ }
+
+ mCommandEnd = 0;
+ }
+
+ void write(uint32_t val) { mData[mDataWritten++] = val; }
+
+ void writeSigned(int32_t val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
+
+ void writeFloat(float val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
+
+ void write64(uint64_t val) {
+ uint32_t lo = static_cast<uint32_t>(val & 0xffffffff);
+ uint32_t hi = static_cast<uint32_t>(val >> 32);
+ write(lo);
+ write(hi);
+ }
+
+ void writeRect(const Rect& rect) {
+ writeSigned(rect.left);
+ writeSigned(rect.top);
+ writeSigned(rect.right);
+ writeSigned(rect.bottom);
+ }
+
+ void writeRegion(const std::vector<Rect>& region) {
+ for (const auto& rect : region) {
+ writeRect(rect);
+ }
+ }
+
+ void writeFRect(const FRect& rect) {
+ writeFloat(rect.left);
+ writeFloat(rect.top);
+ writeFloat(rect.right);
+ writeFloat(rect.bottom);
+ }
+
+ void writeColor(const Color& color) {
+ write((color.r << 0) | (color.g << 8) | (color.b << 16) | (color.a << 24));
+ }
+
+ void writeFloatColor(const FloatColor& color) {
+ writeFloat(color.r);
+ writeFloat(color.g);
+ writeFloat(color.b);
+ writeFloat(color.a);
+ }
+
+ void writeBlob(uint32_t length, const unsigned char* blob) {
+ memcpy(&mData[mDataWritten], blob, length);
+ uint32_t numElements = length / 4;
+ mDataWritten += numElements;
+ mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0;
+ }
+
+ // ownership of handle is not transferred
+ void writeHandle(const native_handle_t* handle, bool useCache) {
+ if (!handle) {
+ writeSigned(
+ static_cast<int32_t>((useCache) ? HandleIndex::CACHED : HandleIndex::EMPTY));
+ return;
+ }
+
+ mDataHandles.push_back(::android::dupToAidl(handle));
+ writeSigned(mDataHandles.size() - 1);
+ }
+
+ void writeHandle(const native_handle_t* handle) { writeHandle(handle, false); }
+
+ // ownership of fence is transferred
+ void writeFence(int fence) {
+ native_handle_t* handle = nullptr;
+ if (fence >= 0) {
+ handle = getTemporaryHandle(1, 0);
+ if (handle) {
+ handle->data[0] = fence;
+ } else {
+ ALOGW("failed to get temporary handle for fence %d", fence);
+ sync_wait(fence, -1);
+ close(fence);
+ }
+ }
+
+ writeHandle(handle);
+ }
+
+ native_handle_t* getTemporaryHandle(int numFds, int numInts) {
+ native_handle_t* handle = native_handle_create(numFds, numInts);
+ if (handle) {
+ mTemporaryHandles.push_back(handle);
+ }
+ return handle;
+ }
+
+ static constexpr uint16_t kMaxLength = std::numeric_limits<uint16_t>::max();
+
+ std::unique_ptr<int32_t[]> mData;
+ uint32_t mDataWritten;
+
+ private:
+ void growData(uint32_t grow) {
+ uint32_t newWritten = mDataWritten + grow;
+ if (newWritten < mDataWritten) {
+ LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32 ", growing by %" PRIu32,
+ mDataWritten, grow);
+ }
+
+ if (newWritten <= mDataMaxSize) {
+ return;
+ }
+
+ uint32_t newMaxSize = mDataMaxSize << 1;
+ if (newMaxSize < newWritten) {
+ newMaxSize = newWritten;
+ }
+
+ auto newData = std::make_unique<int32_t[]>(newMaxSize);
+ std::copy_n(mData.get(), mDataWritten, newData.get());
+ mDataMaxSize = newMaxSize;
+ mData = std::move(newData);
+ }
+
+ uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
+
+ uint32_t mDataMaxSize;
+ // end offset of the current command
+ uint32_t mCommandEnd;
+
+ std::vector<NativeHandle> mDataHandles;
+ std::vector<native_handle_t*> mTemporaryHandles;
+
+ std::unique_ptr<CommandQueueType> mQueue;
+};
+
+// This class helps parse a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase {
+ public:
+ CommandReaderBase() : mDataMaxSize(0) { reset(); }
+
+ bool setMQDescriptor(const DescriptorType& descriptor) {
+ mQueue = std::make_unique<CommandQueueType>(descriptor, false);
+ if (mQueue->isValid()) {
+ return true;
+ } else {
+ mQueue = nullptr;
+ return false;
+ }
+ }
+
+ bool readQueue(int32_t commandLength, std::vector<NativeHandle> commandHandles) {
+ if (!mQueue) {
+ return false;
+ }
+
+ auto quantumCount = mQueue->getQuantumCount();
+ if (mDataMaxSize < quantumCount) {
+ mDataMaxSize = quantumCount;
+ mData = std::make_unique<int32_t[]>(mDataMaxSize);
+ }
+
+ if (commandLength > mDataMaxSize || !mQueue->read(mData.get(), commandLength)) {
+ ALOGE("failed to read commands from message queue");
+ return false;
+ }
+
+ mDataSize = commandLength;
+ mDataRead = 0;
+ mCommandBegin = 0;
+ mCommandEnd = 0;
+ mDataHandles = std::move(commandHandles);
+ return true;
+ }
+
+ void reset() {
+ mDataSize = 0;
+ mDataRead = 0;
+ mCommandBegin = 0;
+ mCommandEnd = 0;
+ mDataHandles.clear();
+ }
+
+ protected:
+ template <typename T>
+ bool beginCommand(T* outCommand, uint16_t* outLength) {
+ return beginCommandBase(reinterpret_cast<Command*>(outCommand), outLength);
+ }
+
+ bool isEmpty() const { return (mDataRead >= mDataSize); }
+
+ bool beginCommandBase(Command* outCommand, uint16_t* outLength) {
+ if (mCommandEnd) {
+ LOG_FATAL("endCommand was not called for last command");
+ }
+
+ constexpr uint32_t opcode_mask = static_cast<uint32_t>(Command::OPCODE_MASK);
+ constexpr uint32_t length_mask = static_cast<uint32_t>(Command::LENGTH_MASK);
+
+ uint32_t val = read();
+ *outCommand = static_cast<Command>(val & opcode_mask);
+ *outLength = static_cast<uint16_t>(val & length_mask);
+
+ if (mDataRead + *outLength > mDataSize) {
+ ALOGE("command 0x%x has invalid command length %" PRIu16, *outCommand, *outLength);
+ // undo the read() above
+ mDataRead--;
+ return false;
+ }
+
+ mCommandEnd = mDataRead + *outLength;
+
+ return true;
+ }
+
+ void endCommand() {
+ if (!mCommandEnd) {
+ LOG_FATAL("beginCommand was not called");
+ } else if (mDataRead > mCommandEnd) {
+ LOG_FATAL("too much data read");
+ mDataRead = mCommandEnd;
+ } else if (mDataRead < mCommandEnd) {
+ LOG_FATAL("too little data read");
+ mDataRead = mCommandEnd;
+ }
+
+ mCommandBegin = mCommandEnd;
+ mCommandEnd = 0;
+ }
+
+ uint32_t getCommandLoc() const { return mCommandBegin; }
+
+ uint32_t read() { return mData[mDataRead++]; }
+
+ int32_t readSigned() {
+ int32_t val;
+ memcpy(&val, &mData[mDataRead++], sizeof(val));
+ return val;
+ }
+
+ float readFloat() {
+ float val;
+ memcpy(&val, &mData[mDataRead++], sizeof(val));
+ return val;
+ }
+
+ uint64_t read64() {
+ uint32_t lo = read();
+ uint32_t hi = read();
+ return (static_cast<uint64_t>(hi) << 32) | lo;
+ }
+
+ Color readColor() {
+ uint32_t val = read();
+ return Color{
+ static_cast<int8_t>((val >> 0) & 0xff),
+ static_cast<int8_t>((val >> 8) & 0xff),
+ static_cast<int8_t>((val >> 16) & 0xff),
+ static_cast<int8_t>((val >> 24) & 0xff),
+ };
+ }
+
+ // ownership of handle is not transferred
+ const native_handle_t* readHandle(bool* outUseCache) {
+ const native_handle_t* handle = nullptr;
+
+ int32_t index = readSigned();
+ switch (index) {
+ case static_cast<int32_t>(HandleIndex::EMPTY):
+ *outUseCache = false;
+ break;
+ case static_cast<int32_t>(HandleIndex::CACHED):
+ *outUseCache = true;
+ break;
+ default:
+ if (static_cast<size_t>(index) < mDataHandles.size()) {
+ handle = ::android::makeFromAidl(mDataHandles[index]);
+ } else {
+ ALOGE("invalid handle index %zu", static_cast<size_t>(index));
+ }
+ *outUseCache = false;
+ break;
+ }
+
+ return handle;
+ }
+
+ const native_handle_t* readHandle() {
+ bool useCache;
+ return readHandle(&useCache);
+ }
+
+ // ownership of fence is transferred
+ int readFence() {
+ auto handle = readHandle();
+ if (!handle || handle->numFds == 0) {
+ return -1;
+ }
+
+ if (handle->numFds != 1) {
+ ALOGE("invalid fence handle with %d fds", handle->numFds);
+ return -1;
+ }
+
+ int fd = dup(handle->data[0]);
+ if (fd < 0) {
+ ALOGW("failed to dup fence %d", handle->data[0]);
+ sync_wait(handle->data[0], -1);
+ fd = -1;
+ }
+
+ return fd;
+ }
+
+ std::unique_ptr<int32_t[]> mData;
+ uint32_t mDataRead;
+
+ private:
+ std::unique_ptr<CommandQueueType> mQueue;
+ uint32_t mDataMaxSize;
+
+ uint32_t mDataSize;
+
+ // begin/end offsets of the current command
+ uint32_t mCommandBegin;
+ uint32_t mCommandEnd;
+
+ std::vector<NativeHandle> mDataHandles;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3
diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS
index 4177296..62e3f2a 100644
--- a/graphics/mapper/2.0/vts/OWNERS
+++ b/graphics/mapper/2.0/vts/OWNERS
@@ -1,8 +1,5 @@
-# Graphics team
+# Bug component: 25423
chrisforbes@google.com
jreck@google.com
lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/mapper/2.0/vts/functional/OWNERS b/graphics/mapper/2.0/vts/functional/OWNERS
deleted file mode 100644
index a2ed8c8..0000000
--- a/graphics/mapper/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-sumir@google.com
diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS
index 4177296..43c018a 100644
--- a/graphics/mapper/2.1/vts/OWNERS
+++ b/graphics/mapper/2.1/vts/OWNERS
@@ -1,8 +1,2 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+# Bug component: 25423
+include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/2.1/vts/functional/OWNERS b/graphics/mapper/2.1/vts/functional/OWNERS
deleted file mode 100644
index a2ed8c8..0000000
--- a/graphics/mapper/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-sumir@google.com
diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS
index c9f24d0..43c018a 100644
--- a/graphics/mapper/3.0/vts/OWNERS
+++ b/graphics/mapper/3.0/vts/OWNERS
@@ -1,4 +1,2 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
+# Bug component: 25423
+include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
index c9f24d0..43c018a 100644
--- a/graphics/mapper/4.0/vts/OWNERS
+++ b/graphics/mapper/4.0/vts/OWNERS
@@ -1,4 +1,2 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
+# Bug component: 25423
+include ../../2.0/vts/OWNERS
diff --git a/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
index 9e1cc70..3c353e6 100644
--- a/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
+++ b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
@@ -25,7 +25,26 @@
namespace V2_0 {
sp<IHealth> get_health_service() {
- for (auto&& instanceName : {"default", "backup"}) {
+ // For the core and vendor variant, the "backup" instance points to healthd,
+ // which is removed.
+ // For the recovery variant, the "backup" instance has a different
+ // meaning. It points to android.hardware.health@2.0-impl-default.recovery
+ // which was assumed by OEMs to be always installed when a
+ // vendor-specific libhealthd is not necessary. Hence, its behavior
+ // is kept. See health/2.0/README.md.
+ // android.hardware.health@2.0-impl-default.recovery, and subsequently the
+ // special handling of recovery mode below, can be removed once health@2.1
+ // is the minimum required version (i.e. compatibility matrix level 5 is the
+ // minimum supported level). Health 2.1 requires OEMs to install the
+ // implementation to the recovery partition when it is necessary (i.e. on
+ // non-A/B devices, where IsBatteryOk() is needed in recovery).
+ for (auto&& instanceName :
+#ifdef __ANDROID_RECOVERY__
+ { "default", "backup" }
+#else
+ {"default"}
+#endif
+ ) {
auto ret = IHealth::getService(instanceName);
if (ret != nullptr) {
return ret;
diff --git a/health/aidl/OWNERS b/health/aidl/OWNERS
new file mode 100644
index 0000000..cd06415
--- /dev/null
+++ b/health/aidl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 30545
+elsk@google.com
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
index 1baabdf..360b338 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
@@ -50,8 +50,8 @@
}
template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
- const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+ const auto version = NN_TRY(nn::validate(canonical));
if (version > kVersion) {
return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
index 00970c0..3060c65 100644
--- a/neuralnetworks/1.0/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
@@ -63,12 +63,11 @@
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared =
- NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
- &maybeRequestInShared, &relocation)));
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+ &maybeRequestInShared, &relocation));
- const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
+ const auto hidlRequest = NN_TRY(convert(requestInShared));
return executeInternal(hidlRequest, relocation);
}
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
index a8cf8cf..09d9fe8 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
@@ -52,8 +52,8 @@
}
template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
- const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+ const auto version = NN_TRY(nn::validate(canonical));
if (version > kVersion) {
return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
index 09691b6..5c3b8a7 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
@@ -61,8 +61,8 @@
}
template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
- const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+ const auto version = NN_TRY(nn::validate(canonical));
if (version > kVersion) {
return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
diff --git a/neuralnetworks/1.2/utils/src/Callbacks.cpp b/neuralnetworks/1.2/utils/src/Callbacks.cpp
index 9f54bb1..01b5e12 100644
--- a/neuralnetworks/1.2/utils/src/Callbacks.cpp
+++ b/neuralnetworks/1.2/utils/src/Callbacks.cpp
@@ -75,8 +75,7 @@
<< "execution failed with " << toString(status);
}
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
- return hal::utils::makeExecutionFailure(
- convertExecutionGeneralResultsHelper(outputShapes, timing));
+ return convertExecutionGeneralResultsHelper(outputShapes, timing);
}
Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index 29945b7..6a80b42 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -120,9 +120,8 @@
NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
- auto table = NN_TRY(hal::utils::makeGeneralFailure(
- Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
- nn::ErrorStatus::GENERAL_FAILURE));
+ auto table =
+ NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
return Capabilities{
.relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
diff --git a/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp b/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
index 8ce96c4..2746965 100644
--- a/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
+++ b/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
@@ -320,8 +320,7 @@
// if the request is valid but of a higher version than what's supported in burst execution,
// fall back to another execution path
- if (const auto version = NN_TRY(hal::utils::makeExecutionFailure(nn::validate(request)));
- version > nn::Version::ANDROID_Q) {
+ if (const auto version = NN_TRY(nn::validate(request)); version > nn::Version::ANDROID_Q) {
// fallback to another execution path if the packet could not be sent
return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
}
@@ -329,17 +328,15 @@
// ensure that request is ready for IPC
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared =
- NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
- &maybeRequestInShared, &relocation)));
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+ &maybeRequestInShared, &relocation));
// clear pools field of request, as they will be provided via slots
const auto requestWithoutPools = nn::Request{
.inputs = requestInShared.inputs, .outputs = requestInShared.outputs, .pools = {}};
- auto hidlRequest = NN_TRY(
- hal::utils::makeExecutionFailure(V1_0::utils::unvalidatedConvert(requestWithoutPools)));
- const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
+ auto hidlRequest = NN_TRY(V1_0::utils::unvalidatedConvert(requestWithoutPools));
+ const auto hidlMeasure = NN_TRY(convert(measure));
std::vector<int32_t> slots;
std::vector<OptionalCacheHold> holds;
@@ -367,8 +364,7 @@
// if the request is valid but of a higher version than what's supported in burst execution,
// fall back to another execution path
- if (const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(request)));
- version > nn::Version::ANDROID_Q) {
+ if (const auto version = NN_TRY(nn::validate(request)); version > nn::Version::ANDROID_Q) {
// fallback to another execution path if the packet could not be sent
return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration);
}
@@ -430,8 +426,7 @@
}
// get result packet
- const auto [status, outputShapes, timing] =
- NN_TRY(hal::utils::makeExecutionFailure(mResultChannelReceiver->getBlocking()));
+ const auto [status, outputShapes, timing] = NN_TRY(mResultChannelReceiver->getBlocking());
if (relocation.output) {
relocation.output->flush();
diff --git a/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp b/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
index c67159e..65ec7f5 100644
--- a/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
+++ b/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
@@ -45,8 +45,6 @@
namespace android::hardware::neuralnetworks::V1_2::utils {
namespace {
-using neuralnetworks::utils::makeExecutionFailure;
-
constexpr V1_2::Timing kNoTiming = {std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::max()};
@@ -241,28 +239,25 @@
"ExecutionBurstServer getting memory, executing, and returning results");
// ensure executor with cache has required memory
- const auto cacheEntries =
- NN_TRY(makeExecutionFailure(mMemoryCache.getCacheEntries(slotsOfPools)));
+ const auto cacheEntries = NN_TRY(mMemoryCache.getCacheEntries(slotsOfPools));
// convert request, populating its pools
// This code performs an unvalidated convert because the request object without its pools is
// invalid because it is incomplete. Instead, the validation is performed after the memory pools
// have been added to the request.
- auto canonicalRequest =
- NN_TRY(makeExecutionFailure(nn::unvalidatedConvert(requestWithoutPools)));
+ auto canonicalRequest = NN_TRY(nn::unvalidatedConvert(requestWithoutPools));
CHECK(canonicalRequest.pools.empty());
std::transform(cacheEntries.begin(), cacheEntries.end(),
std::back_inserter(canonicalRequest.pools),
[](const auto& cacheEntry) { return cacheEntry.first; });
- NN_TRY(makeExecutionFailure(validate(canonicalRequest)));
+ NN_TRY(validate(canonicalRequest));
- nn::MeasureTiming canonicalMeasure = NN_TRY(makeExecutionFailure(nn::convert(measure)));
+ nn::MeasureTiming canonicalMeasure = NN_TRY(nn::convert(measure));
const auto [outputShapes, timing] =
NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure, {}, {}));
- return std::make_pair(NN_TRY(makeExecutionFailure(convert(outputShapes))),
- NN_TRY(makeExecutionFailure(convert(timing))));
+ return std::make_pair(NN_TRY(convert(outputShapes)), NN_TRY(convert(timing)));
}
} // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
index d0ef36e..c261184 100644
--- a/neuralnetworks/1.2/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
@@ -95,13 +95,12 @@
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared =
- NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
- &maybeRequestInShared, &relocation)));
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+ &maybeRequestInShared, &relocation));
- const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
- const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
+ const auto hidlRequest = NN_TRY(convert(requestInShared));
+ const auto hidlMeasure = NN_TRY(convert(measure));
return executeInternal(hidlRequest, hidlMeasure, relocation);
}
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
index 1d76caa..28525bd 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
@@ -61,8 +61,8 @@
}
template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
- const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+ const auto version = NN_TRY(nn::validate(canonical));
if (version > kVersion) {
return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
diff --git a/neuralnetworks/1.3/utils/src/Callbacks.cpp b/neuralnetworks/1.3/utils/src/Callbacks.cpp
index 8e9fb83..156216f 100644
--- a/neuralnetworks/1.3/utils/src/Callbacks.cpp
+++ b/neuralnetworks/1.3/utils/src/Callbacks.cpp
@@ -91,8 +91,7 @@
<< "execution failed with " << toString(status);
}
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
- return hal::utils::makeExecutionFailure(
- convertExecutionGeneralResultsHelper(outputShapes, timing));
+ return convertExecutionGeneralResultsHelper(outputShapes, timing);
}
Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index 11225cf..b35b2cd 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -131,9 +131,8 @@
}
auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
- auto table = NN_TRY(hal::utils::makeGeneralFailure(
- Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
- nn::ErrorStatus::GENERAL_FAILURE));
+ auto table =
+ NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
return Capabilities{
.relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
diff --git a/neuralnetworks/1.3/utils/src/Execution.cpp b/neuralnetworks/1.3/utils/src/Execution.cpp
index 3d17cc3..4dc0ddf 100644
--- a/neuralnetworks/1.3/utils/src/Execution.cpp
+++ b/neuralnetworks/1.3/utils/src/Execution.cpp
@@ -65,7 +65,7 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
const nn::OptionalTimePoint& deadline) const {
- const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+ const auto hidlDeadline = NN_TRY(convert(deadline));
return kPreparedModel->executeInternal(kRequest, kMeasure, hidlDeadline, kLoopTimeoutDuration,
kRelocation);
}
diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
index 1623de5..d5dee9d 100644
--- a/neuralnetworks/1.3/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
@@ -62,8 +62,7 @@
auto resultSyncFence = nn::SyncFence::createAsSignaled();
if (syncFence.getNativeHandle() != nullptr) {
auto sharedHandle = NN_TRY(nn::convert(syncFence));
- resultSyncFence = NN_TRY(hal::utils::makeGeneralFailure(
- nn::SyncFence::create(std::move(sharedHandle)), nn::ErrorStatus::GENERAL_FAILURE));
+ resultSyncFence = NN_TRY(nn::SyncFence::create(std::move(sharedHandle)));
}
if (callback == nullptr) {
@@ -141,16 +140,14 @@
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared =
- NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
- &maybeRequestInShared, &relocation)));
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+ &maybeRequestInShared, &relocation));
- const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
- const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
- const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
- const auto hidlLoopTimeoutDuration =
- NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+ const auto hidlRequest = NN_TRY(convert(requestInShared));
+ const auto hidlMeasure = NN_TRY(convert(measure));
+ const auto hidlDeadline = NN_TRY(convert(deadline));
+ const auto hidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
return executeInternal(hidlRequest, hidlMeasure, hidlDeadline, hidlLoopTimeoutDuration,
relocation);
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
index 4259143..2eff11b 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
@@ -137,4 +137,5 @@
FILL = 100,
RANK = 101,
BATCH_MATMUL = 102,
+ PACK = 103,
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
index d9951d5..2ec91ac 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
@@ -5273,4 +5273,53 @@
* c_o = r_y if adj_y else c_y
*/
BATCH_MATMUL = 102,
+
+ /**
+ * Packs N input tensors (N >= 1) of rank R into one output tensor of rank R+1.
+ * The tensors are packed along a given axis.
+ *
+ * The input tensors must have identical {@link OperandType} and dimensions.
+ *
+ * For example, suppose there are N input tensors of shape (A, B, C).
+ * If axis is 0, the output tensor will have shape (N, A, B, C).
+ * If axis is 1, the output tensor will have shape (A, N, B, C).
+ *
+ * All dimensions through the axis dimension determine the output tile count;
+ * the remaining dimensions determine the tile shape.
+ *
+ * Return to the example of N input tensors of shape (A, B, C).
+ * If axis is 0, there are N tiles in the output, each of shape (A, B, C).
+ * If axis is 1, there are A*N tiles in the output, each of shape (B, C).
+ *
+ * The coordinates of a tile within the output tensor are (t[0],...,t[axis]).
+ * The coordinates of a tile within an input tensor are (t[0],...,t[axis-1]).
+ * (If axis is 0, an input tensor consists of a single tile.)
+ * If we index input tensors starting with 0 (rather than by operand number),
+ * then output_tile[t[0],...,t[axis]] = input_tile[t[axis]][t[0],...,t[axis-1]].
+ * That is, all output tile coordinates except for the axis coordinate select
+ * the corresponding location within some input tensor; and the axis coordinate
+ * selects the input tensor.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+ * * {@link OperandType::TENSOR_INT32}
+ *
+ * Supported input tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: A scalar of type {@link OperandType::INT32}, specifying
+ * the axis along which to pack. The valid range is [0, R+1).
+ * * 1 ~ N: Input tensors to be packed together.
+ * For {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensors,
+ * the scales and zeroPoint must be the same for all input tensors,
+ * and will be the same for the output tensor.
+ *
+ * Outputs:
+ * * 0: The packed tensor.
+ */
+ PACK = 103,
}
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
index 316d34f..1b149e4 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
@@ -50,9 +50,8 @@
}
template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
- const auto version = NN_TRY(::android::hardware::neuralnetworks::utils::makeGeneralFailure(
- nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+ const auto version = NN_TRY(nn::validate(canonical));
if (version > kVersion) {
return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
diff --git a/neuralnetworks/aidl/utils/src/Burst.cpp b/neuralnetworks/aidl/utils/src/Burst.cpp
index 800ac32..c59c10b 100644
--- a/neuralnetworks/aidl/utils/src/Burst.cpp
+++ b/neuralnetworks/aidl/utils/src/Burst.cpp
@@ -176,16 +176,14 @@
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared =
- NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
- &maybeRequestInShared, &relocation)));
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+ &maybeRequestInShared, &relocation));
- const auto aidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
- const auto aidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
- const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
- const auto aidlLoopTimeoutDuration =
- NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+ const auto aidlRequest = NN_TRY(convert(requestInShared));
+ const auto aidlMeasure = NN_TRY(convert(measure));
+ const auto aidlDeadline = NN_TRY(convert(deadline));
+ const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
std::vector<int64_t> memoryIdentifierTokens;
std::vector<OptionalCacheHold> holds;
@@ -233,8 +231,8 @@
return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
<< "execution failed with " << nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
}
- auto [outputShapes, timing] = NN_TRY(hal::utils::makeExecutionFailure(
- convertExecutionResults(executionResult.outputShapes, executionResult.timing)));
+ auto [outputShapes, timing] =
+ NN_TRY(convertExecutionResults(executionResult.outputShapes, executionResult.timing));
if (relocation.output) {
relocation.output->flush();
@@ -308,7 +306,7 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> BurstExecution::compute(
const nn::OptionalTimePoint& deadline) const {
- const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+ const auto aidlDeadline = NN_TRY(convert(deadline));
return kBurst->executeInternal(kRequest, kMemoryIdentifierTokens, kMeasure, aidlDeadline,
kLoopTimeoutDuration, kRelocation);
}
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index f087156..ddff3f2 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -178,9 +178,8 @@
}
auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
- auto table = NN_TRY(hal::utils::makeGeneralFailure(
- Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
- nn::ErrorStatus::GENERAL_FAILURE));
+ auto table =
+ NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
return Capabilities{
.relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
diff --git a/neuralnetworks/aidl/utils/src/Execution.cpp b/neuralnetworks/aidl/utils/src/Execution.cpp
index 2aee8a6..13d4f32 100644
--- a/neuralnetworks/aidl/utils/src/Execution.cpp
+++ b/neuralnetworks/aidl/utils/src/Execution.cpp
@@ -60,7 +60,7 @@
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
const nn::OptionalTimePoint& deadline) const {
- const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+ const auto aidlDeadline = NN_TRY(convert(deadline));
return kPreparedModel->executeInternal(kRequest, kMeasure, aidlDeadline, kLoopTimeoutDuration,
kRelocation);
}
diff --git a/neuralnetworks/aidl/utils/src/PreparedModel.cpp b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
index f861d74..0769016 100644
--- a/neuralnetworks/aidl/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
@@ -78,16 +78,14 @@
// Ensure that request is ready for IPC.
std::optional<nn::Request> maybeRequestInShared;
hal::utils::RequestRelocation relocation;
- const nn::Request& requestInShared =
- NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
- &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
- &maybeRequestInShared, &relocation)));
+ const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+ &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+ &maybeRequestInShared, &relocation));
- const auto aidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
- const auto aidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
- const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
- const auto aidlLoopTimeoutDuration =
- NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+ const auto aidlRequest = NN_TRY(convert(requestInShared));
+ const auto aidlMeasure = NN_TRY(convert(measure));
+ const auto aidlDeadline = NN_TRY(convert(deadline));
+ const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
return executeInternal(aidlRequest, aidlMeasure, aidlDeadline, aidlLoopTimeoutDuration,
relocation);
}
@@ -110,8 +108,8 @@
return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
<< "execution failed with " << nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
}
- auto [outputShapes, timing] = NN_TRY(hal::utils::makeExecutionFailure(
- convertExecutionResults(executionResult.outputShapes, executionResult.timing)));
+ auto [outputShapes, timing] =
+ NN_TRY(convertExecutionResults(executionResult.outputShapes, executionResult.timing));
if (relocation.output) {
relocation.output->flush();
diff --git a/neuralnetworks/utils/adapter/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/src/PreparedModel.cpp
index 8968c2c..7397def 100644
--- a/neuralnetworks/utils/adapter/src/PreparedModel.cpp
+++ b/neuralnetworks/utils/adapter/src/PreparedModel.cpp
@@ -57,6 +57,15 @@
return result;
}
+nn::GeneralResult<nn::Version> validateRequestForModel(const nn::Request& request,
+ const nn::Model& model) {
+ nn::GeneralResult<nn::Version> version = nn::validateRequestForModel(request, model);
+ if (!version.ok()) {
+ version.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+ }
+ return version;
+}
+
class FencedExecutionCallback final : public V1_3::IFencedExecutionCallback {
public:
explicit FencedExecutionCallback(const nn::ExecuteFencedInfoCallback& callback)
@@ -148,8 +157,7 @@
const std::any resource = preparedModel->getUnderlyingResource();
if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
CHECK(*model != nullptr);
- NN_TRY(utils::makeGeneralFailure(nn::validateRequestForModel(nnRequest, **model),
- nn::ErrorStatus::INVALID_ARGUMENT));
+ NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
}
Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
@@ -175,8 +183,7 @@
const std::any resource = preparedModel->getUnderlyingResource();
if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
CHECK(*model != nullptr);
- NN_TRY(utils::makeGeneralFailure(nn::validateRequestForModel(nnRequest, **model),
- nn::ErrorStatus::INVALID_ARGUMENT));
+ NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
}
Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
@@ -206,8 +213,7 @@
const std::any resource = preparedModel->getUnderlyingResource();
if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
CHECK(*model != nullptr);
- NN_TRY(utils::makeGeneralFailure(nn::validateRequestForModel(nnRequest, **model),
- nn::ErrorStatus::INVALID_ARGUMENT));
+ NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
}
Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
@@ -224,14 +230,14 @@
nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> executeSynchronously(
const nn::SharedPreparedModel& preparedModel, const V1_0::Request& request,
V1_2::MeasureTiming measure) {
- const auto nnRequest = NN_TRY(utils::makeExecutionFailure(convertInput(request)));
- const auto nnMeasure = NN_TRY(utils::makeExecutionFailure(convertInput(measure)));
+ const auto nnRequest = NN_TRY(convertInput(request));
+ const auto nnMeasure = NN_TRY(convertInput(measure));
const auto [outputShapes, timing] =
NN_TRY(preparedModel->execute(nnRequest, nnMeasure, {}, {}));
- auto hidlOutputShapes = NN_TRY(utils::makeExecutionFailure(V1_2::utils::convert(outputShapes)));
- const auto hidlTiming = NN_TRY(utils::makeExecutionFailure(V1_2::utils::convert(timing)));
+ auto hidlOutputShapes = NN_TRY(V1_2::utils::convert(outputShapes));
+ const auto hidlTiming = NN_TRY(V1_2::utils::convert(timing));
return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
}
@@ -239,29 +245,30 @@
const nn::SharedPreparedModel& preparedModel, const V1_3::Request& request,
V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& deadline,
const V1_3::OptionalTimeoutDuration& loopTimeoutDuration) {
- const auto nnRequest = NN_TRY(utils::makeExecutionFailure(convertInput(request)));
- const auto nnMeasure = NN_TRY(utils::makeExecutionFailure(convertInput(measure)));
- const auto nnDeadline = NN_TRY(utils::makeExecutionFailure(convertInput(deadline)));
- const auto nnLoopTimeoutDuration =
- NN_TRY(utils::makeExecutionFailure(convertInput(loopTimeoutDuration)));
+ const auto nnRequest = NN_TRY(convertInput(request));
+ const auto nnMeasure = NN_TRY(convertInput(measure));
+ const auto nnDeadline = NN_TRY(convertInput(deadline));
+ const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
const auto [outputShapes, timing] =
NN_TRY(preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration));
- auto hidlOutputShapes = NN_TRY(utils::makeExecutionFailure(V1_3::utils::convert(outputShapes)));
- const auto hidlTiming = NN_TRY(utils::makeExecutionFailure(V1_3::utils::convert(timing)));
+ auto hidlOutputShapes = NN_TRY(V1_3::utils::convert(outputShapes));
+ const auto hidlTiming = NN_TRY(V1_3::utils::convert(timing));
return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
}
nn::GeneralResult<std::vector<nn::SyncFence>> convertSyncFences(
const hidl_vec<hidl_handle>& handles) {
+ auto nnHandles = NN_TRY(convertInput(handles));
std::vector<nn::SyncFence> syncFences;
syncFences.reserve(handles.size());
- for (const auto& handle : handles) {
- auto nativeHandle = NN_TRY(convertInput(handle));
- auto syncFence = NN_TRY(utils::makeGeneralFailure(
- nn::SyncFence::create(std::move(nativeHandle)), nn::ErrorStatus::INVALID_ARGUMENT));
- syncFences.push_back(std::move(syncFence));
+ for (auto&& handle : nnHandles) {
+ if (auto syncFence = nn::SyncFence::create(std::move(handle)); !syncFence.ok()) {
+ return nn::error(nn::ErrorStatus::INVALID_ARGUMENT) << std::move(syncFence).error();
+ } else {
+ syncFences.push_back(std::move(syncFence).value());
+ }
}
return syncFences;
}
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
index 209b663..e51f916 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
@@ -52,38 +52,6 @@
std::move(result).value(); \
})
-template <typename Type>
-nn::GeneralResult<Type> makeGeneralFailure(
- nn::Result<Type> result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) {
- if (!result.has_value()) {
- return nn::error(status) << std::move(result).error();
- }
- if constexpr (!std::is_same_v<Type, void>) {
- return std::move(result).value();
- } else {
- return {};
- }
-}
-
-template <typename Type>
-nn::ExecutionResult<Type> makeExecutionFailure(nn::GeneralResult<Type> result) {
- if (!result.has_value()) {
- const auto [message, status] = std::move(result).error();
- return nn::error(status) << message;
- }
- if constexpr (!std::is_same_v<Type, void>) {
- return std::move(result).value();
- } else {
- return {};
- }
-}
-
-template <typename Type>
-nn::ExecutionResult<Type> makeExecutionFailure(
- nn::Result<Type> result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) {
- return makeExecutionFailure(makeGeneralFailure(result, status));
-}
-
#define HANDLE_HAL_STATUS(status) \
if (const auto canonical = ::android::nn::convert(status).value_or( \
::android::nn::ErrorStatus::GENERAL_FAILURE); \
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index ae02c88..235ba29 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -333,7 +333,7 @@
nn::GeneralResult<std::vector<uint32_t>> countNumberOfConsumers(
size_t numberOfOperands, const std::vector<nn::Operation>& operations) {
- return makeGeneralFailure(nn::countNumberOfConsumers(numberOfOperands, operations));
+ return nn::countNumberOfConsumers(numberOfOperands, operations);
}
nn::GeneralResult<hidl_memory> createHidlMemoryFromSharedMemory(const nn::SharedMemory& memory) {
diff --git a/oemlock/1.0/vts/functional/OWNERS b/oemlock/1.0/vts/functional/OWNERS
new file mode 100644
index 0000000..ec8c304
--- /dev/null
+++ b/oemlock/1.0/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 186411
+chengyouho@google.com
+frankwoo@google.com
diff --git a/power/1.0/vts/functional/OWNERS b/power/1.0/vts/OWNERS
similarity index 100%
copy from power/1.0/vts/functional/OWNERS
copy to power/1.0/vts/OWNERS
diff --git a/power/1.1/vts/OWNERS b/power/1.1/vts/OWNERS
new file mode 100644
index 0000000..3a64da7
--- /dev/null
+++ b/power/1.1/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 158088
+wvw@google.com
diff --git a/power/1.0/vts/functional/OWNERS b/power/1.1/vts/functional/OWNERS
similarity index 100%
rename from power/1.0/vts/functional/OWNERS
rename to power/1.1/vts/functional/OWNERS
diff --git a/power/1.2/vts/OWNERS b/power/1.2/vts/OWNERS
new file mode 100644
index 0000000..4d8c7e9
--- /dev/null
+++ b/power/1.2/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 158088
+include ../../1.1/vts/OWNERS
diff --git a/power/1.3/vts/OWNERS b/power/1.3/vts/OWNERS
new file mode 100644
index 0000000..4d8c7e9
--- /dev/null
+++ b/power/1.3/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 158088
+include ../../1.1/vts/OWNERS
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 6561c92..6e82b8b 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -104,7 +104,7 @@
uint32_t frequency = settings.dvbt().frequency;
if (type == FrontendScanType::SCAN_BLIND) {
- frequency += 100;
+ frequency += 100 * 1000;
}
msg.frequencies({frequency});
mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg);
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index c4f610e..2157bdf 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -175,8 +175,8 @@
// assign randomly selected values for testing.
info = {
.type = mFrontends[frontendId]->getFrontendType(),
- .minFrequency = 139,
- .maxFrequency = 1139,
+ .minFrequency = 139000000,
+ .maxFrequency = 1139000000,
.minSymbolRate = 45,
.maxSymbolRate = 1145,
.acquireRange = 30,
diff --git a/tv/tuner/1.0/vts/functional/DvrTests.cpp b/tv/tuner/1.0/vts/functional/DvrTests.cpp
index 599abfb..83f9858 100644
--- a/tv/tuner/1.0/vts/functional/DvrTests.cpp
+++ b/tv/tuner/1.0/vts/functional/DvrTests.cpp
@@ -124,11 +124,9 @@
while (mDataOutputBuffer.empty()) {
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
- stopRecordThread();
return;
}
}
- stopRecordThread();
ALOGW("[vts] record pass and stop");
}
@@ -193,9 +191,10 @@
bool DvrCallback::readRecordFMQ() {
android::Mutex::Autolock autoLock(mMsgLock);
bool result = false;
+ int readSize = mRecordMQ->availableToRead();
mDataOutputBuffer.clear();
- mDataOutputBuffer.resize(mRecordMQ->availableToRead());
- result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+ mDataOutputBuffer.resize(readSize);
+ result = mRecordMQ->read(mDataOutputBuffer.data(), readSize);
EXPECT_TRUE(result) << "can't read from Record MQ";
mMsgCondition.signal();
return result;
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
index 62ac6f7..ba66595 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
@@ -85,7 +85,7 @@
// passed in means the real input config on the transponder connected to the DUT.
// We want the blind the test to start from lower frequency than this to check the blind
// scan implementation.
- resetBlindScanStartingFrequency(config, targetFrequency - 100);
+ resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
}
Result result = frontend->scan(config.settings, type);
@@ -415,7 +415,6 @@
void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
ASSERT_TRUE(getFrontendIds());
- ASSERT_TRUE(mFeIds.size() > 0);
for (size_t i = 0; i < mFeIds.size(); i++) {
ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
if (mFrontendInfo.type != feType) {
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index 2cea181..008879d 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -68,7 +68,7 @@
// without overriding in the xml config.
string defaultFeId = "FE_DEFAULT";
FrontendDvbtSettings dvbtSettings{
- .frequency = 578000,
+ .frequency = 578000000,
.transmissionMode = FrontendDvbtTransmissionMode::AUTO,
.bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
.isHighPriority = true,
diff --git a/tv/tuner/1.1/default/Frontend.cpp b/tv/tuner/1.1/default/Frontend.cpp
index e3fbdad..f5463a9 100644
--- a/tv/tuner/1.1/default/Frontend.cpp
+++ b/tv/tuner/1.1/default/Frontend.cpp
@@ -128,7 +128,7 @@
}
if (type == FrontendScanType::SCAN_BLIND) {
- frequency += 100;
+ frequency += 100 * 1000;
}
msg.frequencies({frequency});
diff --git a/tv/tuner/1.1/default/Tuner.cpp b/tv/tuner/1.1/default/Tuner.cpp
index 1e940ba..6d94fbd 100644
--- a/tv/tuner/1.1/default/Tuner.cpp
+++ b/tv/tuner/1.1/default/Tuner.cpp
@@ -264,8 +264,8 @@
// assign randomly selected values for testing.
info = {
.type = mFrontends[frontendId]->getFrontendType(),
- .minFrequency = 139,
- .maxFrequency = 1139,
+ .minFrequency = 139000000,
+ .maxFrequency = 1139000000,
.minSymbolRate = 45,
.maxSymbolRate = 1145,
.acquireRange = 30,
diff --git a/tv/tuner/1.1/vts/functional/AndroidTest.xml b/tv/tuner/1.1/vts/functional/AndroidTest.xml
index 3e6878c..848cfc0 100644
--- a/tv/tuner/1.1/vts/functional/AndroidTest.xml
+++ b/tv/tuner/1.1/vts/functional/AndroidTest.xml
@@ -24,6 +24,7 @@
<option name="cleanup" value="true" />
<option name="push" value="VtsHalTvTunerV1_1TargetTest->/data/local/tmp/VtsHalTvTunerV1_1TargetTest" />
<option name="push" value="test.es->/data/local/tmp/test.es" />
+ <option name="push" value="segment000000.ts->/data/local/tmp/segment000000.ts" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
diff --git a/tv/tuner/1.1/vts/functional/DvrTests.cpp b/tv/tuner/1.1/vts/functional/DvrTests.cpp
index 1e478f5..e40e7fd 100644
--- a/tv/tuner/1.1/vts/functional/DvrTests.cpp
+++ b/tv/tuner/1.1/vts/functional/DvrTests.cpp
@@ -123,11 +123,9 @@
while (mDataOutputBuffer.empty()) {
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
- stopRecordThread();
return;
}
}
- stopRecordThread();
ALOGW("[vts] record pass and stop");
}
@@ -204,6 +202,7 @@
void DvrCallback::stopRecordThread() {
mKeepReadingRecordFMQ = false;
mRecordThreadRunning = false;
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
}
AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) {
diff --git a/tv/tuner/1.1/vts/functional/FrontendTests.cpp b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
index 9c0933e..bc57821 100644
--- a/tv/tuner/1.1/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
@@ -136,7 +136,7 @@
// passed in means the real input config on the transponder connected to the DUT.
// We want the blind the test to start from lower frequency than this to check the blind
// scan implementation.
- resetBlindScanStartingFrequency(config, targetFrequency - 100);
+ resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
}
Result result = frontend_1_1->scan_1_1(config.config1_0.settings, type, config.settingsExt1_1);
@@ -474,7 +474,6 @@
void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
ASSERT_TRUE(getFrontendIds());
- ASSERT_TRUE(mFeIds.size() > 0);
for (size_t i = 0; i < mFeIds.size(); i++) {
ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
if (mFrontendInfo.type != feType) {
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
index 2b5ad46..669fa11 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
@@ -73,7 +73,7 @@
// without overriding in the xml config.
string defaultFeId = "FE_DEFAULT";
FrontendDvbtSettings dvbtSettings{
- .frequency = 578000,
+ .frequency = 578000000,
.transmissionMode = FrontendDvbtTransmissionMode::AUTO,
.bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
.isHighPriority = true,
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 660d0bb..f9e697e 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -128,7 +128,7 @@
}
if (in_type == FrontendScanType::SCAN_BLIND) {
- frequency += 100;
+ frequency += 100 * 1000;
}
{
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index 678be54..8468929 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -252,8 +252,8 @@
// assign randomly selected values for testing.
*_aidl_return = {
.type = mFrontends[in_frontendId]->getFrontendType(),
- .minFrequency = 139,
- .maxFrequency = 1139,
+ .minFrequency = 139000000,
+ .maxFrequency = 1139000000,
.minSymbolRate = 45,
.maxSymbolRate = 1145,
.acquireRange = 30,
diff --git a/tv/tuner/aidl/vts/functional/AndroidTest.xml b/tv/tuner/aidl/vts/functional/AndroidTest.xml
index f93ed78..a849e5a 100644
--- a/tv/tuner/aidl/vts/functional/AndroidTest.xml
+++ b/tv/tuner/aidl/vts/functional/AndroidTest.xml
@@ -24,6 +24,7 @@
<option name="cleanup" value="true" />
<option name="push" value="VtsHalTvTunerTargetTest->/data/local/tmp/VtsHalTvTunerTargetTest" />
<option name="push" value="test.es->/data/local/tmp/test.es" />
+ <option name="push" value="segment000000.ts->/data/local/tmp/segment000000.ts" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 7dce4fb..77add8e 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -126,7 +126,7 @@
// passed in means the real input config on the transponder connected to the DUT.
// We want the blind the test to start from lower frequency than this to check the blind
// scan implementation.
- resetBlindScanStartingFrequency(config, targetFrequency - 100);
+ resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
}
ndk::ScopedAStatus result = frontend->scan(config.settings, type);
@@ -446,7 +446,6 @@
void FrontendTests::getFrontendIdByType(FrontendType feType, int32_t& feId) {
ASSERT_TRUE(getFrontendIds());
- ASSERT_TRUE(mFeIds.size() > 0);
for (size_t i = 0; i < mFeIds.size(); i++) {
ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
if (mFrontendInfo.type != feType) {
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index b4fb54f..006bf17 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -81,7 +81,7 @@
// without overriding in the xml config.
string defaultFeId = "FE_DEFAULT";
FrontendDvbtSettings dvbtSettings{
- .frequency = 578000,
+ .frequency = 578000000,
.transmissionMode = FrontendDvbtTransmissionMode::AUTO,
.bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
.isHighPriority = true,
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index b411011..08270d6 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -998,6 +998,7 @@
if (!feConfig.hasConnectToCicamId()) {
canConnectToCiCam = false;
ciCamId = -1;
+ return;
}
canConnectToCiCam = true;
ciCamId = static_cast<int32_t>(feConfig.getConnectToCicamId());
diff --git a/tv/tuner/config/TunerTestingConfigReaderV1_1.h b/tv/tuner/config/TunerTestingConfigReaderV1_1.h
index 13d5303..c87980d 100644
--- a/tv/tuner/config/TunerTestingConfigReaderV1_1.h
+++ b/tv/tuner/config/TunerTestingConfigReaderV1_1.h
@@ -145,6 +145,7 @@
if (!feConfig.hasConnectToCicamId()) {
canConnectToCiCam = false;
ciCamId = -1;
+ return;
}
canConnectToCiCam = true;
ciCamId = static_cast<uint32_t>(feConfig.getConnectToCicamId());
diff --git a/tv/tuner/config/sample_tuner_vts_config_1_0.xml b/tv/tuner/config/sample_tuner_vts_config_1_0.xml
index 347e984..e880bcd 100644
--- a/tv/tuner/config/sample_tuner_vts_config_1_0.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_1_0.xml
@@ -53,14 +53,14 @@
-->
<frontends>
<frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
- connectToCicamId="0" frequency="578000" endFrequency="800000">
+ connectToCicamId="0" frequency="578000000" endFrequency="800000000">
<dvbtFrontendSettings bandwidth="8" transmissionMode="1" isHighPriority="1"
constellation="1" hierarchy="1" hpCoderate="1" lpCoderate="1"
guardInterval="1" standard="1" isMiso="0" plpMode="1"
plpId="0" plpGroupId="0"/>
</frontend>
<frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
- connectToCicamId="0" frequency="578000" endFrequency="800000">
+ connectToCicamId="0" frequency="578000000" endFrequency="800000000">
</frontend>
</frontends>
<!-- Filter section:
diff --git a/tv/tuner/config/sample_tuner_vts_config_1_1.xml b/tv/tuner/config/sample_tuner_vts_config_1_1.xml
index 8c99207..55ce0ec 100644
--- a/tv/tuner/config/sample_tuner_vts_config_1_1.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_1_1.xml
@@ -53,11 +53,11 @@
-->
<frontends>
<frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
- connectToCicamId="0" frequency="578000" endFrequency="800000">
+ connectToCicamId="0" frequency="578000000" endFrequency="800000000">
<dvbtFrontendSettings bandwidth="8" transmissionMode="128" isHighPriority="1"/>
</frontend>
<frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
- connectToCicamId="0" frequency="578000" endFrequency="800000">
+ connectToCicamId="0" frequency="578000000" endFrequency="800000000">
</frontend>
</frontends>
<!-- Filter section:
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 5d21753..0d1ebc2 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -17,6 +17,7 @@
backend: {
java: {
sdk_version: "module_current",
+ enabled: false,
},
ndk: {
vndk: {
@@ -37,3 +38,29 @@
},
},
}
+
+aidl_interface {
+ name: "android.hardware.uwb.fira_android",
+ vendor_available: true,
+ srcs: ["android/hardware/uwb/fira_android/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ enabled: true,
+ apex_available: [
+ "com.android.uwb",
+ ],
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.uwb",
+ ],
+ min_sdk_version: "current",
+ },
+ },
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
new file mode 100644
index 0000000..b0d88e0
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="byte") @VintfStability
+enum UwbVendorGids {
+ ANDROID = 14,
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
new file mode 100644
index 0000000..37b7efb
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="int") @VintfStability
+enum UwbVendorSessionSetAppConfigCmdParams {
+ CCC_RANGING_PROTOCOL_VER = 163,
+ CCC_UWB_CONFIG_ID = 164,
+ CCC_PULSESHAPE_COMBO = 165,
+ CCC_URSK_TTL = 166,
+}
diff --git a/uwb/aidl/android/hardware/uwb/IUwbChip.aidl b/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
index 5f1a59e..9530af4 100755
--- a/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
+++ b/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
@@ -51,6 +51,10 @@
/**
* Supported version of vendor UCI specification.
+ *
+ * This corresponds to the version of the "android.hardware.uwb.fira_android" types-only
+ * package included in the HAL implementation. This vendor params/commands package will be
+ * updated on a different cadence to the main UWB HAL interface package.
*/
int getSupportedVendorUciVersion();
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/README.md b/uwb/aidl/android/hardware/uwb/fira_android/README.md
new file mode 100644
index 0000000..e658d93
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/README.md
@@ -0,0 +1,15 @@
+The `android.hardware.uwb.fira_android` package is used to add any Android specific
+additions to the UCI specification defined by FIRA standards body. These
+additions should be added to the vendor specific portions carved out in the UCI
+specification.
+
+These include:
+ - Android specific GIDs/OIDs for commands/responses/notifications.
+ - Andriod specific params in an existing UCI specified command/response/notification.
+
+All other interactions sent/received over the HAL interface is expected to
+comply with the UCI specification that can be found [here](
+https://groups.firaconsortium.org/wg/Technical/document/folder/127).
+
+TODO([b/196004116](b/196004116)): Link to the published specification.
+
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl
new file mode 100644
index 0000000..c7bc6b0
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor command GIDs (Group ID) should be defined here.
+ *
+ * For each vendor GID defined here, also create a corresponding AIDL file enumerating the
+ * OIDs (Opcode Identifier) allowed within that GID.
+ * For ex: VENDOR_GID_XXX = 1110b -> UwbVendorGidXXXOids.aidl
+ */
+@VintfStability
+@Backing(type="byte")
+enum UwbVendorGids {
+ /**
+ * Use values from the Proprietary Group range: 1110b – 1111b defined in Table 36 of
+ * UCI specification.
+ */
+
+ /** All Android specific commands/response/notification should use this GID */
+ ANDROID = 0xE,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
new file mode 100644
index 0000000..850e2da
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor app params set in UCI command:
+ * GID: 0001b (UWB Session config Group)
+ * OID: 000011b (SESSION_SET_APP_CONFIG_CMD)
+ *
+ * Note: Refer to Table 34 of the UCI specification for the other params
+ * expected in this command.
+ */
+@VintfStability
+@Backing(type="int")
+enum UwbVendorSessionSetAppConfigCmdParams {
+ /** CCC params for ranging start */
+
+ /** Added in vendor version 0. */
+ CCC_RANGING_PROTOCOL_VER = 0xA3,
+ CCC_UWB_CONFIG_ID = 0xA4,
+ CCC_PULSESHAPE_COMBO = 0xA5,
+ CCC_URSK_TTL = 0xA6,
+}
diff --git a/vibrator/1.0/vts/OWNERS b/vibrator/1.0/vts/OWNERS
new file mode 100644
index 0000000..75b9a4b
--- /dev/null
+++ b/vibrator/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 345036
+michaelwr@google.com
+leungv@google.com
diff --git a/vibrator/1.1/vts/OWNERS b/vibrator/1.1/vts/OWNERS
new file mode 100644
index 0000000..44bfe56
--- /dev/null
+++ b/vibrator/1.1/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 345036
+include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.2/vts/OWNERS b/vibrator/1.2/vts/OWNERS
new file mode 100644
index 0000000..44bfe56
--- /dev/null
+++ b/vibrator/1.2/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 345036
+include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.3/vts/OWNERS b/vibrator/1.3/vts/OWNERS
new file mode 100644
index 0000000..44bfe56
--- /dev/null
+++ b/vibrator/1.3/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 345036
+include ../../1.0/vts/OWNERS
diff --git a/vibrator/aidl/OWNERS b/vibrator/aidl/OWNERS
index e3d7e6b..ae10db6 100644
--- a/vibrator/aidl/OWNERS
+++ b/vibrator/aidl/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 345036
include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
chasewu@google.com
leungv@google.com
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 82d794c..6bdff42 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -28,6 +28,8 @@
#include "wifi_chip.h"
#include "wifi_status_util.h"
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
namespace {
using android::sp;
using android::base::unique_fd;
@@ -126,8 +128,37 @@
}
std::string getPredefinedP2pIfaceName() {
+ std::array<char, PROPERTY_VALUE_MAX> primaryIfaceName;
+ char p2pParentIfname[100];
+ std::string p2pDevIfName = "";
std::array<char, PROPERTY_VALUE_MAX> buffer;
property_get("wifi.direct.interface", buffer.data(), "p2p0");
+ if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX,
+ strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+ /* Get the p2p parent interface name from p2p device interface name set
+ * in property */
+ strncpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX),
+ strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX));
+ if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(),
+ nullptr) == 0) {
+ return buffer.data();
+ }
+ /* Check if the parent interface derived from p2p device interface name
+ * is active */
+ if (strncmp(p2pParentIfname, primaryIfaceName.data(),
+ strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) !=
+ 0) {
+ /*
+ * Update the predefined p2p device interface parent interface name
+ * with current active wlan interface
+ */
+ p2pDevIfName += P2P_MGMT_DEVICE_PREFIX;
+ p2pDevIfName += primaryIfaceName.data();
+ LOG(INFO) << "update the p2p device interface name to "
+ << p2pDevIfName.c_str();
+ return p2pDevIfName;
+ }
+ }
return buffer.data();
}
diff --git a/wifi/1.5/default/wifi_iface_util.cpp b/wifi/1.5/default/wifi_iface_util.cpp
index 7bf830b..0977026 100644
--- a/wifi/1.5/default/wifi_iface_util.cpp
+++ b/wifi/1.5/default/wifi_iface_util.cpp
@@ -56,14 +56,21 @@
bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
const std::array<uint8_t, 6>& mac) {
#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
- if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
+ legacy_hal::wifi_error legacy_status;
+ uint64_t legacy_feature_set;
+ std::tie(legacy_status, legacy_feature_set) =
+ legacy_hal_.lock()->getSupportedFeatureSet(iface_name);
+
+ if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+ !iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
LOG(ERROR) << "SetUpState(false) failed.";
return false;
}
#endif
bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac);
#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
- if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+ if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+ !iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready.";
// Wait for driver ready and try to set iface UP again
if (legacy_hal_.lock()->waitForDriverReady() !=
diff --git a/wifi/supplicant/1.0/vts/OWNERS b/wifi/supplicant/1.0/vts/OWNERS
index cf81c79..b16dc11 100644
--- a/wifi/supplicant/1.0/vts/OWNERS
+++ b/wifi/supplicant/1.0/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.1/vts/OWNERS b/wifi/supplicant/1.1/vts/OWNERS
index cf81c79..b16dc11 100644
--- a/wifi/supplicant/1.1/vts/OWNERS
+++ b/wifi/supplicant/1.1/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.2/vts/OWNERS b/wifi/supplicant/1.2/vts/OWNERS
index cf81c79..b16dc11 100644
--- a/wifi/supplicant/1.2/vts/OWNERS
+++ b/wifi/supplicant/1.2/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.3/vts/OWNERS b/wifi/supplicant/1.3/vts/OWNERS
index cf81c79..287152d 100644
--- a/wifi/supplicant/1.3/vts/OWNERS
+++ b/wifi/supplicant/1.3/vts/OWNERS
@@ -1,2 +1,3 @@
+# Bug component: 33618
arabawy@google.com
etancohen@google.com
diff --git a/wifi/supplicant/1.4/vts/OWNERS b/wifi/supplicant/1.4/vts/OWNERS
index cf81c79..b16dc11 100644
--- a/wifi/supplicant/1.4/vts/OWNERS
+++ b/wifi/supplicant/1.4/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.3/vts/OWNERS