Merge "Revert "KeyMint VTS: add TEST_MAPPING""
diff --git a/audio/aidl/OWNERS b/audio/aidl/OWNERS
new file mode 100644
index 0000000..f9a2d6b
--- /dev/null
+++ b/audio/aidl/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 48436
+elaurent@google.com
+mnaganov@google.com
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
index c0c17e2..05691d9 100644
--- a/automotive/can/1.0/default/Android.bp
+++ b/automotive/can/1.0/default/Android.bp
@@ -46,13 +46,7 @@
vendor: true,
relative_install_path: "hw",
srcs: [
- "CanBus.cpp",
- "CanBusNative.cpp",
- "CanBusVirtual.cpp",
- "CanBusSlcan.cpp",
- "CanController.cpp",
- "CanSocket.cpp",
- "CloseHandle.cpp",
+ ":automotiveCanV1.0_sources",
"service.cpp",
],
shared_libs: [
@@ -64,4 +58,24 @@
"android.hardware.automotive@libc++fs",
"libnl++",
],
+ vintf_fragments: ["manifest_android.hardware.automotive.can@1.0.xml"],
+}
+
+filegroup {
+ name: "automotiveCanV1.0_sources",
+ srcs: [
+ "CanBus.cpp",
+ "CanBusNative.cpp",
+ "CanBusVirtual.cpp",
+ "CanBusSlcan.cpp",
+ "CanController.cpp",
+ "CanSocket.cpp",
+ "CloseHandle.cpp",
+ ],
+}
+
+cc_library_headers {
+ name: "automotiveCanV1.0_headers",
+ vendor: true,
+ export_include_dirs: ["."],
}
diff --git a/automotive/can/1.0/default/manifest_android.hardware.automotive.can@1.0.xml b/automotive/can/1.0/default/manifest_android.hardware.automotive.can@1.0.xml
new file mode 100644
index 0000000..2078ce5
--- /dev/null
+++ b/automotive/can/1.0/default/manifest_android.hardware.automotive.can@1.0.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest version="1.0" type="device" >
+ <hal format="hidl">
+ <name>android.hardware.automotive.can</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.0::ICanController/socketcan</fqname>
+ </hal>
+</manifest>
diff --git a/automotive/can/1.0/default/tests/fuzzer/Android.bp b/automotive/can/1.0/default/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..52b43b0
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_fuzz {
+ name: "automotiveCanV1.0_fuzzer",
+ vendor: true,
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "AutomotiveCanV1_0Fuzzer.cpp",
+ ":automotiveCanV1.0_sources",
+ ],
+ header_libs: [
+ "automotiveCanV1.0_headers",
+ "android.hardware.automotive.can@hidl-utils-lib",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libhidlbase",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@libnetdevice",
+ "android.hardware.automotive@libc++fs",
+ "libnl++",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 533764,
+ },
+}
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
new file mode 100644
index 0000000..96110db
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "AutomotiveCanV1_0Fuzzer.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
+
+constexpr CanController::InterfaceType kInterfaceType[] = {CanController::InterfaceType::VIRTUAL,
+ CanController::InterfaceType::SOCKETCAN,
+ CanController::InterfaceType::SLCAN};
+constexpr FilterFlag kFilterFlag[] = {FilterFlag::DONT_CARE, FilterFlag::SET, FilterFlag::NOT_SET};
+constexpr size_t kInterfaceTypeLength = std::size(kInterfaceType);
+constexpr size_t kFilterFlagLength = std::size(kFilterFlag);
+constexpr size_t kMaxCharacters = 30;
+constexpr size_t kMaxPayloadBytes = 64;
+constexpr size_t kMaxFilters = 20;
+constexpr size_t kMaxSerialNumber = 1000;
+constexpr size_t kMaxBuses = 10;
+constexpr size_t kMaxRepeat = 5;
+
+Bus CanFuzzer::makeBus() {
+ ICanController::BusConfig config = {};
+ if (mBusNames.size() > 0 && mLastInterface < mBusNames.size()) {
+ config.name = mBusNames[mLastInterface++];
+ } else {
+ config.name = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+ }
+ config.interfaceId.virtualif({mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters)});
+ return Bus(mCanController, config);
+}
+
+void CanFuzzer::getSupportedInterfaceTypes() {
+ hidl_vec<CanController::InterfaceType> iftypesResult;
+ mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult));
+}
+
+hidl_vec<hidl_string> CanFuzzer::getBusNames() {
+ hidl_vec<hidl_string> services = {};
+ if (auto manager = hidl::manager::V1_2::IServiceManager::getService(); manager) {
+ manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services));
+ }
+ return services;
+}
+
+void CanFuzzer::invokeUpInterface() {
+ const CanController::InterfaceType iftype =
+ kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+ 0, kInterfaceTypeLength - 1)];
+ std::string configName;
+
+ if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
+ (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
+ const size_t busNameIndex =
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+ configName = mBusNames[busNameIndex];
+ } else {
+ configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+ }
+ const std::string ifname = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+
+ ICanController::BusConfig config = {.name = configName};
+
+ if (iftype == CanController::InterfaceType::SOCKETCAN) {
+ CanController::BusConfig::InterfaceId::Socketcan socketcan = {};
+ if (const bool shouldPassSerialSocket = mFuzzedDataProvider->ConsumeBool();
+ shouldPassSerialSocket) {
+ socketcan.serialno(
+ {mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxSerialNumber)});
+ } else {
+ socketcan.ifname(ifname);
+ }
+ config.interfaceId.socketcan(socketcan);
+ } else if (iftype == CanController::InterfaceType::SLCAN) {
+ CanController::BusConfig::InterfaceId::Slcan slcan = {};
+ if (const bool shouldPassSerialSlcan = mFuzzedDataProvider->ConsumeBool();
+ shouldPassSerialSlcan) {
+ slcan.serialno(
+ {mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxSerialNumber)});
+ } else {
+ slcan.ttyname(ifname);
+ }
+ config.interfaceId.slcan(slcan);
+ } else if (iftype == CanController::InterfaceType::VIRTUAL) {
+ config.interfaceId.virtualif({ifname});
+ }
+
+ const size_t numInvocations =
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kMaxRepeat);
+ for (size_t i = 0; i < numInvocations; ++i) {
+ mCanController->upInterface(config);
+ }
+}
+
+void CanFuzzer::invokeDownInterface() {
+ hidl_string configName;
+ if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
+ (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
+ const size_t busNameIndex =
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+ configName = mBusNames[busNameIndex];
+ } else {
+ configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+ }
+
+ const size_t numInvocations =
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kMaxRepeat);
+ for (size_t i = 0; i < numInvocations; ++i) {
+ mCanController->downInterface(configName);
+ }
+}
+
+void CanFuzzer::invokeController() {
+ getSupportedInterfaceTypes();
+ invokeUpInterface();
+ invokeDownInterface();
+}
+
+void CanFuzzer::invokeBus() {
+ const size_t numBuses = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(1, kMaxBuses);
+ for (size_t i = 0; i < numBuses; ++i) {
+ if (const bool shouldSendMessage = mFuzzedDataProvider->ConsumeBool(); shouldSendMessage) {
+ auto sendingBus = makeBus();
+ CanMessage msg = {.id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>()};
+ uint32_t numPayloadBytes =
+ mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxPayloadBytes);
+ hidl_vec<uint8_t> payload(numPayloadBytes);
+ for (uint32_t j = 0; j < numPayloadBytes; ++j) {
+ payload[j] = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+ }
+ msg.payload = payload;
+ msg.remoteTransmissionRequest = mFuzzedDataProvider->ConsumeBool();
+ msg.isExtendedId = mFuzzedDataProvider->ConsumeBool();
+ sendingBus.send(msg);
+ } else {
+ auto listeningBus = makeBus();
+ uint32_t numFilters =
+ mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(1, kMaxFilters);
+ hidl_vec<CanMessageFilter> filterVector(numFilters);
+ for (uint32_t k = 0; k < numFilters; ++k) {
+ filterVector[k].id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+ filterVector[k].mask = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+ filterVector[k].rtr =
+ kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+ 0, kFilterFlagLength - 1)];
+ filterVector[k].extendedFormat =
+ kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+ 0, kFilterFlagLength - 1)];
+ filterVector[k].exclude = mFuzzedDataProvider->ConsumeBool();
+ }
+ auto listener = listeningBus.listen(filterVector);
+ }
+ }
+}
+
+void CanFuzzer::deInit() {
+ mCanController.clear();
+ if (mFuzzedDataProvider) {
+ delete mFuzzedDataProvider;
+ }
+ mBusNames = {};
+}
+
+void CanFuzzer::process(const uint8_t* data, size_t size) {
+ mFuzzedDataProvider = new FuzzedDataProvider(data, size);
+ invokeController();
+ invokeBus();
+}
+
+bool CanFuzzer::init() {
+ mCanController = sp<CanController>::make();
+ if (!mCanController) {
+ return false;
+ }
+ mBusNames = getBusNames();
+ return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < 1) {
+ return 0;
+ }
+ CanFuzzer canFuzzer;
+ if (canFuzzer.init()) {
+ canFuzzer.process(data, size);
+ }
+ return 0;
+}
+
+} // namespace android::hardware::automotive::can::V1_0::implementation::fuzzer
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
new file mode 100644
index 0000000..930cddd
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
+#define __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
+#include <CanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
+
+using ::android::sp;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+ DISALLOW_COPY_AND_ASSIGN(CanMessageListener);
+
+ CanMessageListener() {}
+
+ virtual Return<void> onReceive(const can::V1_0::CanMessage& msg) override {
+ std::unique_lock<std::mutex> lock(mMessagesGuard);
+ mMessages.push_back(msg);
+ mMessagesUpdated.notify_one();
+ return {};
+ }
+
+ virtual ~CanMessageListener() {
+ if (mCloseHandle) {
+ mCloseHandle->close();
+ }
+ }
+
+ void assignCloseHandle(sp<ICloseHandle> closeHandle) { mCloseHandle = closeHandle; }
+
+ private:
+ sp<ICloseHandle> mCloseHandle;
+
+ std::mutex mMessagesGuard;
+ std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard);
+ std::vector<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+};
+
+struct Bus {
+ DISALLOW_COPY_AND_ASSIGN(Bus);
+
+ Bus(sp<ICanController> controller, const ICanController::BusConfig& config)
+ : mIfname(config.name), mController(controller) {
+ const auto result = controller->upInterface(config);
+ const auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ const auto service = manager->get(ICanBus::descriptor, config.name);
+ mBus = ICanBus::castFrom(service);
+ }
+
+ virtual ~Bus() { reset(); }
+
+ void reset() {
+ mBus.clear();
+ if (mController) {
+ mController->downInterface(mIfname);
+ mController.clear();
+ }
+ }
+
+ ICanBus* operator->() const { return mBus.get(); }
+ sp<ICanBus> get() { return mBus; }
+
+ sp<CanMessageListener> listen(const hidl_vec<CanMessageFilter>& filter) {
+ sp<CanMessageListener> listener = sp<CanMessageListener>::make();
+
+ if (!mBus) {
+ return listener;
+ }
+ Result result;
+ sp<ICloseHandle> closeHandle;
+ mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk();
+ listener->assignCloseHandle(closeHandle);
+
+ return listener;
+ }
+
+ void send(const CanMessage& msg) {
+ if (!mBus) {
+ return;
+ }
+ mBus->send(msg);
+ }
+
+ private:
+ const std::string mIfname;
+ sp<ICanController> mController;
+ sp<ICanBus> mBus;
+};
+
+class CanFuzzer {
+ public:
+ ~CanFuzzer() { deInit(); }
+ bool init();
+ void process(const uint8_t* data, size_t size);
+ void deInit();
+
+ private:
+ Bus makeBus();
+ hidl_vec<hidl_string> getBusNames();
+ void getSupportedInterfaceTypes();
+ void invokeBus();
+ void invokeController();
+ void invokeUpInterface();
+ void invokeDownInterface();
+ FuzzedDataProvider* mFuzzedDataProvider = nullptr;
+ sp<CanController> mCanController = nullptr;
+ hidl_vec<hidl_string> mBusNames = {};
+ unsigned mLastInterface = 0;
+};
+} // namespace android::hardware::automotive::can::V1_0::implementation::fuzzer
+
+#endif // __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
index ad607d8..9c72acd 100644
--- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
@@ -18,7 +18,7 @@
// These values are called out in the EVS design doc (as of Mar 8, 2017)
-static const int kMaxStreamStartMilliseconds = 500;
+static const int kMaxStreamStartMilliseconds = 1000;
static const int kMinimumFramesPerSecond = 10;
static const int kSecondsToMilliseconds = 1000;
@@ -332,11 +332,6 @@
printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds);
ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds);
- // Check aspect ratio
- unsigned width = 0, height = 0;
- frameHandler->getFrameDimension(&width, &height);
- EXPECT_GE(width, height);
-
// Wait a bit, then ensure we get at least the required minimum number of frames
sleep(5);
nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -370,7 +365,7 @@
ALOGI("Starting CameraStreamBuffering test");
// Arbitrary constant (should be > 1 and not too big)
- static const unsigned int kBuffersToHold = 6;
+ static const unsigned int kBuffersToHold = 2;
// Get the camera list
loadCameraList();
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 8cc1882..d7f9ff8 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
@@ -472,11 +499,6 @@
<< std::scientific << timeToFirstFrame * kNanoToMilliseconds
<< " ms.";
- // Check aspect ratio
- unsigned width = 0, height = 0;
- frameHandler->getFrameDimension(&width, &height);
- EXPECT_GE(width, height);
-
// Wait a bit, then ensure we get at least the required minimum number of frames
sleep(5);
nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -514,15 +536,11 @@
LOG(INFO) << "Starting CameraStreamBuffering test";
// Arbitrary constant (should be > 1 and not too big)
- static const unsigned int kBuffersToHold = 6;
+ static const unsigned int kBuffersToHold = 2;
// 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 +550,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 +623,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 +660,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 +730,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 +832,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 +844,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 +981,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 +992,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 +1160,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 +1171,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 +1631,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 +2015,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 +2040,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 +2118,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 +2144,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 +2154,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 +2162,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 +2264,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 +2289,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 +2305,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 +2320,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 +2340,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 +2356,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 +2365,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/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
index 583a455..58423c8 100644
--- a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
+++ b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <fuzzer/FuzzedDataProvider.h>
#include <cmath>
#include <cstdlib>
#include <cstring>
@@ -21,36 +22,43 @@
#include "FormatConvert.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) {
- if (size < 256) {
+ // 1 random value (4bytes) + min imagesize = 16*2 times bytes per pixel (worse case 2)
+ if (size < (4 + 16 * 2 * 2)) {
return 0;
}
+ FuzzedDataProvider fdp(data, size);
+ std::size_t image_pixel_size = size - 4;
+ image_pixel_size = (image_pixel_size & INT_MAX) / 2;
- std::srand(std::time(nullptr)); // use current time as seed for random generator
- int random_variable = std::rand() % 10;
- int width = (int)sqrt(size);
- int height = width * ((float)random_variable / 10.0);
+ // API have a requirement that width must be divied by 16 except yuyvtorgb
+ int min_height = 2;
+ int max_height = (image_pixel_size / 16) & ~(1); // must be even number
+ int height = fdp.ConsumeIntegralInRange<uint32_t>(min_height, max_height);
+ int width = (image_pixel_size / height) & ~(16); // must be divisible by 16
- uint8_t* src = (uint8_t*)malloc(sizeof(uint8_t) * size);
- memcpy(src, data, sizeof(uint8_t) * (size));
- uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * size);
+ uint8_t* src = (uint8_t*)(data + 4);
+ uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * image_pixel_size);
#ifdef COPY_NV21_TO_RGB32
- android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt, 0);
+ android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt,
+ width);
#elif COPY_NV21_TO_BGR32
- android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt, 0);
+ android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt,
+ width);
#elif COPY_YV12_TO_RGB32
- android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt, 0);
+ android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt,
+ width);
#elif COPY_YV12_TO_BGR32
- android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt, 0);
+ android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt,
+ width);
#elif COPY_YUYV_TO_RGB32
- android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, 0, tgt,
- 0);
+ android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, width,
+ tgt, width);
#elif COPY_YUYV_TO_BGR32
- android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, 0, tgt,
- 0);
+ android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, width,
+ tgt, width);
#endif
- free(src);
free(tgt);
return 0;
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 14177dd..ba33098 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -185,6 +185,7 @@
],
shared_libs: [
"libbase",
+ "libcutils",
],
header_libs: ["libbase_headers"],
test_suites: ["general-tests"],
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
index c8c89dc..44f9134 100644
--- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
@@ -1,4 +1,4 @@
service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service
- class hal
+ class early_hal
user vehicle_network
group system inet
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
index fcfe761..6706258 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -76,6 +76,9 @@
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
private:
+ // Set unit test class as friend class to test private functions.
+ friend class VehicleHalManagerTestHelper;
+
using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr;
// Returns true if needs to call again shortly.
using RetriableAction = std::function<bool()>;
@@ -105,14 +108,20 @@
void cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId);
void cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config);
+ bool cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options);
+
static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize);
static bool checkCallerHasWritePermissions(int fd);
- static bool safelyParseInt(int fd, int index, std::string s, int* out);
+ template <typename T>
+ static bool safelyParseInt(int fd, int index, const std::string& s, T* out);
+ static bool safelyParseFloat(int fd, int index, const std::string& s, float* out);
+ // Parses "s" as a hex string and populate "*bytes". The hex string must be in the format of
+ // valid hex format, e.g. "0xABCD".
+ static bool parseHexString(int fd, const std::string& s, std::vector<uint8_t>* bytes);
void cmdHelp(int fd) const;
void cmdListAllProperties(int fd) const;
void cmdDumpAllProperties(int fd);
void cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options);
- void cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options);
static bool isSubscribable(const VehiclePropConfig& config,
SubscribeFlags flags);
@@ -120,7 +129,18 @@
static float checkSampleRate(const VehiclePropConfig& config,
float sampleRate);
static ClientId getClientId(const sp<IVehicleCallback>& callback);
-private:
+
+ // Parses the cmdline options for "--set" command. "*prop" would be populated with the
+ // the properties to be set. Returns true when the cmdline options are valid, false otherwise.
+ static bool parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options,
+ VehiclePropValue* prop);
+ // Parses the options and get the values for the current option specified by "*index". "*index"
+ // would advance to the next option field (e.g., the next "-f"). Returns a list of values for
+ // the current option.
+ static std::vector<std::string> getOptionValues(const hidl_vec<hidl_string>& options,
+ size_t* index);
+
+ private:
VehicleHal* mHal;
std::unique_ptr<VehiclePropConfigIndex> mConfigIndex;
SubscriptionManager mSubscriptionManager;
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index dc5d3d3..e34e692 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -20,7 +20,9 @@
#include <cmath>
#include <fstream>
+#include <unordered_set>
+#include <android-base/parsedouble.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h>
@@ -44,15 +46,34 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
+namespace {
+
constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
const VehiclePropValue kEmptyValue{};
+// A list of supported options for "--set" command.
+const std::unordered_set<std::string> kSetPropOptions = {
+ // integer.
+ "-i",
+ // 64bit integer.
+ "-i64",
+ // float.
+ "-f",
+ // string.
+ "-s",
+ // bytes in hex format, e.g. 0xDEADBEEF.
+ "-b",
+ // Area id in integer.
+ "-a"};
+
+} // namespace
+
/**
* Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want
* to store in reusable object pool.
*/
-constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
+constexpr auto kMaxHidlVecOfVehiclePropValuePoolSize = 20;
Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
ALOGI("getAllPropConfigs called");
@@ -213,6 +234,11 @@
} else if (EqualsIgnoreCase(option, "--get")) {
cmdDumpSpecificProperties(fd, options);
} else if (EqualsIgnoreCase(option, "--set")) {
+ if (!checkCallerHasWritePermissions(fd)) {
+ dprintf(fd, "Caller does not have write permission\n");
+ return;
+ }
+ // Ignore the return value for this.
cmdSetOneProperty(fd, options);
} else {
dprintf(fd, "Invalid option: %s\n", option.c_str());
@@ -239,7 +265,8 @@
return false;
}
-bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* out) {
+template <typename T>
+bool VehicleHalManager::safelyParseInt(int fd, int index, const std::string& s, T* out) {
if (!android::base::ParseInt(s, out)) {
dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str());
return false;
@@ -247,19 +274,27 @@
return true;
}
+bool VehicleHalManager::safelyParseFloat(int fd, int index, const std::string& s, float* out) {
+ if (!android::base::ParseFloat(s, out)) {
+ dprintf(fd, "non-float argument at index %d: %s\n", index, s.c_str());
+ return false;
+ }
+ return true;
+}
+
void VehicleHalManager::cmdHelp(int fd) const {
dprintf(fd, "Usage: \n\n");
dprintf(fd, "[no args]: dumps (id and value) all supported properties \n");
dprintf(fd, "--help: shows this help\n");
dprintf(fd, "--list: lists the ids of all supported properties\n");
dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n");
- // TODO: support other formats (int64, float, bytes)
dprintf(fd,
- "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of "
- "property PROP, using arbitrary number of key/value parameters (i for int32, "
- "s for string) and an optional area.\n"
- "Notice that the string value can be set just once, while the other can have multiple "
- "values (so they're used in the respective array)\n");
+ "--set <PROP> [-i INT_VALUE [INT_VALUE ...]] [-i64 INT64_VALUE [INT64_VALUE ...]] "
+ "[-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
+ "[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. "
+ "Notice that the string, bytes and area value can be set just once, while the other can"
+ " have multiple values (so they're used in the respective array), "
+ "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n");
}
void VehicleHalManager::cmdListAllProperties(int fd) const {
@@ -337,102 +372,49 @@
VehiclePropValue input;
input.prop = prop;
input.areaId = areaId;
- auto callback = [&](StatusCode status, const VehiclePropValue& output) {
+ auto callback = [&fd, &prop](StatusCode status, const VehiclePropValue& output) {
if (status == StatusCode::OK) {
dprintf(fd, "%s\n", toString(output).c_str());
} else {
dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str());
}
};
- get(input, callback);
+
+ StatusCode status;
+ auto value = mHal->get(input, &status);
+ callback(status, value.get() ? *value : kEmptyValue);
}
-void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
- if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return;
-
- size_t size = options.size();
-
- // Syntax is --set PROP Type1 Value1 TypeN ValueN, so number of arguments must be even
- if (size % 2 != 0) {
- dprintf(fd, "must pass even number of arguments (passed %zu)\n", size);
- return;
+bool VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
+ if (!checkArgumentsSize(fd, options, 4)) {
+ dprintf(fd, "Requires at least 4 options, see help\n");
+ return false;
}
- int numberValues = (size - 2) / 2;
- VehiclePropValue prop;
- if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return;
- prop.timestamp = elapsedRealtimeNano();
- prop.status = VehiclePropertyStatus::AVAILABLE;
-
- // First pass: calculate sizes
- int sizeInt32 = 0;
- int stringIndex = 0;
- int areaIndex = 0;
- for (int i = 2, kv = 1; kv <= numberValues; kv++) {
- // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
- std::string type = options[i];
- std::string value = options[i + 1];
- if (EqualsIgnoreCase(type, "i")) {
- sizeInt32++;
- } else if (EqualsIgnoreCase(type, "s")) {
- if (stringIndex != 0) {
- dprintf(fd,
- "defining string value (%s) again at index %d (already defined at %d=%s"
- ")\n",
- value.c_str(), i, stringIndex, options[stringIndex + 1].c_str());
- return;
- }
- stringIndex = i;
- } else if (EqualsIgnoreCase(type, "a")) {
- if (areaIndex != 0) {
- dprintf(fd,
- "defining area value (%s) again at index %d (already defined at %d=%s"
- ")\n",
- value.c_str(), i, areaIndex, options[areaIndex + 1].c_str());
- return;
- }
- areaIndex = i;
- } else {
- dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i);
- return;
- }
- i += 2;
- }
- prop.value.int32Values.resize(sizeInt32);
-
- // Second pass: populate it
- int indexInt32 = 0;
- for (int i = 2, kv = 1; kv <= numberValues; kv++) {
- // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
- int valueIndex = i + 1;
- std::string type = options[i];
- std::string value = options[valueIndex];
- if (EqualsIgnoreCase(type, "i")) {
- int safeInt;
- if (!safelyParseInt(fd, valueIndex, value, &safeInt)) return;
- prop.value.int32Values[indexInt32++] = safeInt;
- } else if (EqualsIgnoreCase(type, "s")) {
- prop.value.stringValue = value;
- } else if (EqualsIgnoreCase(type, "a")) {
- if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return;
- }
- i += 2;
+ VehiclePropValue prop = {};
+ if (!parseSetPropOptions(fd, options, &prop)) {
+ return false;
}
ALOGD("Setting prop %s", toString(prop).c_str());
- auto status = set(prop);
+
+ // Do not use VehicleHalManager::set here because we don't want to check write permission.
+ // Caller should be able to use the debug interface to set read-only properties.
+ handlePropertySetEvent(prop);
+ auto status = mHal->set(prop);
+
if (status == StatusCode::OK) {
dprintf(fd, "Set property %s\n", toString(prop).c_str());
- } else {
- dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
- toString(status).c_str());
+ return true;
}
+ dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
+ toString(status).c_str());
+ return false;
}
void VehicleHalManager::init() {
ALOGI("VehicleHalManager::init");
- mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize);
-
+ mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclePropValuePoolSize);
mBatchingConsumer.run(&mEventQueue,
kHalEventBatchingTimeWindow,
@@ -486,7 +468,7 @@
for (const HalClientValues& cv : clientValues) {
auto vecSize = cv.values.size();
hidl_vec<VehiclePropValue> vec;
- if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
+ if (vecSize < kMaxHidlVecOfVehiclePropValuePoolSize) {
vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
} else {
vec.resize(vecSize);
@@ -595,6 +577,158 @@
}
}
+std::vector<std::string> VehicleHalManager::getOptionValues(const hidl_vec<hidl_string>& options,
+ size_t* index) {
+ std::vector<std::string> values;
+ while (*index < options.size()) {
+ std::string option = options[*index];
+ if (kSetPropOptions.find(option) != kSetPropOptions.end()) {
+ return std::move(values);
+ }
+ values.push_back(option);
+ (*index)++;
+ }
+ return std::move(values);
+}
+
+bool VehicleHalManager::parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options,
+ VehiclePropValue* prop) {
+ // Options format:
+ // --set PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...] [-b b1 b2...] [-a a]
+ size_t optionIndex = 1;
+ int propValue;
+ if (!safelyParseInt(fd, optionIndex, options[optionIndex], &propValue)) {
+ dprintf(fd, "property value: \"%s\" is not a valid int\n", options[optionIndex].c_str());
+ return false;
+ }
+ prop->prop = propValue;
+ prop->timestamp = elapsedRealtimeNano();
+ prop->status = VehiclePropertyStatus::AVAILABLE;
+ optionIndex++;
+ std::unordered_set<std::string> parsedOptions;
+
+ while (optionIndex < options.size()) {
+ std::string type = options[optionIndex];
+ optionIndex++;
+ size_t currentIndex = optionIndex;
+ std::vector<std::string> values = getOptionValues(options, &optionIndex);
+ if (parsedOptions.find(type) != parsedOptions.end()) {
+ dprintf(fd, "duplicate \"%s\" options\n", type.c_str());
+ return false;
+ }
+ parsedOptions.insert(type);
+ if (EqualsIgnoreCase(type, "-i")) {
+ if (values.size() == 0) {
+ dprintf(fd, "no values specified when using \"-i\"\n");
+ return false;
+ }
+ prop->value.int32Values.resize(values.size());
+ for (size_t i = 0; i < values.size(); i++) {
+ int32_t safeInt;
+ if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) {
+ dprintf(fd, "value: \"%s\" is not a valid int\n", values[i].c_str());
+ return false;
+ }
+ prop->value.int32Values[i] = safeInt;
+ }
+ } else if (EqualsIgnoreCase(type, "-i64")) {
+ if (values.size() == 0) {
+ dprintf(fd, "no values specified when using \"-i64\"\n");
+ return false;
+ }
+ prop->value.int64Values.resize(values.size());
+ for (size_t i = 0; i < values.size(); i++) {
+ int64_t safeInt;
+ if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) {
+ dprintf(fd, "value: \"%s\" is not a valid int64\n", values[i].c_str());
+ return false;
+ }
+ prop->value.int64Values[i] = safeInt;
+ }
+ } else if (EqualsIgnoreCase(type, "-f")) {
+ if (values.size() == 0) {
+ dprintf(fd, "no values specified when using \"-f\"\n");
+ return false;
+ }
+ prop->value.floatValues.resize(values.size());
+ for (size_t i = 0; i < values.size(); i++) {
+ float safeFloat;
+ if (!safelyParseFloat(fd, currentIndex + i, values[i], &safeFloat)) {
+ dprintf(fd, "value: \"%s\" is not a valid float\n", values[i].c_str());
+ return false;
+ }
+ prop->value.floatValues[i] = safeFloat;
+ }
+ } else if (EqualsIgnoreCase(type, "-s")) {
+ if (values.size() != 1) {
+ dprintf(fd, "expect exact one value when using \"-s\"\n");
+ return false;
+ }
+ prop->value.stringValue = values[0];
+ } else if (EqualsIgnoreCase(type, "-b")) {
+ if (values.size() != 1) {
+ dprintf(fd, "expect exact one value when using \"-b\"\n");
+ return false;
+ }
+ std::vector<uint8_t> bytes;
+ if (!parseHexString(fd, values[0], &bytes)) {
+ dprintf(fd, "value: \"%s\" is not a valid hex string\n", values[0].c_str());
+ return false;
+ }
+ prop->value.bytes = bytes;
+ } else if (EqualsIgnoreCase(type, "-a")) {
+ if (values.size() != 1) {
+ dprintf(fd, "expect exact one value when using \"-a\"\n");
+ return false;
+ }
+ if (!safelyParseInt(fd, currentIndex, values[0], &(prop->areaId))) {
+ dprintf(fd, "area ID: \"%s\" is not a valid int\n", values[0].c_str());
+ return false;
+ }
+ } else {
+ dprintf(fd, "unknown option: %s\n", type.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool VehicleHalManager::parseHexString(int fd, const std::string& s, std::vector<uint8_t>* bytes) {
+ if (s.size() % 2 != 0) {
+ dprintf(fd, "invalid hex string: %s, should have even size\n", s.c_str());
+ return false;
+ }
+ if (strncmp(s.substr(0, 2).c_str(), "0x", 2)) {
+ dprintf(fd, "hex string should start with \"0x\", got %s\n", s.c_str());
+ return false;
+ }
+ std::string subs = s.substr(2);
+ std::transform(subs.begin(), subs.end(), subs.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+
+ bool highDigit = true;
+ for (size_t i = 0; i < subs.size(); i++) {
+ char c = subs[i];
+ uint8_t v;
+ if (c >= '0' && c <= '9') {
+ v = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ v = c - 'a' + 10;
+ } else {
+ dprintf(fd, "invalid character %c in hex string %s\n", c, subs.c_str());
+ return false;
+ }
+ if (highDigit) {
+ (*bytes).push_back(v * 16);
+ } else {
+ (*bytes)[bytes->size() - 1] += v;
+ }
+ highDigit = !highDigit;
+ }
+ return true;
+}
+
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 8ff4924..55617be 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -307,6 +307,18 @@
.prop = toInt(VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = WHEEL_FRONT_LEFT,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_FRONT_RIGHT,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_REAR_LEFT,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_REAR_RIGHT,
+ }},
},
.initialAreaValues = {{WHEEL_FRONT_LEFT, {.floatValues = {137.0f}}},
{WHEEL_FRONT_RIGHT, {.floatValues = {137.0f}}},
@@ -1032,14 +1044,6 @@
{
.config =
{
- .prop = toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
.prop = toInt(VehicleProperty::WATCHDOG_ALIVE),
.access = VehiclePropertyAccess::WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -1105,6 +1109,42 @@
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
},
+ {
+ .config =
+ {
+ .prop = PLACEHOLDER_PROPERTY_INT,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0}},
+ },
+ {
+ .config =
+ {
+ .prop = PLACEHOLDER_PROPERTY_FLOAT,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.floatValues = {0.0f}},
+ },
+ {
+ .config =
+ {
+ .prop = PLACEHOLDER_PROPERTY_BOOLEAN,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0 /* false */}},
+ },
+ {
+ .config =
+ {
+ .prop = PLACEHOLDER_PROPERTY_STRING,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.stringValue = {"Test"}},
+ },
#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
// Vendor propetry for E2E ClusterHomeService testing.
{
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
index d5f6a18..51251a7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
@@ -189,6 +189,19 @@
KeyPress = 100,
};
+/**
+ * These properties are placeholder properties for developers to test new features without
+ * implementing a real property.
+ */
+constexpr int32_t PLACEHOLDER_PROPERTY_INT =
+ 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::INT32;
+constexpr int32_t PLACEHOLDER_PROPERTY_FLOAT =
+ 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::FLOAT;
+constexpr int32_t PLACEHOLDER_PROPERTY_BOOLEAN =
+ 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::BOOLEAN;
+constexpr int32_t PLACEHOLDER_PROPERTY_STRING =
+ 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::STRING;
+
const int32_t kHvacPowerProperties[] = {
toInt(VehicleProperty::HVAC_FAN_SPEED),
toInt(VehicleProperty::HVAC_FAN_DIRECTION),
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
index 0975071..bdf46fb 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -18,6 +18,7 @@
#include <iostream>
#include <android-base/macros.h>
+#include <cutils/native_handle.h>
#include <utils/SystemClock.h>
#include <gtest/gtest.h>
@@ -32,6 +33,18 @@
namespace vehicle {
namespace V2_0 {
+// A simple helper class to expose 'cmdSetOneProperty' to the unit tests.
+class VehicleHalManagerTestHelper {
+ public:
+ VehicleHalManagerTestHelper(VehicleHalManager* manager) { mManager = manager; }
+ bool cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
+ return mManager->cmdSetOneProperty(fd, options);
+ }
+
+ public:
+ VehicleHalManager* mManager;
+};
+
namespace {
using namespace std::placeholders;
@@ -57,33 +70,21 @@
auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
int32_t areaId = requestedPropValue.areaId;
- switch (property) {
- case VehicleProperty::INFO_MAKE:
- pValue = getValuePool()->obtainString(kCarMake);
- break;
- case VehicleProperty::INFO_FUEL_CAPACITY:
- if (fuelCapacityAttemptsLeft-- > 0) {
- // Emulate property not ready yet.
- *outStatus = StatusCode::TRY_AGAIN;
- } else {
- pValue = getValuePool()->obtainFloat(42.42);
- }
- break;
- default:
- if (requestedPropValue.prop == kCustomComplexProperty) {
- pValue = getValuePool()->obtainComplex();
- pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 };
- pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 };
- pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 };
- pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 };
- pValue->value.stringValue = kCarMake;
- break;
- }
- auto key = makeKey(toInt(property), areaId);
- if (mValues.count(key) == 0) {
- ALOGW("");
- }
- pValue = getValuePool()->obtain(mValues[key]);
+ if (property == VehicleProperty::INFO_FUEL_CAPACITY) {
+ if (fuelCapacityAttemptsLeft-- > 0) {
+ // Emulate property not ready yet.
+ *outStatus = StatusCode::TRY_AGAIN;
+ } else {
+ pValue = getValuePool()->obtainFloat(42.42);
+ }
+ } else {
+ auto key = makeKey(requestedPropValue);
+ if (mValues.count(key) == 0) {
+ ALOGW("key not found\n");
+ *outStatus = StatusCode::INVALID_ARG;
+ return pValue;
+ }
+ pValue = getValuePool()->obtain(mValues[key]);
}
if (*outStatus == StatusCode::OK && pValue.get() != nullptr) {
@@ -100,7 +101,6 @@
&& mirrorFoldAttemptsLeft-- > 0) {
return StatusCode::TRY_AGAIN;
}
-
mValues[makeKey(propValue)] = propValue;
return StatusCode::OK;
}
@@ -181,6 +181,18 @@
actualStatusCode = refStatus;
}
+ MockedVehicleHal::VehiclePropValuePtr getComplexProperty() {
+ auto pValue = objectPool->obtainComplex();
+ pValue->prop = kCustomComplexProperty;
+ pValue->areaId = 0;
+ pValue->value.int32Values = hidl_vec<int32_t>{10, 20};
+ pValue->value.int64Values = hidl_vec<int64_t>{30, 40};
+ pValue->value.floatValues = hidl_vec<float_t>{1.1, 2.2};
+ pValue->value.bytes = hidl_vec<uint8_t>{1, 2, 3};
+ pValue->value.stringValue = kCarMake;
+ return pValue;
+ }
+
public:
VehiclePropValue actualValue;
StatusCode actualStatusCode;
@@ -308,6 +320,8 @@
}
TEST_F(VehicleHalManagerTest, get_Complex) {
+ ASSERT_EQ(StatusCode::OK, hal->set(*getComplexProperty().get()));
+
invokeGet(kCustomComplexProperty, 0);
ASSERT_EQ(StatusCode::OK, actualStatusCode);
@@ -334,6 +348,11 @@
}
TEST_F(VehicleHalManagerTest, get_StaticString) {
+ auto pValue = objectPool->obtainString(kCarMake);
+ pValue->prop = toInt(VehicleProperty::INFO_MAKE);
+ pValue->areaId = 0;
+ ASSERT_EQ(StatusCode::OK, hal->set(*pValue.get()));
+
invokeGet(toInt(VehicleProperty::INFO_MAKE), 0);
ASSERT_EQ(StatusCode::OK, actualStatusCode);
@@ -458,6 +477,138 @@
ASSERT_TRUE(clients.isEmpty());
}
+TEST_F(VehicleHalManagerTest, debug) {
+ hidl_handle fd = {};
+ fd.setTo(native_handle_create(/*numFds=*/1, /*numInts=*/0), /*shouldOwn=*/true);
+
+ // Because debug function returns void, so no way to check return value.
+ manager->debug(fd, {});
+ manager->debug(fd, {"--help"});
+ manager->debug(fd, {"--list"});
+ manager->debug(fd, {"--get"});
+ manager->debug(fd, {"--set"});
+ manager->debug(fd, {"invalid"});
+}
+
+struct SetPropTestCase {
+ std::string test_name;
+ const hidl_vec<hidl_string> configs;
+ bool success;
+};
+
+class VehicleHalManagerSetPropTest : public VehicleHalManagerTest,
+ public testing::WithParamInterface<SetPropTestCase> {};
+
+TEST_P(VehicleHalManagerSetPropTest, cmdSetOneProperty) {
+ const SetPropTestCase& tc = GetParam();
+ VehicleHalManagerTestHelper helper(manager.get());
+ ASSERT_EQ(tc.success, helper.cmdSetOneProperty(STDERR_FILENO, tc.configs));
+}
+
+std::vector<SetPropTestCase> GenSetPropParams() {
+ char infoMakeProperty[100] = {};
+ snprintf(infoMakeProperty, sizeof(infoMakeProperty), "%d", toInt(VehicleProperty::INFO_MAKE));
+ return {
+ {"success_set_string", {"--set", infoMakeProperty, "-s", kCarMake}, true},
+ {"success_set_bytes", {"--set", infoMakeProperty, "-b", "0xdeadbeef"}, true},
+ {"success_set_bytes_caps", {"--set", infoMakeProperty, "-b", "0xDEADBEEF"}, true},
+ {"success_set_int", {"--set", infoMakeProperty, "-i", "2147483647"}, true},
+ {"success_set_ints",
+ {"--set", infoMakeProperty, "-i", "2147483647", "0", "-2147483648"},
+ true},
+ {"success_set_int64",
+ {"--set", infoMakeProperty, "-i64", "-9223372036854775808"},
+ true},
+ {"success_set_int64s",
+ {"--set", infoMakeProperty, "-i64", "-9223372036854775808", "0",
+ "9223372036854775807"},
+ true},
+ {"success_set_float", {"--set", infoMakeProperty, "-f", "1.175494351E-38"}, true},
+ {"success_set_floats",
+ {"--set", infoMakeProperty, "-f", "-3.402823466E+38", "0", "3.402823466E+38"},
+ true},
+ {"success_set_area", {"--set", infoMakeProperty, "-a", "2147483647"}, true},
+ {"fail_no_options", {}, false},
+ {"fail_less_than_4_options", {"--set", infoMakeProperty, "-i"}, false},
+ {"fail_unknown_options", {"--set", infoMakeProperty, "-s", kCarMake, "-abcd"}, false},
+ {"fail_invalid_property", {"--set", "not valid", "-s", kCarMake}, false},
+ {"fail_duplicate_string",
+ {"--set", infoMakeProperty, "-s", kCarMake, "-s", kCarMake},
+ false},
+ {"fail_multiple_strings", {"--set", infoMakeProperty, "-s", kCarMake, kCarMake}, false},
+ {"fail_no_string_value", {"--set", infoMakeProperty, "-s", "-a", "1234"}, false},
+ {"fail_duplicate_bytes",
+ {"--set", infoMakeProperty, "-b", "0xdeadbeef", "-b", "0xdeadbeef"},
+ false},
+ {"fail_multiple_bytes",
+ {"--set", infoMakeProperty, "-b", "0xdeadbeef", "0xdeadbeef"},
+ false},
+ {"fail_invalid_bytes", {"--set", infoMakeProperty, "-b", "0xgood"}, false},
+ {"fail_invalid_bytes_no_prefix", {"--set", infoMakeProperty, "-b", "deadbeef"}, false},
+ {"fail_invalid_int", {"--set", infoMakeProperty, "-i", "abc"}, false},
+ {"fail_int_out_of_range", {"--set", infoMakeProperty, "-i", "2147483648"}, false},
+ {"fail_no_int_value", {"--set", infoMakeProperty, "-i", "-s", kCarMake}, false},
+ {"fail_invalid_int64", {"--set", infoMakeProperty, "-i64", "abc"}, false},
+ {"fail_int64_out_of_range",
+ {"--set", infoMakeProperty, "-i64", "-9223372036854775809"},
+ false},
+ {"fail_no_int64_value", {"--set", infoMakeProperty, "-i64", "-s", kCarMake}, false},
+ {"fail_invalid_float", {"--set", infoMakeProperty, "-f", "abc"}, false},
+ {"fail_float_out_of_range",
+ {"--set", infoMakeProperty, "-f", "-3.402823466E+39"},
+ false},
+ {"fail_no_float_value", {"--set", infoMakeProperty, "-f", "-s", kCarMake}, false},
+ {"fail_multiple_areas", {"--set", infoMakeProperty, "-a", "2147483648", "0"}, false},
+ {"fail_invalid_area", {"--set", infoMakeProperty, "-a", "abc"}, false},
+ {"fail_area_out_of_range", {"--set", infoMakeProperty, "-a", "2147483648"}, false},
+ {"fail_no_area_value", {"--set", infoMakeProperty, "-a", "-s", kCarMake}, false},
+ };
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ VehicleHalManagerSetPropTests, VehicleHalManagerSetPropTest,
+ testing::ValuesIn(GenSetPropParams()),
+ [](const testing::TestParamInfo<VehicleHalManagerSetPropTest::ParamType>& info) {
+ return info.param.test_name;
+ });
+
+TEST_F(VehicleHalManagerTest, SetComplexPropTest) {
+ char infoMakeProperty[100] = {};
+ snprintf(infoMakeProperty, sizeof(infoMakeProperty), "%d", toInt(VehicleProperty::INFO_MAKE));
+ VehicleHalManagerTestHelper helper(manager.get());
+ ASSERT_TRUE(helper.cmdSetOneProperty(
+ STDERR_FILENO, {"--set", infoMakeProperty, "-s", kCarMake,
+ "-b", "0xdeadbeef", "-i", "2147483647",
+ "0", "-2147483648", "-i64", "-9223372036854775808",
+ "0", "9223372036854775807", "-f", "-3.402823466E+38",
+ "0", "3.402823466E+38", "-a", "123"}));
+ StatusCode status = StatusCode::OK;
+ VehiclePropValue requestProp;
+ requestProp.prop = toInt(VehicleProperty::INFO_MAKE);
+ requestProp.areaId = 123;
+ auto value = hal->get(requestProp, &status);
+ ASSERT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(value->prop, toInt(VehicleProperty::INFO_MAKE));
+ ASSERT_EQ(value->areaId, 123);
+ ASSERT_STREQ(kCarMake, value->value.stringValue.c_str());
+ uint8_t bytes[] = {0xde, 0xad, 0xbe, 0xef};
+ ASSERT_FALSE(memcmp(bytes, value->value.bytes.data(), sizeof(bytes)));
+ ASSERT_EQ(3u, value->value.int32Values.size());
+ ASSERT_EQ(2147483647, value->value.int32Values[0]);
+ ASSERT_EQ(0, value->value.int32Values[1]);
+ ASSERT_EQ(-2147483648, value->value.int32Values[2]);
+ ASSERT_EQ(3u, value->value.int64Values.size());
+ // -9223372036854775808 is not a valid literal since '-' and '9223372036854775808' would be two
+ // tokens and the later does not fit in unsigned long long.
+ ASSERT_EQ(-9223372036854775807 - 1, value->value.int64Values[0]);
+ ASSERT_EQ(0, value->value.int64Values[1]);
+ ASSERT_EQ(9223372036854775807, value->value.int64Values[2]);
+ ASSERT_EQ(3u, value->value.floatValues.size());
+ ASSERT_EQ(-3.402823466E+38f, value->value.floatValues[0]);
+ ASSERT_EQ(0.0f, value->value.floatValues[1]);
+ ASSERT_EQ(3.402823466E+38f, value->value.floatValues[2]);
+}
+
} // namespace anonymous
} // namespace V2_0
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
index 866776e..4b4713d 100644
--- a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
@@ -39,9 +39,7 @@
ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession(
const std::shared_ptr<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
- const std::vector<LatencyMode>& latency_modes,
- DataMQDesc* _aidl_return) {
- latency_modes_ = latency_modes;
+ const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
@@ -62,8 +60,8 @@
ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
DataMQDesc* _aidl_return) {
*_aidl_return = DataMQDesc();
- BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
- nullptr, *audio_config_);
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
return ndk::ScopedAStatus::ok();
}
@@ -71,4 +69,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
index d2f58f3..59df3a9 100644
--- a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
@@ -62,9 +62,7 @@
ndk::ScopedAStatus A2dpSoftwareAudioProvider::startSession(
const std::shared_ptr<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
- const std::vector<LatencyMode>& latency_modes,
- DataMQDesc* _aidl_return) {
- latency_modes_ = latency_modes;
+ const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
@@ -92,8 +90,8 @@
}
*_aidl_return = data_mq_->dupeDesc();
auto desc = data_mq_->dupeDesc();
- BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
- &desc, *audio_config_);
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
return ndk::ScopedAStatus::ok();
}
@@ -101,4 +99,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
index 75794e8..a9f830a 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -68,4 +68,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
index c754849..e8b01ac 100644
--- a/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
@@ -57,9 +57,7 @@
ndk::ScopedAStatus HearingAidAudioProvider::startSession(
const std::shared_ptr<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
- const std::vector<LatencyMode>& latency_modes,
- DataMQDesc* _aidl_return) {
- latency_modes_ = latency_modes;
+ const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
@@ -86,8 +84,8 @@
}
*_aidl_return = data_mq_->dupeDesc();
auto desc = data_mq_->dupeDesc();
- BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
- &desc, *audio_config_);
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
return ndk::ScopedAStatus::ok();
}
@@ -95,4 +93,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 1a3c658..0e22e44 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -54,9 +54,7 @@
ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
const std::shared_ptr<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
- const std::vector<LatencyMode>& latency_modes,
- DataMQDesc* _aidl_return) {
- latency_modes_ = latency_modes;
+ const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
@@ -79,8 +77,8 @@
ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
DataMQDesc* _aidl_return) {
- BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
- nullptr, *audio_config_);
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
*_aidl_return = DataMQDesc();
return ndk::ScopedAStatus::ok();
}
@@ -89,4 +87,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
index 1f64b43..911c928 100644
--- a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
@@ -70,9 +70,7 @@
ndk::ScopedAStatus LeAudioSoftwareAudioProvider::startSession(
const std::shared_ptr<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
- const std::vector<LatencyMode>& latency_modes,
- DataMQDesc* _aidl_return) {
- latency_modes_ = latency_modes;
+ const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
@@ -134,8 +132,8 @@
}
*_aidl_return = data_mq_->dupeDesc();
auto desc = data_mq_->dupeDesc();
- BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
- &desc, *audio_config_);
+ BluetoothAudioSessionReport::OnSessionStarted(
+ session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
return ndk::ScopedAStatus::ok();
}
@@ -143,4 +141,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index e700e7e..cdee520 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -46,7 +46,8 @@
void BluetoothAudioSession::OnSessionStarted(
const std::shared_ptr<IBluetoothAudioPort> stack_iface,
- const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
+ const DataMQDesc* mq_desc, const AudioConfiguration& audio_config,
+ const std::vector<LatencyMode>& latency_modes) {
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (stack_iface == nullptr) {
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
@@ -61,6 +62,7 @@
audio_config_ = nullptr;
} else {
stack_iface_ = stack_iface;
+ latency_modes_ = latency_modes;
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
<< ", AudioConfiguration=" << audio_config.toString();
ReportSessionStatus();
@@ -191,14 +193,14 @@
*
***/
-bool BluetoothAudioSession::StartStream() {
+bool BluetoothAudioSession::StartStream(bool is_low_latency) {
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
<< " has NO session";
return false;
}
- auto hal_retval = stack_iface_->startStream(false);
+ auto hal_retval = stack_iface_->startStream(is_low_latency);
if (!hal_retval.isOk()) {
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
<< toString(session_type_) << " failed";
@@ -418,6 +420,7 @@
void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
std::lock_guard<std::recursive_mutex> guard(mutex_);
+ low_latency_allowed_ = allowed;
if (observers_.empty()) {
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
<< " has NO port state observer";
@@ -428,7 +431,9 @@
std::shared_ptr<PortStatusCallbacks> callback = observer.second;
LOG(INFO) << __func__
<< " - allowed=" << (allowed ? " allowed" : " disallowed");
- callback->low_latency_mode_allowed_cb_(cookie, allowed);
+ if (callback->low_latency_mode_allowed_cb_ != nullptr) {
+ callback->low_latency_mode_allowed_cb_(cookie, allowed);
+ }
}
}
@@ -530,7 +535,25 @@
}
}
-void BluetoothAudioSession::SetLatencyMode(LatencyMode latency_mode) {
+std::vector<LatencyMode> BluetoothAudioSession::GetSupportedLatencyModes() {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return std::vector<LatencyMode>();
+ }
+ if (low_latency_allowed_) return latency_modes_;
+ std::vector<LatencyMode> modes;
+ for (LatencyMode mode : latency_modes_) {
+ if (mode == LatencyMode::LOW_LATENCY)
+ // ignore those low latency mode if Bluetooth stack doesn't allow
+ continue;
+ modes.push_back(mode);
+ }
+ return modes;
+}
+
+void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (!IsSessionReady()) {
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
index 6e390cc..5bf17bd 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -27,6 +27,7 @@
#include <mutex>
#include <unordered_map>
+#include <vector>
namespace aidl {
namespace android {
@@ -120,7 +121,8 @@
***/
void OnSessionStarted(const std::shared_ptr<IBluetoothAudioPort> stack_iface,
const DataMQDesc* mq_desc,
- const AudioConfiguration& audio_config);
+ const AudioConfiguration& audio_config,
+ const std::vector<LatencyMode>& latency_modes);
/***
* The report function is used to report that the Bluetooth stack has ended
@@ -175,13 +177,15 @@
* Those control functions are for the bluetooth_audio module to start,
* suspend, stop stream, to check position, and to update metadata.
***/
- bool StartStream();
+ bool StartStream(bool low_latency);
bool SuspendStream();
void StopStream();
bool GetPresentationPosition(PresentationPosition& presentation_position);
void UpdateSourceMetadata(const struct source_metadata& source_metadata);
void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
- void SetLatencyMode(LatencyMode latency_mode);
+
+ std::vector<LatencyMode> GetSupportedLatencyModes();
+ void SetLatencyMode(const LatencyMode& latency_mode);
// The control function writes stream to FMQ
size_t OutWritePcmData(const void* buffer, size_t bytes);
@@ -202,6 +206,8 @@
std::unique_ptr<DataMQ> data_mq_;
// audio data configuration for both software and offloading
std::unique_ptr<AudioConfiguration> audio_config_;
+ std::vector<LatencyMode> latency_modes_;
+ bool low_latency_allowed_ = true;
// saving those registered bluetooth_audio's callbacks
std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
@@ -234,4 +240,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
index 451a31f..5b838b0 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -98,11 +98,12 @@
stop
* stream, to check position, and to update metadata.
***/
- static bool StartStream(const SessionType& session_type) {
+ static bool StartStream(const SessionType& session_type,
+ bool low_latency = false) {
std::shared_ptr<BluetoothAudioSession> session_ptr =
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
if (session_ptr != nullptr) {
- return session_ptr->StartStream();
+ return session_ptr->StartStream(low_latency);
}
return false;
}
@@ -154,6 +155,25 @@
}
}
+ static std::vector<LatencyMode> GetSupportedLatencyModes(
+ const SessionType& session_type) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->GetSupportedLatencyModes();
+ }
+ return std::vector<LatencyMode>();
+ }
+
+ static void SetLatencyMode(const SessionType& session_type,
+ const LatencyMode& latency_mode) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ session_ptr->SetLatencyMode(latency_mode);
+ }
+ }
+
/***
* The control API writes stream to FMQ
***/
@@ -185,4 +205,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
index 03776b5..0350259 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
@@ -33,11 +33,13 @@
static void OnSessionStarted(
const SessionType& session_type,
const std::shared_ptr<IBluetoothAudioPort> host_iface,
- const DataMQDesc* data_mq, const AudioConfiguration& audio_config) {
+ const DataMQDesc* data_mq, const AudioConfiguration& audio_config,
+ const std::vector<LatencyMode>& latency_modes) {
std::shared_ptr<BluetoothAudioSession> session_ptr =
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
if (session_ptr != nullptr) {
- session_ptr->OnSessionStarted(host_iface, data_mq, audio_config);
+ session_ptr->OnSessionStarted(host_iface, data_mq, audio_config,
+ latency_modes);
}
}
@@ -96,4 +98,4 @@
} // namespace bluetooth
} // namespace hardware
} // namespace android
-} // namespace aidl
\ No newline at end of file
+} // namespace aidl
diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp
index 870c944..38eeb15 100644
--- a/broadcastradio/2.0/default/Android.bp
+++ b/broadcastradio/2.0/default/Android.bp
@@ -25,6 +25,9 @@
cc_binary {
name: "android.hardware.broadcastradio@2.0-service",
+ vintf_fragments: [
+ "android.hardware.broadcastradio@2.0-service.xml",
+ ],
init_rc: ["android.hardware.broadcastradio@2.0-service.rc"],
vendor: true,
relative_install_path: "hw",
@@ -41,7 +44,7 @@
"TunerSession.cpp",
"VirtualProgram.cpp",
"VirtualRadio.cpp",
- "service.cpp"
+ "service.cpp",
],
static_libs: [
"android.hardware.broadcastradio@common-utils-2x-lib",
diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml
new file mode 100644
index 0000000..97f2e4d
--- /dev/null
+++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.broadcastradio</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>IBroadcastRadio</name>
+ <instance>amfm</instance>
+ <instance>dab</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/camera/metadata/3.7/types.hal b/camera/metadata/3.7/types.hal
new file mode 100644
index 0000000..a09bdf9
--- /dev/null
+++ b/camera/metadata/3.7/types.hal
@@ -0,0 +1,50 @@
+/*
+ * 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.7;
+
+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;
+
+// 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.6::CameraMetadataTag {
+ /** android.info.deviceStateOrientations [static, int64[], ndk_public]
+ */
+ ANDROID_INFO_DEVICE_STATE_ORIENTATIONS = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_INFO_END_3_4,
+
+ ANDROID_INFO_END_3_7,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 37d2973..052103d 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -882,6 +882,7 @@
camera_metadata* oldSessionParams, camera_metadata* newSessionParams);
void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate);
+ static void overrideRotateAndCrop(::android::hardware::hidl_vec<uint8_t> *settings /*in/out*/);
static bool isDepthOnly(const camera_metadata_t* staticMeta);
@@ -935,6 +936,9 @@
camera_metadata_ro_entry* streamConfigs,
camera_metadata_ro_entry* maxResolutionStreamConfigs,
const camera_metadata_t* staticMetadata);
+ void getPrivacyTestPatternModes(
+ const camera_metadata_t* staticMetadata,
+ std::unordered_set<int32_t>* privacyTestPatternModes/*out*/);
static V3_2::DataspaceFlags getDataspace(PixelFormat format);
@@ -4659,6 +4663,7 @@
settings = req;
});
ASSERT_TRUE(ret.isOk());
+ overrideRotateAndCrop(&settings);
hidl_handle buffer_handle;
StreamBuffer outputBuffer;
@@ -4835,6 +4840,7 @@
settings.setToExternal(
reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (settingsBuffer)),
get_camera_metadata_size(settingsBuffer));
+ overrideRotateAndCrop(&settings);
free_camera_metadata(staticMeta);
ret = session->close();
@@ -4912,6 +4918,7 @@
reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (
filteredSettingsBuffer)),
get_camera_metadata_size(filteredSettingsBuffer));
+ overrideRotateAndCrop(&camSettings[0].settings);
camSettings[0].fmqSettingsSize = 0;
camSettings[0].physicalCameraId = physicalDeviceId;
@@ -5069,6 +5076,7 @@
settings.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(settingsBuffer)),
get_camera_metadata_size(settingsBuffer));
+ overrideRotateAndCrop(&settings);
free_camera_metadata(staticMeta);
ret = session->close();
@@ -5304,6 +5312,7 @@
camera_metadata_t *metaBuffer = requestMeta.release();
requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer),
get_camera_metadata_size(metaBuffer), true);
+ overrideRotateAndCrop(&requestSettings[i]);
requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i],
emptyInputBuffer, {outputBuffers[i]}};
@@ -5530,6 +5539,7 @@
camera_metadata_t *metaBuffer = requestMeta.release();
requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer),
get_camera_metadata_size(metaBuffer), true);
+ overrideRotateAndCrop(&requestSettings[i]);
requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i],
emptyInputBuffer, {outputBuffers[i]}};
@@ -5670,6 +5680,7 @@
settings = req;
});
ASSERT_TRUE(ret.isOk());
+ overrideRotateAndCrop(&settings);
::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
@@ -5754,6 +5765,7 @@
settings = req;
});
ASSERT_TRUE(ret.isOk());
+ overrideRotateAndCrop(&settings);
hidl_handle buffer_handle;
if (useHalBufManager) {
@@ -6617,6 +6629,25 @@
ASSERT_TRUE(-ENOENT == retcode || 0 == retcode);
}
+void CameraHidlTest::getPrivacyTestPatternModes(
+ const camera_metadata_t* staticMetadata,
+ std::unordered_set<int32_t>* privacyTestPatternModes/*out*/) {
+ ASSERT_NE(staticMetadata, nullptr);
+ ASSERT_NE(privacyTestPatternModes, nullptr);
+
+ camera_metadata_ro_entry entry;
+ int retcode = find_camera_metadata_ro_entry(
+ staticMetadata, ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, &entry);
+ ASSERT_TRUE(0 == retcode);
+
+ for (auto i = 0; i < entry.count; i++) {
+ if (entry.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR ||
+ entry.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK) {
+ privacyTestPatternModes->insert(entry.data.i32[i]);
+ }
+ }
+}
+
// Select an appropriate dataspace given a specific pixel format.
V3_2::DataspaceFlags CameraHidlTest::getDataspace(PixelFormat format) {
switch (format) {
@@ -7654,6 +7685,16 @@
ASSERT_TRUE(isUltraHighResCamera && !isMultiCamera);
physicalIds.insert(cameraId);
}
+
+ std::unordered_set<int32_t> physicalRequestKeyIDs;
+ rc = getSupportedKeys(const_cast<camera_metadata_t *>(metadata),
+ ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS, &physicalRequestKeyIDs);
+ ASSERT_TRUE(Status::OK == rc);
+ bool hasTestPatternPhysicalRequestKey = physicalRequestKeyIDs.find(
+ ANDROID_SENSOR_TEST_PATTERN_MODE) != physicalRequestKeyIDs.end();
+ std::unordered_set<int32_t> privacyTestPatternModes;
+ getPrivacyTestPatternModes(metadata, &privacyTestPatternModes);
+
// Map from image format to number of multi-resolution sizes for that format
std::unordered_map<int32_t, size_t> multiResOutputFormatCounterMap;
std::unordered_map<int32_t, size_t> multiResInputFormatCounterMap;
@@ -7675,6 +7716,7 @@
camera_metadata_ro_entry physicalStreamConfigs;
camera_metadata_ro_entry physicalMaxResolutionStreamConfigs;
bool isUltraHighRes = false;
+ std::unordered_set<int32_t> subCameraPrivacyTestPatterns;
if (isPublicId) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> subDevice;
Return<void> ret;
@@ -7705,6 +7747,8 @@
&physicalMultiResStreamConfigs, &physicalStreamConfigs,
&physicalMaxResolutionStreamConfigs, staticMetadata);
isUltraHighRes = isUltraHighResolution(staticMetadata);
+
+ getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns);
});
ASSERT_TRUE(ret.isOk());
} else {
@@ -7731,6 +7775,7 @@
&physicalMultiResStreamConfigs, &physicalStreamConfigs,
&physicalMaxResolutionStreamConfigs, staticMetadata);
isUltraHighRes = isUltraHighResolution(staticMetadata);
+ getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns);
});
ASSERT_TRUE(ret.isOk());
@@ -7747,6 +7792,10 @@
ASSERT_TRUE(ret.isOk());
}
+ if (hasTestPatternPhysicalRequestKey) {
+ ASSERT_TRUE(privacyTestPatternModes == subCameraPrivacyTestPatterns);
+ }
+
if (physicalMultiResStreamConfigs.count > 0) {
ASSERT_GE(deviceVersion, CAMERA_DEVICE_API_VERSION_3_7);
ASSERT_EQ(physicalMultiResStreamConfigs.count % 4, 0);
@@ -7982,6 +8031,20 @@
poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA);
}
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_INFO_DEVICE_STATE_ORIENTATIONS, &entry);
+ if (0 == retcode && entry.count > 0) {
+ ASSERT_TRUE((entry.count % 2) == 0);
+ uint64_t maxPublicState = ((uint64_t) provider::V2_5::DeviceState::FOLDED) << 1;
+ uint64_t vendorStateStart = 1UL << 31; // Reserved for vendor specific states
+ uint64_t stateMask = (1 << vendorStateStart) - 1;
+ stateMask &= ~((1 << maxPublicState) - 1);
+ for (int i = 0; i < entry.count; i += 2){
+ ASSERT_TRUE((entry.data.i64[i] & stateMask) == 0);
+ ASSERT_TRUE((entry.data.i64[i+1] % 90) == 0);
+ }
+ }
+
verifyExtendedSceneModeCharacteristics(metadata);
verifyZoomCharacteristics(metadata);
}
@@ -8742,6 +8805,25 @@
}
}
+void CameraHidlTest::overrideRotateAndCrop(
+ ::android::hardware::hidl_vec<uint8_t> *settings /*in/out*/) {
+ if (settings == nullptr) {
+ return;
+ }
+
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+ requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings->data()));
+ auto entry = requestMeta.find(ANDROID_SCALER_ROTATE_AND_CROP);
+ if ((entry.count > 0) && (entry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO)) {
+ uint8_t disableRotateAndCrop = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
+ requestMeta.update(ANDROID_SCALER_ROTATE_AND_CROP, &disableRotateAndCrop, 1);
+ settings->releaseData();
+ camera_metadata_t *metaBuffer = requestMeta.release();
+ settings->setToExternal(reinterpret_cast<uint8_t *> (metaBuffer),
+ get_camera_metadata_size(metaBuffer), true);
+ }
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, CameraHidlTest,
diff --git a/current.txt b/current.txt
index 7718b98..6a77e19 100644
--- a/current.txt
+++ b/current.txt
@@ -901,6 +901,9 @@
4a087a308608d146b022ebc15633de989f5f4dfe1491a83fa41763290a82e40d android.hardware.automotive.vehicle@2.0::types
70eb14415391f835fb218b43a1e25f5d6495f098f96fa2acaea70985e98e1ce8 android.hardware.automotive.vehicle@2.0::types
+# HALs released in Android SCv2
+77f6fcf3fd0dd3e424d8a0292094ebd17e4c35454bb9abbd3a6cbed1aba70765 android.hardware.camera.metadata@3.7::types
+
# ABI preserving changes to HALs during Android T
62ace52d9c3ff1f60f94118557a2aaf0b953513e59dcd34d5f94ae28d4c7e780 android.hardware.fastboot@1.0::IFastboot
d0fb32f3ddeb9af7115ab32905225ea69b930d2472be8e9610f0cf136c15aefb android.hardware.keymaster@4.0::IKeymasterDevice # b/210424594
diff --git a/health/aidl/default/Health.cpp b/health/aidl/default/Health.cpp
index e1d1982..d41d01a 100644
--- a/health/aidl/default/Health.cpp
+++ b/health/aidl/default/Health.cpp
@@ -130,12 +130,7 @@
ndk::ScopedAStatus Health::getHealthInfo(HealthInfo* out) {
battery_monitor_.updateValues();
- // TODO(b/177269435): BatteryMonitor should store AIDL HealthInfo instead.
- auto health_info_2_1 = battery_monitor_.getHealthInfo_2_1();
- if (!::android::h2a::translate(health_info_2_1, out)) {
- return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
- IHealth::STATUS_UNKNOWN, "Cannot translate HIDL HealthInfo to AIDL");
- }
+ *out = battery_monitor_.getHealthInfo();
// Fill in storage infos; these aren't retrieved by BatteryMonitor.
if (auto res = getStorageInfo(&out->storageInfos); !res.isOk()) {
diff --git a/keymaster/3.0/vts/OWNERS b/keymaster/3.0/vts/OWNERS
index 376c12b..846bb84 100644
--- a/keymaster/3.0/vts/OWNERS
+++ b/keymaster/3.0/vts/OWNERS
@@ -1,3 +1,4 @@
+drysdale@google.com
jdanis@google.com
swillden@google.com
yim@google.com
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
index abfb2e0..0d6fa6c 100644
--- a/keymaster/4.0/vts/OWNERS
+++ b/keymaster/4.0/vts/OWNERS
@@ -1,3 +1,4 @@
+drysdale@google.com
jbires@google.com
jdanis@google.com
swillden@google.com
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index d0ad433..315a4bd 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -443,6 +443,101 @@
AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
}
+void KeymasterHidlTest::CheckAesIncrementalEncryptOperation(BlockMode block_mode,
+ int message_size) {
+ auto builder = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(block_mode)
+ .Padding(PaddingMode::NONE);
+ if (block_mode == BlockMode::GCM) {
+ builder.Authorization(TAG_MIN_MAC_LENGTH, 128);
+ }
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(builder));
+
+ for (int increment = 1; increment <= message_size; ++increment) {
+ string message(message_size, 'a');
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+ string ciphertext;
+ size_t input_consumed;
+ string to_send;
+ for (size_t i = 0; i < message.size(); i += increment) {
+ to_send.append(message.substr(i, increment));
+ EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+ EXPECT_EQ(to_send.length(), input_consumed);
+ to_send = to_send.substr(input_consumed);
+ EXPECT_EQ(0U, to_send.length());
+
+ switch (block_mode) {
+ case BlockMode::ECB:
+ case BlockMode::CBC:
+ // Implementations must take as many blocks as possible, leaving less than
+ // a block.
+ EXPECT_LE(to_send.length(), 16U);
+ break;
+ case BlockMode::GCM:
+ case BlockMode::CTR:
+ // Implementations must always take all the data.
+ EXPECT_EQ(0U, to_send.length());
+ break;
+ }
+ }
+ EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+ switch (block_mode) {
+ case BlockMode::GCM:
+ EXPECT_EQ(message.size() + 16, ciphertext.size());
+ break;
+ case BlockMode::CTR:
+ EXPECT_EQ(message.size(), ciphertext.size());
+ break;
+ case BlockMode::CBC:
+ case BlockMode::ECB:
+ EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+ break;
+ }
+
+ auto iv = output_params.GetTagValue(TAG_NONCE);
+ switch (block_mode) {
+ case BlockMode::CBC:
+ case BlockMode::GCM:
+ case BlockMode::CTR:
+ ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+ EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+ params.push_back(TAG_NONCE, iv.value());
+ break;
+
+ case BlockMode::ECB:
+ EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+ break;
+ }
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+ << "Decrypt begin() failed for block mode " << block_mode;
+
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment) {
+ to_send.append(ciphertext.substr(i, increment));
+ EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+ to_send = to_send.substr(input_consumed);
+ }
+ ErrorCode error = Finish(to_send, &plaintext);
+ ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+ << " and increment " << increment;
+ if (error == ErrorCode::OK) {
+ ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode " << block_mode
+ << " and increment " << increment;
+ }
+ }
+}
+
void KeymasterHidlTest::CheckHmacTestVector(const string& key, const string& message, Digest digest,
const string& expected_mac) {
SCOPED_TRACE("CheckHmacTestVector");
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 2ca7ea7..ad30aa7 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -166,6 +166,8 @@
string MacMessage(const string& message, Digest digest, size_t mac_length);
+ void CheckAesIncrementalEncryptOperation(BlockMode block_mode, int message_size);
+
void CheckHmacTestVector(const string& key, const string& message, Digest digest,
const string& expected_mac);
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 2ff33b0..14c756d 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -2932,105 +2932,39 @@
}
/*
- * EncryptionOperationsTest.AesIncremental
+ * EncryptionOperationsTest.AesEcbIncremental
*
- * Verifies that AES works, all modes, when provided data in various size increments.
+ * Verifies that AES works for ECB block mode, when provided data in various size increments.
*/
-TEST_P(EncryptionOperationsTest, AesIncremental) {
- auto block_modes = {
- BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
- };
+TEST_P(EncryptionOperationsTest, AesEcbIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::ECB, 240);
+}
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .AesEncryptionKey(128)
- .BlockMode(block_modes)
- .Padding(PaddingMode::NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+/*
+ * EncryptionOperationsTest.AesCbcIncremental
+ *
+ * Verifies that AES works for CBC block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::CBC, 240);
+}
- for (int increment = 1; increment <= 240; ++increment) {
- for (auto block_mode : block_modes) {
- string message(240, 'a');
- auto params = AuthorizationSetBuilder()
- .BlockMode(block_mode)
- .Padding(PaddingMode::NONE)
- .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+/*
+ * EncryptionOperationsTest.AesCtrIncremental
+ *
+ * Verifies that AES works for CTR block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::CTR, 240);
+}
- AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
-
- string ciphertext;
- size_t input_consumed;
- string to_send;
- for (size_t i = 0; i < message.size(); i += increment) {
- to_send.append(message.substr(i, increment));
- EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
- EXPECT_EQ(to_send.length(), input_consumed);
- to_send = to_send.substr(input_consumed);
- EXPECT_EQ(0U, to_send.length());
-
- switch (block_mode) {
- case BlockMode::ECB:
- case BlockMode::CBC:
- // Implementations must take as many blocks as possible, leaving less than
- // a block.
- EXPECT_LE(to_send.length(), 16U);
- break;
- case BlockMode::GCM:
- case BlockMode::CTR:
- // Implementations must always take all the data.
- EXPECT_EQ(0U, to_send.length());
- break;
- }
- }
- EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
-
- switch (block_mode) {
- case BlockMode::GCM:
- EXPECT_EQ(message.size() + 16, ciphertext.size());
- break;
- case BlockMode::CTR:
- EXPECT_EQ(message.size(), ciphertext.size());
- break;
- case BlockMode::CBC:
- case BlockMode::ECB:
- EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
- break;
- }
-
- auto iv = output_params.GetTagValue(TAG_NONCE);
- switch (block_mode) {
- case BlockMode::CBC:
- case BlockMode::GCM:
- case BlockMode::CTR:
- ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
- EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
- params.push_back(TAG_NONCE, iv.value());
- break;
-
- case BlockMode::ECB:
- EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
- break;
- }
-
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
- << "Decrypt begin() failed for block mode " << block_mode;
-
- string plaintext;
- for (size_t i = 0; i < ciphertext.size(); i += increment) {
- to_send.append(ciphertext.substr(i, increment));
- EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
- to_send = to_send.substr(input_consumed);
- }
- ErrorCode error = Finish(to_send, &plaintext);
- ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
- << " and increment " << increment;
- if (error == ErrorCode::OK) {
- ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
- << block_mode << " and increment " << increment;
- }
- }
- }
+/*
+ * EncryptionOperationsTest.AesGcmIncremental
+ *
+ * Verifies that AES works for GCM block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::GCM, 240);
}
struct AesCtrSp80038aTestVector {
diff --git a/keymaster/4.1/vts/OWNERS b/keymaster/4.1/vts/OWNERS
index 2b2ad2a..24ed042 100644
--- a/keymaster/4.1/vts/OWNERS
+++ b/keymaster/4.1/vts/OWNERS
@@ -1,3 +1,4 @@
+drysdale@google.com
jbires@google.com
jdanis@google.com
swillden@google.com
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
index 4c0b328..80ed41d 100644
--- a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
@@ -46,9 +46,6 @@
/**
* Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
*
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
* @param device NNAPI canonical IDevice interface object to be adapted.
* @param executor Type-erased executor to handle executing tasks asynchronously.
* @return AIDL NN HAL IDevice interface object.
@@ -58,9 +55,6 @@
/**
* Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
*
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
* This function uses a default executor, which will execute tasks from a detached thread.
*
* @param device NNAPI canonical IDevice interface object to be adapted.
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
index 6fba4ab..3bd93e0 100644
--- a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
@@ -46,9 +46,6 @@
/**
* Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
*
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
* @param device NNAPI canonical IDevice interface object to be adapted.
* @param executor Type-erased executor to handle executing tasks asynchronously.
* @return HIDL NN HAL IDevice interface object.
@@ -58,9 +55,6 @@
/**
* Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
*
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
* This function uses a default executor, which will execute tasks from a detached thread.
*
* @param device NNAPI canonical IDevice interface object to be adapted.
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
index 9482b0d..01cd4bc 100644
--- a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
@@ -39,7 +39,7 @@
// Class that adapts nn::IPreparedModel to V1_3::IPreparedModel.
class PreparedModel final : public V1_3::IPreparedModel {
public:
- PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor);
+ explicit PreparedModel(nn::SharedPreparedModel preparedModel);
Return<V1_0::ErrorStatus> execute(const V1_0::Request& request,
const sp<V1_0::IExecutionCallback>& callback) override;
@@ -70,7 +70,6 @@
private:
const nn::SharedPreparedModel kPreparedModel;
- const Executor kExecutor;
};
} // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/hidl/src/Device.cpp b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
index 0f44638..305a1b4 100644
--- a/neuralnetworks/utils/adapter/hidl/src/Device.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
@@ -62,11 +62,11 @@
using PrepareModelResult = nn::GeneralResult<nn::SharedPreparedModel>;
-sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel, Executor executor) {
+sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel) {
if (preparedModel == nullptr) {
return nullptr;
}
- return sp<PreparedModel>::make(std::move(preparedModel), std::move(executor));
+ return sp<PreparedModel>::make(std::move(preparedModel));
}
void notify(V1_0::IPreparedModelCallback* callback, nn::ErrorStatus status,
@@ -105,14 +105,14 @@
}
template <typename CallbackType>
-void notify(CallbackType* callback, PrepareModelResult result, Executor executor) {
+void notify(CallbackType* callback, PrepareModelResult result) {
if (!result.has_value()) {
const auto [message, status] = std::move(result).error();
LOG(ERROR) << message;
notify(callback, status, nullptr);
} else {
auto preparedModel = std::move(result).value();
- auto hidlPreparedModel = adaptPreparedModel(std::move(preparedModel), std::move(executor));
+ auto hidlPreparedModel = adaptPreparedModel(std::move(preparedModel));
notify(callback, nn::ErrorStatus::NONE, std::move(hidlPreparedModel));
}
}
@@ -133,10 +133,10 @@
auto nnModel = NN_TRY(convertInput(model));
- Task task = [device, nnModel = std::move(nnModel), executor, callback] {
+ Task task = [device, nnModel = std::move(nnModel), callback] {
auto result = device->prepareModel(nnModel, nn::ExecutionPreference::DEFAULT,
nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
- notify(callback.get(), std::move(result), executor);
+ notify(callback.get(), std::move(result));
};
executor(std::move(task), {});
@@ -154,10 +154,10 @@
auto nnModel = NN_TRY(convertInput(model));
const auto nnPreference = NN_TRY(convertInput(preference));
- Task task = [device, nnModel = std::move(nnModel), nnPreference, executor, callback] {
+ Task task = [device, nnModel = std::move(nnModel), nnPreference, callback] {
auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {},
{}, {}, {});
- notify(callback.get(), std::move(result), executor);
+ notify(callback.get(), std::move(result));
};
executor(std::move(task), {});
@@ -183,10 +183,10 @@
Task task = [device, nnModel = std::move(nnModel), nnPreference,
nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
- nnToken, executor, callback] {
+ nnToken, callback] {
auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {},
nnModelCache, nnDataCache, nnToken, {}, {});
- notify(callback.get(), std::move(result), executor);
+ notify(callback.get(), std::move(result));
};
executor(std::move(task), {});
@@ -213,10 +213,10 @@
Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
- nnToken, executor, callback] {
+ nnToken, callback] {
auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
nnModelCache, nnDataCache, nnToken, {}, {});
- notify(callback.get(), std::move(result), executor);
+ notify(callback.get(), std::move(result));
};
executor(std::move(task), nnDeadline);
@@ -238,9 +238,9 @@
const auto nnToken = nn::CacheToken(token);
Task task = [device, nnModelCache = std::move(nnModelCache),
- nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+ nnDataCache = std::move(nnDataCache), nnToken, callback] {
auto result = device->prepareModelFromCache({}, nnModelCache, nnDataCache, nnToken);
- notify(callback.get(), std::move(result), executor);
+ notify(callback.get(), std::move(result));
};
executor(std::move(task), {});
@@ -262,9 +262,9 @@
const auto nnToken = nn::CacheToken(token);
auto task = [device, nnDeadline, nnModelCache = std::move(nnModelCache),
- nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+ nnDataCache = std::move(nnDataCache), nnToken, callback] {
auto result = device->prepareModelFromCache(nnDeadline, nnModelCache, nnDataCache, nnToken);
- notify(callback.get(), std::move(result), executor);
+ notify(callback.get(), std::move(result));
};
executor(std::move(task), nnDeadline);
diff --git a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
index c6055a6..3570a74 100644
--- a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
@@ -55,15 +55,6 @@
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)
@@ -144,58 +135,48 @@
}
nn::GeneralResult<void> execute(const nn::SharedPreparedModel& preparedModel,
- const Executor& executor, const V1_0::Request& request,
+ const V1_0::Request& request,
const sp<V1_0::IExecutionCallback>& callback) {
if (callback.get() == nullptr) {
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
}
- auto nnRequest = NN_TRY(convertInput(request));
+ const auto nnRequest = NN_TRY(convertInput(request));
- const std::any resource = preparedModel->getUnderlyingResource();
- if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
- CHECK(*model != nullptr);
- NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+ auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
+
+ if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+ const auto& [message, code, outputShapes] = result.error();
+ return nn::error(code) << message;
}
- Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
- auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
- notify(callback.get(), std::move(result));
- };
- executor(std::move(task), {});
-
+ notify(callback.get(), std::move(result));
return {};
}
nn::GeneralResult<void> execute_1_2(const nn::SharedPreparedModel& preparedModel,
- const Executor& executor, const V1_0::Request& request,
- V1_2::MeasureTiming measure,
+ const V1_0::Request& request, V1_2::MeasureTiming measure,
const sp<V1_2::IExecutionCallback>& callback) {
if (callback.get() == nullptr) {
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
}
- auto nnRequest = NN_TRY(convertInput(request));
+ const auto nnRequest = NN_TRY(convertInput(request));
const auto nnMeasure = NN_TRY(convertInput(measure));
- const std::any resource = preparedModel->getUnderlyingResource();
- if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
- CHECK(*model != nullptr);
- NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+ auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
+
+ if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+ const auto& [message, code, outputShapes] = result.error();
+ return nn::error(code) << message;
}
- Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
- auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
- notify(callback.get(), std::move(result));
- };
- executor(std::move(task), {});
-
+ notify(callback.get(), std::move(result));
return {};
}
nn::GeneralResult<void> execute_1_3(const nn::SharedPreparedModel& preparedModel,
- const Executor& executor, const V1_3::Request& request,
- V1_2::MeasureTiming measure,
+ const V1_3::Request& request, V1_2::MeasureTiming measure,
const V1_3::OptionalTimePoint& deadline,
const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
const sp<V1_3::IExecutionCallback>& callback) {
@@ -203,25 +184,20 @@
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
}
- auto nnRequest = NN_TRY(convertInput(request));
+ 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 std::any resource = preparedModel->getUnderlyingResource();
- if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
- CHECK(*model != nullptr);
- NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+ auto result =
+ preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration, {}, {});
+
+ if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+ const auto& [message, code, outputShapes] = result.error();
+ return nn::error(code) << message;
}
- Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
- nnLoopTimeoutDuration, callback] {
- auto result = preparedModel->execute(nnRequest, nnMeasure, nnDeadline,
- nnLoopTimeoutDuration, {}, {});
- notify(callback.get(), std::move(result));
- };
- executor(std::move(task), nnDeadline);
-
+ notify(callback.get(), std::move(result));
return {};
}
@@ -304,10 +280,9 @@
} // namespace
-PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor)
- : kPreparedModel(std::move(preparedModel)), kExecutor(std::move(executor)) {
+PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel)
+ : kPreparedModel(std::move(preparedModel)) {
CHECK(kPreparedModel != nullptr);
- CHECK(kExecutor != nullptr);
}
nn::SharedPreparedModel PreparedModel::getUnderlyingPreparedModel() const {
@@ -316,7 +291,7 @@
Return<V1_0::ErrorStatus> PreparedModel::execute(const V1_0::Request& request,
const sp<V1_0::IExecutionCallback>& callback) {
- auto result = adapter::execute(kPreparedModel, kExecutor, request, callback);
+ auto result = adapter::execute(kPreparedModel, request, callback);
if (!result.has_value()) {
auto [message, code] = std::move(result).error();
LOG(ERROR) << "adapter::PreparedModel::execute failed with " << code << ": " << message;
@@ -329,7 +304,7 @@
Return<V1_0::ErrorStatus> PreparedModel::execute_1_2(const V1_0::Request& request,
V1_2::MeasureTiming measure,
const sp<V1_2::IExecutionCallback>& callback) {
- auto result = adapter::execute_1_2(kPreparedModel, kExecutor, request, measure, callback);
+ auto result = adapter::execute_1_2(kPreparedModel, request, measure, callback);
if (!result.has_value()) {
auto [message, code] = std::move(result).error();
LOG(ERROR) << "adapter::PreparedModel::execute_1_2 failed with " << code << ": " << message;
@@ -344,7 +319,7 @@
const V1_3::OptionalTimePoint& deadline,
const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
const sp<V1_3::IExecutionCallback>& callback) {
- auto result = adapter::execute_1_3(kPreparedModel, kExecutor, request, measure, deadline,
+ auto result = adapter::execute_1_3(kPreparedModel, request, measure, deadline,
loopTimeoutDuration, callback);
if (!result.has_value()) {
auto [message, code] = std::move(result).error();
@@ -405,8 +380,8 @@
cb(V1_2::utils::convert(code).value(), nullptr);
return Void();
}
- auto burstContext = std::move(result).value();
- cb(V1_0::ErrorStatus::NONE, std::move(burstContext));
+ const auto burstContext = std::move(result).value();
+ cb(V1_0::ErrorStatus::NONE, burstContext);
return Void();
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
index 6982d40..980b042 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
@@ -47,4 +47,7 @@
EMERGENCY = 512,
MCX = 1024,
XCAP = 2048,
+ VSIM = 4096,
+ BIP = 8192,
+ ENTERPRISE = 16384,
}
diff --git a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
index e780d8e..ae103fc 100644
--- a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
@@ -73,4 +73,16 @@
* APN type for XCAP
*/
XCAP = 1 << 11,
+ /**
+ * APN type for VSIM.
+ */
+ VSIM = 1 << 12,
+ /**
+ * APN type for BIP.
+ */
+ BIP = 1 << 13,
+ /**
+ * APN type for ENTERPRISE
+ */
+ ENTERPRISE = 1 << 14
}
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
index e5a9345..2ebf1fe 100644
--- a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<permissions>
- <feature name="android.hardware.hardware_keystore" version="100" />
+ <feature name="android.hardware.hardware_keystore" version="200" />
</permissions>
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index ff4036c..c174c02 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -665,6 +665,81 @@
AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
}
+void KeyMintAidlTestBase::CheckAesIncrementalEncryptOperation(BlockMode block_mode,
+ int message_size) {
+ auto builder = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(block_mode)
+ .Padding(PaddingMode::NONE);
+ if (block_mode == BlockMode::GCM) {
+ builder.Authorization(TAG_MIN_MAC_LENGTH, 128);
+ }
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(builder));
+
+ for (int increment = 1; increment <= message_size; ++increment) {
+ string message(message_size, 'a');
+ auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(PaddingMode::NONE);
+ if (block_mode == BlockMode::GCM) {
+ params.Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+ }
+
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+ string ciphertext;
+ string to_send;
+ for (size_t i = 0; i < message.size(); i += increment) {
+ EXPECT_EQ(ErrorCode::OK, Update(message.substr(i, increment), &ciphertext));
+ }
+ EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext))
+ << "Error sending " << to_send << " with block mode " << block_mode;
+
+ switch (block_mode) {
+ case BlockMode::GCM:
+ EXPECT_EQ(message.size() + 16, ciphertext.size());
+ break;
+ case BlockMode::CTR:
+ EXPECT_EQ(message.size(), ciphertext.size());
+ break;
+ case BlockMode::CBC:
+ case BlockMode::ECB:
+ EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+ break;
+ }
+
+ auto iv = output_params.GetTagValue(TAG_NONCE);
+ switch (block_mode) {
+ case BlockMode::CBC:
+ case BlockMode::GCM:
+ case BlockMode::CTR:
+ ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
+ EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
+ params.push_back(TAG_NONCE, iv->get());
+ break;
+
+ case BlockMode::ECB:
+ EXPECT_FALSE(iv) << "ECB mode should not generate IV";
+ break;
+ }
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+ << "Decrypt begin() failed for block mode " << block_mode;
+
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment) {
+ EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
+ }
+ ErrorCode error = Finish(to_send, &plaintext);
+ ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+ << " and increment " << increment;
+ if (error == ErrorCode::OK) {
+ ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode " << block_mode
+ << " and increment " << increment;
+ }
+ }
+}
+
void KeyMintAidlTestBase::CheckHmacTestVector(const string& key, const string& message,
Digest digest, const string& expected_mac) {
SCOPED_TRACE("CheckHmacTestVector");
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 6fb5bf5..e59443c 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -169,6 +169,8 @@
string MacMessage(const string& message, Digest digest, size_t mac_length);
+ void CheckAesIncrementalEncryptOperation(BlockMode block_mode, int message_size);
+
void CheckHmacTestVector(const string& key, const string& message, Digest digest,
const string& expected_mac);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 767de2b..c734c37 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -5441,89 +5441,39 @@
}
/*
- * EncryptionOperationsTest.AesIncremental
+ * EncryptionOperationsTest.AesEcbIncremental
*
- * Verifies that AES works, all modes, when provided data in various size increments.
+ * Verifies that AES works for ECB block mode, when provided data in various size increments.
*/
-TEST_P(EncryptionOperationsTest, AesIncremental) {
- auto block_modes = {
- BlockMode::ECB,
- BlockMode::CBC,
- BlockMode::CTR,
- BlockMode::GCM,
- };
+TEST_P(EncryptionOperationsTest, AesEcbIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::ECB, 240);
+}
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .AesEncryptionKey(128)
- .BlockMode(block_modes)
- .Padding(PaddingMode::NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+/*
+ * EncryptionOperationsTest.AesCbcIncremental
+ *
+ * Verifies that AES works for CBC block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::CBC, 240);
+}
- for (int increment = 1; increment <= 240; ++increment) {
- for (auto block_mode : block_modes) {
- string message(240, 'a');
- auto params =
- AuthorizationSetBuilder().BlockMode(block_mode).Padding(PaddingMode::NONE);
- if (block_mode == BlockMode::GCM) {
- params.Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
- }
+/*
+ * EncryptionOperationsTest.AesCtrIncremental
+ *
+ * Verifies that AES works for CTR block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::CTR, 240);
+}
- AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
-
- string ciphertext;
- string to_send;
- for (size_t i = 0; i < message.size(); i += increment) {
- EXPECT_EQ(ErrorCode::OK, Update(message.substr(i, increment), &ciphertext));
- }
- EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext))
- << "Error sending " << to_send << " with block mode " << block_mode;
-
- switch (block_mode) {
- case BlockMode::GCM:
- EXPECT_EQ(message.size() + 16, ciphertext.size());
- break;
- case BlockMode::CTR:
- EXPECT_EQ(message.size(), ciphertext.size());
- break;
- case BlockMode::CBC:
- case BlockMode::ECB:
- EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
- break;
- }
-
- auto iv = output_params.GetTagValue(TAG_NONCE);
- switch (block_mode) {
- case BlockMode::CBC:
- case BlockMode::GCM:
- case BlockMode::CTR:
- ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
- EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
- params.push_back(TAG_NONCE, iv->get());
- break;
-
- case BlockMode::ECB:
- EXPECT_FALSE(iv) << "ECB mode should not generate IV";
- break;
- }
-
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
- << "Decrypt begin() failed for block mode " << block_mode;
-
- string plaintext;
- for (size_t i = 0; i < ciphertext.size(); i += increment) {
- EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
- }
- ErrorCode error = Finish(to_send, &plaintext);
- ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
- << " and increment " << increment;
- if (error == ErrorCode::OK) {
- ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
- << block_mode << " and increment " << increment;
- }
- }
- }
+/*
+ * EncryptionOperationsTest.AesGcmIncremental
+ *
+ * Verifies that AES works for GCM block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+ CheckAesIncrementalEncryptOperation(BlockMode::GCM, 240);
}
struct AesCtrSp80038aTestVector {
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index e16a47b..6f13867 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -38,7 +38,7 @@
class SecureElementProvisioningTest : public testing::Test {
protected:
- static void SetupTestSuite() {
+ static void SetUpTestSuite() {
auto params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
for (auto& param : params) {
ASSERT_TRUE(AServiceManager_isDeclared(param.c_str()))
@@ -63,6 +63,9 @@
map<SecurityLevel, shared_ptr<IKeyMintDevice>> SecureElementProvisioningTest::keymints_;
TEST_F(SecureElementProvisioningTest, ValidConfigurations) {
+ if (keymints_.empty()) {
+ GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+ }
// TEE is required
ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
// StrongBox is optional
@@ -70,6 +73,9 @@
}
TEST_F(SecureElementProvisioningTest, TeeOnly) {
+ if (keymints_.empty()) {
+ GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+ }
ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
ASSERT_NE(tee, nullptr);
@@ -105,6 +111,9 @@
}
TEST_F(SecureElementProvisioningTest, TeeDoesNotImplementStrongBoxMethods) {
+ if (keymints_.empty()) {
+ GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+ }
ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
ASSERT_NE(tee, nullptr);
@@ -122,7 +131,10 @@
}
TEST_F(SecureElementProvisioningTest, StrongBoxDoesNotImplementTeeMethods) {
- if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return;
+ if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+ // Need a StrongBox to provision.
+ GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+ }
auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
ASSERT_NE(sb, nullptr);
@@ -135,7 +147,10 @@
}
TEST_F(SecureElementProvisioningTest, UnimplementedTest) {
- if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return; // Need a StrongBox to provision.
+ if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+ // Need a StrongBox to provision.
+ GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+ }
ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
@@ -166,7 +181,10 @@
}
TEST_F(SecureElementProvisioningTest, ChallengeQualityTest) {
- if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return; // Need a StrongBox to provision.
+ if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+ // Need a StrongBox to provision.
+ GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+ }
ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
@@ -186,7 +204,10 @@
}
TEST_F(SecureElementProvisioningTest, ProvisioningTest) {
- if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return; // Need a StrongBox to provision.
+ if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+ // Need a StrongBox to provision.
+ GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+ }
ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
@@ -215,7 +236,10 @@
}
TEST_F(SecureElementProvisioningTest, InvalidProvisioningTest) {
- if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return; // Need a StrongBox to provision.
+ if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+ // Need a StrongBox to provision.
+ GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+ }
ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index e2d75ce..4341aa1 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -185,6 +185,7 @@
provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
}
ASSERT_NE(provisionable_, nullptr);
+ ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
}
static vector<string> build_params() {
@@ -194,6 +195,7 @@
protected:
std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
+ RpcHardwareInfo rpcHardwareInfo;
};
/**
@@ -357,12 +359,11 @@
class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
protected:
CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
- generateTestEekChain(3);
}
void generateTestEekChain(size_t eekLength) {
- auto chain = generateEekChain(eekLength, eekId_);
- EXPECT_TRUE(chain) << chain.message();
+ auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
+ ASSERT_TRUE(chain) << chain.message();
if (chain) testEekChain_ = chain.moveValue();
testEekLength_ = eekLength;
}
@@ -382,6 +383,17 @@
}
}
+ ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey) {
+ if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
+ rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
+ return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
+ senderPubkey->first, false /* senderIsA */);
+ } else {
+ return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
+ senderPubkey->first, false /* senderIsA */);
+ }
+ }
+
void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
const bytevec& keysToSignMac, const ProtectedData& protectedData,
std::vector<BccEntryData>* bccOutput = nullptr) {
@@ -394,9 +406,7 @@
ASSERT_TRUE(senderPubkey) << senderPubkey.message();
EXPECT_EQ(senderPubkey->second, eekId_);
- auto sessionKey =
- x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
- senderPubkey->first, false /* senderIsA */);
+ auto sessionKey = getSessionKey(senderPubkey);
ASSERT_TRUE(sessionKey) << sessionKey.message();
auto protectedDataPayload =
@@ -406,7 +416,8 @@
auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
ASSERT_TRUE(parsedPayload->asArray());
- EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
+ // Strongbox may contain additional certificate chain.
+ EXPECT_LE(parsedPayload->asArray()->size(), 3U);
auto& signedMac = parsedPayload->asArray()->get(0);
auto& bcc = parsedPayload->asArray()->get(1);
@@ -566,6 +577,7 @@
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
+ generateTestEekChain(3);
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
@@ -605,8 +617,8 @@
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- testMode, {} /* keysToSign */, getProdEekChain(), challenge_, &deviceInfo,
- &protectedData, &keysToSignMac);
+ testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
+ challenge_, &deviceInfo, &protectedData, &keysToSignMac);
EXPECT_TRUE(status.isOk());
}
@@ -646,8 +658,8 @@
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- testMode, keysToSign_, getProdEekChain(), challenge_, &deviceInfo, &protectedData,
- &keysToSignMac);
+ testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_,
+ &deviceInfo, &protectedData, &keysToSignMac);
EXPECT_TRUE(status.isOk());
}
@@ -657,11 +669,14 @@
TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
bool testMode = true;
generateKeys(testMode, 1 /* numKeys */);
- MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
+ auto result = corrupt_maced_key(keysToSign_[0]);
+ ASSERT_TRUE(result) << result.moveMessage();
+ MacedPublicKey keyWithCorruptMac = result.moveValue();
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
+ generateTestEekChain(3);
auto status = provisionable_->generateCertificateRequest(
testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
@@ -675,14 +690,16 @@
TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
bool testMode = false;
generateKeys(testMode, 1 /* numKeys */);
- MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
+ auto result = corrupt_maced_key(keysToSign_[0]);
+ ASSERT_TRUE(result) << result.moveMessage();
+ MacedPublicKey keyWithCorruptMac = result.moveValue();
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- testMode, {keyWithCorruptMac}, getProdEekChain(), challenge_, &deviceInfo,
- &protectedData, &keysToSignMac);
+ testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
+ challenge_, &deviceInfo, &protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
@@ -695,7 +712,7 @@
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
- auto prodEekChain = getProdEekChain();
+ auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
ASSERT_NE(parsedChain, nullptr) << parseErr;
ASSERT_NE(parsedChain->asArray(), nullptr);
@@ -726,7 +743,7 @@
// Build an EEK chain that omits the first self-signed cert.
auto truncatedChain = cppbor::Array();
- auto [chain, _, parseErr] = cppbor::parse(getProdEekChain());
+ auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
ASSERT_TRUE(chain);
auto eekChain = chain->asArray();
ASSERT_NE(eekChain, nullptr);
@@ -754,6 +771,7 @@
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
+ generateTestEekChain(3);
auto status = provisionable_->generateCertificateRequest(
true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
@@ -772,6 +790,7 @@
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
+ generateTestEekChain(3);
auto status = provisionable_->generateCertificateRequest(
false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 36969bb..bf2ab02 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -60,11 +60,15 @@
export_include_dirs: [
"include",
],
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
shared_libs: [
"libbase",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
+ "libkeymaster_portable",
"libjsoncpp",
],
}
@@ -76,6 +80,9 @@
"libgmock",
"libgtest_main",
],
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
shared_libs: [
"libbase",
"libcppbor_external",
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index 406b7a9..f3b8608 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -52,6 +52,34 @@
0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2,
0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04};
+// The Google ECDSA P256 root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1
+inline constexpr uint8_t kCoseEncodedEcdsa256RootCert[] = {
+ 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
+ 0x58, 0x20, 0xf7, 0x14, 0x8a, 0xdb, 0x97, 0xf4, 0xcc, 0x53, 0xef, 0xd2, 0x64, 0x11, 0xc4, 0xe3,
+ 0x75, 0x1f, 0x66, 0x1f, 0xa4, 0x71, 0x0c, 0x6c, 0xcf, 0xfa, 0x09, 0x46, 0x80, 0x74, 0x87, 0x54,
+ 0xf2, 0xad, 0x22, 0x58, 0x20, 0x5e, 0x7f, 0x5b, 0xf6, 0xec, 0xe4, 0xf6, 0x19, 0xcc, 0xff, 0x13,
+ 0x37, 0xfd, 0x0f, 0xa1, 0xc8, 0x93, 0xdb, 0x18, 0x06, 0x76, 0xc4, 0x5d, 0xe6, 0xd7, 0x6a, 0x77,
+ 0x86, 0xc3, 0x2d, 0xaf, 0x8f, 0x58, 0x40, 0x2f, 0x97, 0x8e, 0x42, 0xfb, 0xbe, 0x07, 0x2d, 0x95,
+ 0x47, 0x85, 0x47, 0x93, 0x40, 0xb0, 0x1f, 0xd4, 0x9b, 0x47, 0xa4, 0xc4, 0x44, 0xa9, 0xf2, 0xa1,
+ 0x07, 0x87, 0x10, 0xc7, 0x9f, 0xcb, 0x11, 0xf4, 0xbf, 0x9f, 0xe8, 0x3b, 0xe0, 0xe7, 0x34, 0x4c,
+ 0x15, 0xfc, 0x7b, 0xc3, 0x7e, 0x33, 0x05, 0xf4, 0xd1, 0x34, 0x3c, 0xed, 0x02, 0x04, 0x60, 0x7a,
+ 0x15, 0xe0, 0x79, 0xd3, 0x8a, 0xff, 0x24};
+
+// The Google ECDSA P256 Endpoint Encryption Key certificate, encoded as COSE_Sign1
+inline constexpr uint8_t kCoseEncodedEcdsa256GeekCert[] = {
+ 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x71, 0xa6, 0x01, 0x02, 0x02, 0x58, 0x20, 0x35, 0x73,
+ 0xb7, 0x3f, 0xa0, 0x8a, 0x80, 0x89, 0xb1, 0x26, 0x67, 0xe9, 0xcb, 0x7c, 0x75, 0xa1, 0xaf, 0x02,
+ 0x61, 0xfc, 0x6e, 0x65, 0x03, 0x91, 0x3b, 0xd3, 0x4b, 0x7d, 0x14, 0x94, 0x3e, 0x46, 0x03, 0x38,
+ 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0xe0, 0x41, 0xcf, 0x2f, 0x0f, 0x34, 0x0f, 0x1c, 0x33, 0x2c,
+ 0x41, 0xb0, 0xcf, 0xd7, 0x0c, 0x30, 0x55, 0x35, 0xd2, 0x1e, 0x6a, 0x47, 0x13, 0x4b, 0x2e, 0xd1,
+ 0x48, 0x96, 0x7e, 0x24, 0x9c, 0x68, 0x22, 0x58, 0x20, 0x1f, 0xce, 0x45, 0xc5, 0xfb, 0x61, 0xba,
+ 0x81, 0x21, 0xf9, 0xe5, 0x05, 0x9b, 0x9b, 0x39, 0x0e, 0x76, 0x86, 0x86, 0x47, 0xb8, 0x1e, 0x2f,
+ 0x45, 0xf1, 0xce, 0xaf, 0xda, 0x3f, 0x80, 0x68, 0xdb, 0x58, 0x40, 0x8c, 0xb3, 0xba, 0x7e, 0x20,
+ 0x3e, 0x32, 0xb0, 0x68, 0xdf, 0x60, 0xd1, 0x1d, 0x7d, 0xf0, 0xac, 0x38, 0x8e, 0x51, 0xbc, 0xff,
+ 0x6c, 0xe1, 0x67, 0x3b, 0x4a, 0x79, 0xbc, 0x56, 0x78, 0xb3, 0x99, 0xd8, 0x7c, 0x8a, 0x07, 0xd8,
+ 0xda, 0xb5, 0xb5, 0x7f, 0x71, 0xf4, 0xd8, 0x6b, 0xdf, 0x33, 0x27, 0x34, 0x7b, 0x65, 0xd1, 0x2a,
+ 0xeb, 0x86, 0x99, 0x98, 0xab, 0x3a, 0xb4, 0x80, 0xaa, 0xbd, 0x50};
+
/**
* Generates random bytes.
*/
@@ -64,15 +92,15 @@
};
/**
- * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the
- * specified length. All keys are generated randomly.
+ * Based on the supportedEekCurve, Generates an X25519/ECDH with the specified eekId
+ * and an Ed25519/ECDSA chain of the specified length. All keys are generated randomly.
*/
-ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
+ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length, const bytevec& eekId);
/**
* Returns the CBOR-encoded, production Google Endpoint Encryption Key chain.
*/
-bytevec getProdEekChain();
+bytevec getProdEekChain(int32_t supportedEekCurve);
struct BccEntryData {
bytevec pubKey;
@@ -96,17 +124,19 @@
};
/**
- * Take a given certificate request and output a JSON blob containing both the
- * build fingerprint and certificate request. This data may be serialized, then
- * later uploaded to the remote provisioning service. The input csr is not
- * validated, only encoded.
+ * Take a given instance name and certificate request, then output a JSON blob
+ * containing the name, build fingerprint and certificate request. This data may
+ * be serialized, then later uploaded to the remote provisioning service. The
+ * input csr is not validated, only encoded.
*
* Output format:
* {
* "build_fingerprint": <string>
* "csr": <base64 CBOR CSR>
+ * "name": <string>
* }
*/
-JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr);
+JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name,
+ const cppbor::Array& csr);
} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 35cb891..0dbea5b 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -17,10 +17,16 @@
#include <iterator>
#include <tuple>
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
#include <android-base/properties.h>
#include <cppbor.h>
#include <json/json.h>
+#include <keymaster/km_openssl/ec_key.h>
+#include <keymaster/km_openssl/ecdsa_operation.h>
+#include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/km_openssl/openssl_utils.h>
#include <openssl/base64.h>
+#include <openssl/evp.h>
#include <openssl/rand.h>
#include <remote_prov/remote_prov_utils.h>
@@ -30,6 +36,166 @@
constexpr uint32_t kBccPayloadSubject = 2;
constexpr int32_t kBccPayloadSubjPubKey = -4670552;
constexpr int32_t kBccPayloadKeyUsage = -4670553;
+constexpr int kP256AffinePointSize = 32;
+
+using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
+using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
+using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
+
+ErrMsgOr<bytevec> ecKeyGetPrivateKey(const EC_KEY* ecKey) {
+ // Extract private key.
+ const BIGNUM* bignum = EC_KEY_get0_private_key(ecKey);
+ if (bignum == nullptr) {
+ return "Error getting bignum from private key";
+ }
+ // Pad with zeros in case the length is lesser than 32.
+ bytevec privKey(32, 0);
+ BN_bn2binpad(bignum, privKey.data(), privKey.size());
+ return privKey;
+}
+
+ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey) {
+ // Extract public key.
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ if (group.get() == nullptr) {
+ return "Error creating EC group by curve name";
+ }
+ const EC_POINT* point = EC_KEY_get0_public_key(ecKey);
+ if (point == nullptr) return "Error getting ecpoint from public key";
+
+ int size =
+ EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
+ if (size == 0) {
+ return "Error generating public key encoding";
+ }
+
+ bytevec publicKey;
+ publicKey.resize(size);
+ EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
+ publicKey.size(), nullptr);
+ return publicKey;
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> getAffineCoordinates(const bytevec& pubKey) {
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ if (group.get() == nullptr) {
+ return "Error creating EC group by curve name";
+ }
+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+ if (EC_POINT_oct2point(group.get(), point.get(), pubKey.data(), pubKey.size(), nullptr) != 1) {
+ return "Error decoding publicKey";
+ }
+ BIGNUM_Ptr x(BN_new());
+ BIGNUM_Ptr y(BN_new());
+ BN_CTX_Ptr ctx(BN_CTX_new());
+ if (!ctx.get()) return "Failed to create BN_CTX instance";
+
+ if (!EC_POINT_get_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(),
+ ctx.get())) {
+ return "Failed to get affine coordinates from ECPoint";
+ }
+ bytevec pubX(kP256AffinePointSize);
+ bytevec pubY(kP256AffinePointSize);
+ if (BN_bn2binpad(x.get(), pubX.data(), kP256AffinePointSize) != kP256AffinePointSize) {
+ return "Error in converting absolute value of x coordinate to big-endian";
+ }
+ if (BN_bn2binpad(y.get(), pubY.data(), kP256AffinePointSize) != kP256AffinePointSize) {
+ return "Error in converting absolute value of y coordinate to big-endian";
+ }
+ return std::make_tuple(std::move(pubX), std::move(pubY));
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateEc256KeyPair() {
+ auto ec_key = EC_KEY_Ptr(EC_KEY_new());
+ if (ec_key.get() == nullptr) {
+ return "Failed to allocate ec key";
+ }
+
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ if (group.get() == nullptr) {
+ return "Error creating EC group by curve name";
+ }
+
+ if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
+ EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
+ return "Error generating key";
+ }
+
+ auto privKey = ecKeyGetPrivateKey(ec_key.get());
+ if (!privKey) return privKey.moveMessage();
+
+ auto pubKey = ecKeyGetPublicKey(ec_key.get());
+ if (!pubKey) return pubKey.moveMessage();
+
+ return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateX25519KeyPair() {
+ /* Generate X25519 key pair */
+ bytevec pubKey(X25519_PUBLIC_VALUE_LEN);
+ bytevec privKey(X25519_PRIVATE_KEY_LEN);
+ X25519_keypair(pubKey.data(), privKey.data());
+ return std::make_tuple(std::move(pubKey), std::move(privKey));
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateED25519KeyPair() {
+ /* Generate ED25519 key pair */
+ bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
+ bytevec privKey(ED25519_PRIVATE_KEY_LEN);
+ ED25519_keypair(pubKey.data(), privKey.data());
+ return std::make_tuple(std::move(pubKey), std::move(privKey));
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateKeyPair(int32_t supportedEekCurve, bool isEek) {
+ switch (supportedEekCurve) {
+ case RpcHardwareInfo::CURVE_25519:
+ if (isEek) {
+ return generateX25519KeyPair();
+ }
+ return generateED25519KeyPair();
+ case RpcHardwareInfo::CURVE_P256:
+ return generateEc256KeyPair();
+ default:
+ return "Unknown EEK Curve.";
+ }
+}
+
+ErrMsgOr<bytevec> constructCoseKey(int32_t supportedEekCurve, const bytevec& eekId,
+ const bytevec& pubKey) {
+ CoseKeyType keyType;
+ CoseKeyAlgorithm algorithm;
+ CoseKeyCurve curve;
+ bytevec pubX;
+ bytevec pubY;
+ switch (supportedEekCurve) {
+ case RpcHardwareInfo::CURVE_25519:
+ keyType = OCTET_KEY_PAIR;
+ algorithm = (eekId.empty()) ? EDDSA : ECDH_ES_HKDF_256;
+ curve = (eekId.empty()) ? ED25519 : cppcose::X25519;
+ pubX = pubKey;
+ break;
+ case RpcHardwareInfo::CURVE_P256: {
+ keyType = EC2;
+ algorithm = (eekId.empty()) ? ES256 : ECDH_ES_HKDF_256;
+ curve = P256;
+ auto affineCoordinates = getAffineCoordinates(pubKey);
+ if (!affineCoordinates) return affineCoordinates.moveMessage();
+ std::tie(pubX, pubY) = affineCoordinates.moveValue();
+ } break;
+ default:
+ return "Unknown EEK Curve.";
+ }
+ cppbor::Map coseKey = cppbor::Map()
+ .add(CoseKey::KEY_TYPE, keyType)
+ .add(CoseKey::ALGORITHM, algorithm)
+ .add(CoseKey::CURVE, curve)
+ .add(CoseKey::PUBKEY_X, pubX);
+
+ if (!pubY.empty()) coseKey.add(CoseKey::PUBKEY_Y, pubY);
+ if (!eekId.empty()) coseKey.add(CoseKey::KEY_ID, eekId);
+
+ return coseKey.canonicalize().encode();
+}
bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
@@ -39,7 +205,17 @@
return retval;
}
-ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
+ErrMsgOr<cppbor::Array> constructCoseSign1(int32_t supportedEekCurve, const bytevec& key,
+ const bytevec& payload, const bytevec& aad) {
+ if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
+ return constructECDSACoseSign1(key, {} /* protectedParams */, payload, aad);
+ } else {
+ return cppcose::constructCoseSign1(key, payload, aad);
+ }
+}
+
+ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length,
+ const bytevec& eekId) {
if (length < 2) {
return "EEK chain must contain at least 2 certs.";
}
@@ -48,59 +224,62 @@
bytevec prev_priv_key;
for (size_t i = 0; i < length - 1; ++i) {
- bytevec pub_key(ED25519_PUBLIC_KEY_LEN);
- bytevec priv_key(ED25519_PRIVATE_KEY_LEN);
-
- ED25519_keypair(pub_key.data(), priv_key.data());
+ auto keyPair = generateKeyPair(supportedEekCurve, false);
+ if (!keyPair) return keyPair.moveMessage();
+ auto [pub_key, priv_key] = keyPair.moveValue();
// The first signing key is self-signed.
if (prev_priv_key.empty()) prev_priv_key = priv_key;
- auto coseSign1 = constructCoseSign1(prev_priv_key,
- cppbor::Map() /* payload CoseKey */
- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
- .add(CoseKey::ALGORITHM, EDDSA)
- .add(CoseKey::CURVE, ED25519)
- .add(CoseKey::PUBKEY_X, pub_key)
- .canonicalize()
- .encode(),
- {} /* AAD */);
+ auto coseKey = constructCoseKey(supportedEekCurve, {}, pub_key);
+ if (!coseKey) return coseKey.moveMessage();
+
+ auto coseSign1 =
+ constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
if (!coseSign1) return coseSign1.moveMessage();
eekChain.add(coseSign1.moveValue());
prev_priv_key = priv_key;
}
+ auto keyPair = generateKeyPair(supportedEekCurve, true);
+ if (!keyPair) return keyPair.moveMessage();
+ auto [pub_key, priv_key] = keyPair.moveValue();
- bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
- bytevec priv_key(X25519_PRIVATE_KEY_LEN);
- X25519_keypair(pub_key.data(), priv_key.data());
+ auto coseKey = constructCoseKey(supportedEekCurve, eekId, pub_key);
+ if (!coseKey) return coseKey.moveMessage();
- auto coseSign1 = constructCoseSign1(prev_priv_key,
- cppbor::Map() /* payload CoseKey */
- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
- .add(CoseKey::KEY_ID, eekId)
- .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
- .add(CoseKey::CURVE, cppcose::X25519)
- .add(CoseKey::PUBKEY_X, pub_key)
- .canonicalize()
- .encode(),
- {} /* AAD */);
+ auto coseSign1 =
+ constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
if (!coseSign1) return coseSign1.moveMessage();
eekChain.add(coseSign1.moveValue());
+ if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
+ // convert ec public key to x and y co-ordinates.
+ auto affineCoordinates = getAffineCoordinates(pub_key);
+ if (!affineCoordinates) return affineCoordinates.moveMessage();
+ auto [pubX, pubY] = affineCoordinates.moveValue();
+ pub_key.clear();
+ pub_key.insert(pub_key.begin(), pubX.begin(), pubX.end());
+ pub_key.insert(pub_key.end(), pubY.begin(), pubY.end());
+ }
+
return EekChain{eekChain.encode(), pub_key, priv_key};
}
-bytevec getProdEekChain() {
- bytevec prodEek;
- prodEek.reserve(1 + sizeof(kCoseEncodedRootCert) + sizeof(kCoseEncodedGeekCert));
-
- // In CBOR encoding, 0x82 indicates an array of two items
- prodEek.push_back(0x82);
- prodEek.insert(prodEek.end(), std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert));
- prodEek.insert(prodEek.end(), std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert));
-
- return prodEek;
+bytevec getProdEekChain(int32_t supportedEekCurve) {
+ cppbor::Array chain;
+ if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
+ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256RootCert),
+ std::end(kCoseEncodedEcdsa256RootCert))));
+ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256GeekCert),
+ std::end(kCoseEncodedEcdsa256GeekCert))));
+ } else {
+ chain.add(cppbor::EncodedItem(
+ bytevec(std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert))));
+ chain.add(cppbor::EncodedItem(
+ bytevec(std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert))));
+ }
+ return chain.encode();
}
ErrMsgOr<bytevec> validatePayloadAndFetchPubKey(const cppbor::Map* payload) {
@@ -139,7 +318,8 @@
}
auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+ if (!algorithm || !algorithm->asInt() ||
+ (algorithm->asInt()->value() != EDDSA && algorithm->asInt()->value() != ES256)) {
return "Unsupported signature algorithm";
}
@@ -152,15 +332,36 @@
}
bool selfSigned = signingCoseKey.empty();
- auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);
- if (!key) return "Bad signing key: " + key.moveMessage();
-
bytevec signatureInput =
- cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
+ cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
- if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
- key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
- return "Signature verification failed";
+ if (algorithm->asInt()->value() == EDDSA) {
+ auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);
+
+ if (!key) return "Bad signing key: " + key.moveMessage();
+
+ if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+ key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+ return "Signature verification failed";
+ }
+ } else { // P256
+ auto key = CoseKey::parseP256(selfSigned ? *serializedKey : signingCoseKey);
+ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
+ key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
+ return "Bad signing key: " + key.moveMessage();
+ }
+ auto publicKey = key->getEcPublicKey();
+ if (!publicKey) return publicKey.moveMessage();
+
+ auto ecdsaDerSignature = ecdsaCoseSignatureToDer(signature->value());
+ if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();
+
+ // convert public key to uncompressed form.
+ publicKey->insert(publicKey->begin(), 0x04);
+
+ if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), *ecdsaDerSignature)) {
+ return "Signature verification failed";
+ }
}
return serializedKey.moveValue();
@@ -207,7 +408,7 @@
return result;
}
-JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr) {
+JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name, const cppbor::Array& csr) {
const std::string kFingerprintProp = "ro.build.fingerprint";
if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
@@ -231,6 +432,7 @@
}
Json::Value json(Json::objectValue);
+ json["name"] = instance_name;
json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
json["csr"] = base64.data(); // Boring writes a NUL-terminated c-string
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index 8697c51..0250cd6 100644
--- a/security/keymint/support/remote_prov_utils_test.cpp
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -14,8 +14,12 @@
* limitations under the License.
*/
+#include "cppbor.h"
+#include "keymaster/cppcose/cppcose.h"
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
#include <android-base/properties.h>
#include <cppbor_parse.h>
+#include <cstdint>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <keymaster/android_keymaster_utils.h>
@@ -23,25 +27,120 @@
#include <keymaster/remote_provisioning_utils.h>
#include <openssl/curve25519.h>
#include <remote_prov/remote_prov_utils.h>
-#include <cstdint>
-#include "cppbor.h"
-#include "keymaster/cppcose/cppcose.h"
namespace aidl::android::hardware::security::keymint::remote_prov {
namespace {
using ::keymaster::KeymasterBlob;
-using ::keymaster::validateAndExtractEekPubAndId;
+using ::keymaster::kStatusFailed;
+using ::keymaster::kStatusInvalidEek;
+using ::keymaster::StatusOr;
using ::testing::ElementsAreArray;
+using byte_view = std::basic_string_view<uint8_t>;
+
+struct KeyInfoEcdsa {
+ CoseKeyCurve curve;
+ byte_view pubKeyX;
+ byte_view pubKeyY;
+
+ bool operator==(const KeyInfoEcdsa& other) const {
+ return curve == other.curve && pubKeyX == other.pubKeyX && pubKeyY == other.pubKeyY;
+ }
+};
+
+// The production root signing key for Google ECDSA P256 Endpoint Encryption Key cert chains.
+inline constexpr uint8_t kEcdsa256GeekRootX[] = {
+ 0xf7, 0x14, 0x8a, 0xdb, 0x97, 0xf4, 0xcc, 0x53, 0xef, 0xd2, 0x64, 0x11, 0xc4, 0xe3, 0x75, 0x1f,
+ 0x66, 0x1f, 0xa4, 0x71, 0x0c, 0x6c, 0xcf, 0xfa, 0x09, 0x46, 0x80, 0x74, 0x87, 0x54, 0xf2, 0xad};
+
+inline constexpr uint8_t kEcdsa256GeekRootY[] = {
+ 0x5e, 0x7f, 0x5b, 0xf6, 0xec, 0xe4, 0xf6, 0x19, 0xcc, 0xff, 0x13, 0x37, 0xfd, 0x0f, 0xa1, 0xc8,
+ 0x93, 0xdb, 0x18, 0x06, 0x76, 0xc4, 0x5d, 0xe6, 0xd7, 0x6a, 0x77, 0x86, 0xc3, 0x2d, 0xaf, 0x8f};
+
+// Hard-coded set of acceptable public COSE_Keys that can act as roots of EEK chains.
+inline constexpr KeyInfoEcdsa kAuthorizedEcdsa256EekRoots[] = {
+ {CoseKeyCurve::P256, byte_view(kEcdsa256GeekRootX, sizeof(kEcdsa256GeekRootX)),
+ byte_view(kEcdsa256GeekRootY, sizeof(kEcdsa256GeekRootY))},
+};
+
+static ErrMsgOr<CoseKey> parseEcdh256(const bytevec& coseKey) {
+ auto key = CoseKey::parse(coseKey, EC2, ECDH_ES_HKDF_256, P256);
+ if (!key) return key;
+
+ auto& pubkey_x = key->getMap().get(cppcose::CoseKey::PUBKEY_X);
+ auto& pubkey_y = key->getMap().get(cppcose::CoseKey::PUBKEY_Y);
+ if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
+ pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
+ return "Invalid P256 public key";
+ }
+
+ return key;
+}
+
+StatusOr<std::tuple<std::vector<uint8_t> /* EEK pubX */, std::vector<uint8_t> /* EEK pubY */,
+ std::vector<uint8_t> /* EEK ID */>>
+validateAndExtractEcdsa256EekPubAndId(bool testMode,
+ const KeymasterBlob& endpointEncryptionCertChain) {
+ auto [item, newPos, errMsg] =
+ cppbor::parse(endpointEncryptionCertChain.begin(), endpointEncryptionCertChain.end());
+ if (!item || !item->asArray()) {
+ return kStatusFailed;
+ }
+ const cppbor::Array* certArr = item->asArray();
+ std::vector<uint8_t> lastPubKey;
+ for (size_t i = 0; i < certArr->size(); ++i) {
+ auto cosePubKey =
+ verifyAndParseCoseSign1(certArr->get(i)->asArray(), lastPubKey, {} /* AAD */);
+ if (!cosePubKey) {
+ return kStatusInvalidEek;
+ }
+ lastPubKey = *std::move(cosePubKey);
+
+ // In prod mode the first pubkey should match a well-known Google public key.
+ if (!testMode && i == 0) {
+ auto parsedPubKey = CoseKey::parse(lastPubKey);
+ if (!parsedPubKey) {
+ return kStatusFailed;
+ }
+ auto curve = parsedPubKey->getIntValue(CoseKey::CURVE);
+ if (!curve) {
+ return kStatusInvalidEek;
+ }
+ auto rawPubX = parsedPubKey->getBstrValue(CoseKey::PUBKEY_X);
+ if (!rawPubX) {
+ return kStatusInvalidEek;
+ }
+ auto rawPubY = parsedPubKey->getBstrValue(CoseKey::PUBKEY_Y);
+ if (!rawPubY) {
+ return kStatusInvalidEek;
+ }
+ KeyInfoEcdsa matcher = {static_cast<CoseKeyCurve>(*curve),
+ byte_view(rawPubX->data(), rawPubX->size()),
+ byte_view(rawPubY->data(), rawPubY->size())};
+ if (std::find(std::begin(kAuthorizedEcdsa256EekRoots),
+ std::end(kAuthorizedEcdsa256EekRoots),
+ matcher) == std::end(kAuthorizedEcdsa256EekRoots)) {
+ return kStatusInvalidEek;
+ }
+ }
+ }
+ auto eek = parseEcdh256(lastPubKey);
+ if (!eek) {
+ return kStatusInvalidEek;
+ }
+ return std::make_tuple(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
+ eek->getBstrValue(CoseKey::PUBKEY_Y).value(),
+ eek->getBstrValue(CoseKey::KEY_ID).value());
+}
TEST(RemoteProvUtilsTest, GenerateEekChainInvalidLength) {
- ASSERT_FALSE(generateEekChain(1, /*eekId=*/{}));
+ ASSERT_FALSE(generateEekChain(RpcHardwareInfo::CURVE_25519, 1, /*eekId=*/{}));
}
TEST(RemoteProvUtilsTest, GenerateEekChain) {
bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0};
for (size_t length : {2, 3, 31}) {
- auto get_eek_result = generateEekChain(length, kTestEekId);
+ auto get_eek_result = generateEekChain(RpcHardwareInfo::CURVE_25519, length, kTestEekId);
ASSERT_TRUE(get_eek_result) << get_eek_result.message();
auto& [chain, pubkey, privkey] = *get_eek_result;
@@ -57,7 +156,7 @@
}
TEST(RemoteProvUtilsTest, GetProdEekChain) {
- auto chain = getProdEekChain();
+ auto chain = getProdEekChain(RpcHardwareInfo::CURVE_25519);
auto validation_result = validateAndExtractEekPubAndId(
/*testMode=*/false, KeymasterBlob(chain.data(), chain.size()));
@@ -86,16 +185,68 @@
cppbor::Array array;
array.add(1);
- auto [json, error] = jsonEncodeCsrWithBuild(array);
+ auto [json, error] = jsonEncodeCsrWithBuild(std::string("test"), array);
ASSERT_TRUE(error.empty()) << error;
std::string expected = R"({"build_fingerprint":")" +
::android::base::GetProperty("ro.build.fingerprint", /*default=*/"") +
- R"(","csr":"gQE="})";
+ R"(","csr":"gQE=","name":"test"})";
ASSERT_EQ(json, expected);
}
+TEST(RemoteProvUtilsTest, GenerateEcdsaEekChainInvalidLength) {
+ ASSERT_FALSE(generateEekChain(RpcHardwareInfo::CURVE_P256, 1, /*eekId=*/{}));
+}
+
+TEST(RemoteProvUtilsTest, GenerateEcdsaEekChain) {
+ bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0};
+ for (size_t length : {2, 3, 31}) {
+ auto get_eek_result = generateEekChain(RpcHardwareInfo::CURVE_P256, length, kTestEekId);
+ ASSERT_TRUE(get_eek_result) << get_eek_result.message();
+
+ auto& [chain, pubkey, privkey] = *get_eek_result;
+
+ auto validation_result = validateAndExtractEcdsa256EekPubAndId(
+ /*testMode=*/true, KeymasterBlob(chain.data(), chain.size()));
+ ASSERT_TRUE(validation_result.isOk());
+
+ auto& [eekPubX, eekPubY, eekId] = *validation_result;
+ bytevec eekPub;
+ eekPub.insert(eekPub.begin(), eekPubX.begin(), eekPubX.end());
+ eekPub.insert(eekPub.end(), eekPubY.begin(), eekPubY.end());
+ EXPECT_THAT(eekId, ElementsAreArray(kTestEekId));
+ EXPECT_THAT(eekPub, ElementsAreArray(pubkey));
+ }
+}
+
+TEST(RemoteProvUtilsTest, GetProdEcdsaEekChain) {
+ auto chain = getProdEekChain(RpcHardwareInfo::CURVE_P256);
+
+ auto validation_result = validateAndExtractEcdsa256EekPubAndId(
+ /*testMode=*/false, KeymasterBlob(chain.data(), chain.size()));
+ ASSERT_TRUE(validation_result.isOk()) << "Error: " << validation_result.moveError();
+
+ auto& [eekPubX, eekPubY, eekId] = *validation_result;
+
+ auto [geekCert, ignoredNewPos, error] =
+ cppbor::parse(kCoseEncodedEcdsa256GeekCert, sizeof(kCoseEncodedEcdsa256GeekCert));
+ ASSERT_NE(geekCert, nullptr) << "Error: " << error;
+ ASSERT_NE(geekCert->asArray(), nullptr);
+
+ auto& encodedGeekCoseKey = geekCert->asArray()->get(kCoseSign1Payload);
+ ASSERT_NE(encodedGeekCoseKey, nullptr);
+ ASSERT_NE(encodedGeekCoseKey->asBstr(), nullptr);
+
+ auto geek = CoseKey::parse(encodedGeekCoseKey->asBstr()->value());
+ ASSERT_TRUE(geek) << "Error: " << geek.message();
+
+ const std::vector<uint8_t> empty;
+ EXPECT_THAT(eekId, ElementsAreArray(geek->getBstrValue(CoseKey::KEY_ID).value_or(empty)));
+ EXPECT_THAT(eekPubX, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_X).value_or(empty)));
+ EXPECT_THAT(eekPubY, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_Y).value_or(empty)));
+}
+
} // namespace
} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index 22219b0..d4d5857 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -10,6 +10,7 @@
aidl_interface {
name: "android.hardware.vibrator",
vendor_available: true,
+ host_supported: true,
srcs: [
"android/hardware/vibrator/*.aidl",
],
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 2e12dfb..acdbdcd 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -9,7 +9,8 @@
cc_library_static {
name: "libvibratorexampleimpl",
- vendor: true,
+ vendor_available: true,
+ host_supported: true,
shared_libs: [
"libbase",
"libbinder_ndk",
@@ -24,6 +25,11 @@
":__subpackages__",
"//hardware/interfaces/tests/extension/vibrator:__subpackages__",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
filegroup {
@@ -47,3 +53,40 @@
],
srcs: ["main.cpp"],
}
+
+cc_fuzz {
+ name: "android.hardware.vibrator-service.example_fuzzer",
+ host_supported: true,
+ static_libs: [
+ "android.hardware.vibrator-V2-ndk",
+ "libbase",
+ "libbinder_random_parcel",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libvibratorexampleimpl",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: ["fuzzer.cpp"],
+ fuzz_config: {
+ cc: [
+ "smoreland@google.com",
+ ],
+ },
+}
diff --git a/vibrator/aidl/default/fuzzer.cpp b/vibrator/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..7d52209
--- /dev/null
+++ b/vibrator/aidl/default/fuzzer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <vibrator-impl/Vibrator.h>
+#include <vibrator-impl/VibratorManager.h>
+
+using aidl::android::hardware::vibrator::Vibrator;
+using aidl::android::hardware::vibrator::VibratorManager;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto managedVib = SharedRefBase::make<Vibrator>();
+ auto vibManager = SharedRefBase::make<VibratorManager>(std::move(managedVib));
+
+ fuzzService(vibManager->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
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/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 1606b7b..086166a 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -318,7 +318,7 @@
}
bool waitForFrameworkReady() {
- int waitCount = 10;
+ int waitCount = 15;
do {
// Check whether package service is ready or not.
if (!testing::checkSubstringInCommandOutput(
diff --git a/wifi/supplicant/1.4/vts/functional/Android.bp b/wifi/supplicant/1.4/vts/functional/Android.bp
index 8cbe04f..57ee830 100644
--- a/wifi/supplicant/1.4/vts/functional/Android.bp
+++ b/wifi/supplicant/1.4/vts/functional/Android.bp
@@ -77,7 +77,6 @@
"general-tests",
"vts",
],
- disable_framework: true,
}
cc_test {
@@ -108,5 +107,4 @@
"general-tests",
"vts",
],
- disable_framework: true,
}