Merge "Unregistering HIDL interfaces breaks VTS"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 05e22bf..c998858 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -81,7 +81,7 @@
],
imports: [
"android.hardware.audio.common-V1",
- "android.media.audio.common.types",
+ "android.media.audio.common.types-V1",
],
stability: "vintf",
backend: {
diff --git a/automotive/sv/1.0/default/Android.bp b/automotive/sv/1.0/default/Android.bp
index da974a0..82e11a8 100644
--- a/automotive/sv/1.0/default/Android.bp
+++ b/automotive/sv/1.0/default/Android.bp
@@ -29,9 +29,7 @@
relative_install_path: "hw",
srcs: [
"service.cpp",
- "SurroundViewService.cpp",
- "SurroundView2dSession.cpp",
- "SurroundView3dSession.cpp",
+ ":automotiveSvV1.0_sources",
],
init_rc: ["android.hardware.automotive.sv@1.0-service.rc"],
vintf_fragments: ["android.hardware.automotive.sv@1.0-service.xml"],
@@ -54,3 +52,17 @@
"-g",
],
}
+
+filegroup {
+ name: "automotiveSvV1.0_sources",
+ srcs: [
+ "SurroundViewService.cpp",
+ "SurroundView2dSession.cpp",
+ "SurroundView3dSession.cpp",
+ ],
+}
+
+cc_library_headers {
+ name: "automotiveSvV1.0_headers",
+ export_include_dirs: ["."],
+}
diff --git a/automotive/sv/1.0/default/tests/fuzzer/Android.bp b/automotive/sv/1.0/default/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..c037723
--- /dev/null
+++ b/automotive/sv/1.0/default/tests/fuzzer/Android.bp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_fuzz {
+ name: "automotiveSvV1.0_fuzzer",
+ srcs: [
+ "AutomotiveSvV1_0Fuzzer.cpp",
+ "SurroundViewStream.cpp",
+ ":automotiveSvV1.0_sources",
+ ],
+ header_libs: [
+ "automotiveSvV1.0_headers",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.sv@1.0",
+ "android.hidl.allocator@1.0",
+ "libhidlbase",
+ "libutils",
+ "libhidlmemory",
+ "liblog",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 533764,
+ },
+}
diff --git a/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
new file mode 100644
index 0000000..98834f5
--- /dev/null
+++ b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
@@ -0,0 +1,433 @@
+/*
+ * 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 "AutomotiveSvV1_0Fuzzer.h"
+#include <SurroundViewStream.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <hidlmemory/mapping.h>
+
+namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer {
+
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::allocator::V1_0::IAllocator;
+
+constexpr uint32_t kMinConfigDimension = 0;
+constexpr uint32_t kMaxConfigDimension = 4096;
+constexpr uint32_t kVertexByteSize = (3 * sizeof(float)) + 4;
+constexpr uint32_t kIdByteSize = 2;
+constexpr size_t kMaxCharacters = 30;
+constexpr size_t kMaxVertices = 10;
+constexpr size_t kMaxCameraPoints = 10;
+constexpr size_t kMaxViews = 10;
+constexpr size_t kMaxOverlays = 10;
+constexpr size_t kMinSvBuffers = 0;
+constexpr size_t kMaxSvBuffers = 10;
+
+void SurroundViewFuzzer::invoke2dSessionAPI() {
+ sp<ISurroundView2dSession> surroundView2dSession;
+
+ while (mFuzzedDataProvider.remaining_bytes() > 0) {
+ auto surroundView2dFunc = mFuzzedDataProvider.PickValueInArray<
+ const std::function<void()>>({
+ [&]() {
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](const sp<ISurroundView2dSession>& session,
+ SvResult result) {
+ if (result == SvResult::OK) {
+ surroundView2dSession = session;
+ }
+ });
+ },
+ [&]() {
+ if (surroundView2dSession) {
+ sp<SurroundViewStream> handler =
+ sp<SurroundViewStream>::make(surroundView2dSession);
+ surroundView2dSession->startStream(handler);
+ mIs2dStreamStarted = true;
+ }
+ },
+ [&]() {
+ if (surroundView2dSession) {
+ surroundView2dSession->get2dMappingInfo(
+ []([[maybe_unused]] Sv2dMappingInfo info) {});
+ }
+ },
+ [&]() {
+ if (surroundView2dSession) {
+ Sv2dConfig config;
+ config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
+ kMinConfigDimension, kMaxConfigDimension);
+ if (mFuzzedDataProvider.ConsumeBool()) {
+ config.blending = static_cast<SvQuality>(
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>());
+ } else {
+ config.blending = mFuzzedDataProvider.ConsumeBool() ? (SvQuality::HIGH)
+ : (SvQuality::LOW);
+ }
+ surroundView2dSession->set2dConfig(config);
+ }
+ },
+ [&]() {
+ if (surroundView2dSession) {
+ surroundView2dSession->get2dConfig([&](Sv2dConfig) {});
+ }
+ },
+ [&]() {
+ if (surroundView2dSession) {
+ hidl_vec<Point2dInt> points2dCamera;
+ const size_t camPoints = mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(
+ 1, kMaxCameraPoints);
+ points2dCamera.resize(camPoints);
+ for (size_t i = 0; i < camPoints; ++i) {
+ points2dCamera[i].x = mFuzzedDataProvider.ConsumeFloatingPoint<float>();
+ points2dCamera[i].y = mFuzzedDataProvider.ConsumeFloatingPoint<float>();
+ }
+
+ hidl_vec<hidl_string> cameraIds;
+ mSurroundViewService->getCameraIds(
+ [&cameraIds](const hidl_vec<hidl_string>& camIds) {
+ cameraIds = camIds;
+ });
+ hidl_string cameraId;
+ if (cameraIds.size() > 0 && mFuzzedDataProvider.ConsumeBool()) {
+ const size_t cameraIndex =
+ mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(
+ 0, cameraIds.size() - 1);
+ cameraId = cameraIds[cameraIndex];
+ } else {
+ cameraId =
+ mFuzzedDataProvider.ConsumeRandomLengthString(kMaxCharacters);
+ }
+ surroundView2dSession->projectCameraPoints(
+ points2dCamera, cameraId,
+ []([[maybe_unused]] const hidl_vec<Point2dFloat>& outPoints) {});
+ }
+ },
+ [&]() {
+ if (surroundView2dSession) {
+ SvFramesDesc frames;
+ frames.timestampNs = mFuzzedDataProvider.ConsumeIntegral<uint64_t>();
+ frames.sequenceId = mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ size_t numSvBuffers = mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(
+ kMinSvBuffers, kMaxSvBuffers);
+ frames.svBuffers.resize(numSvBuffers);
+ for (int i = 0; i < numSvBuffers; ++i) {
+ frames.svBuffers[i].viewId =
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
+ frames.svBuffers[i].hardwareBuffer.description[0] =
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ frames.svBuffers[i].hardwareBuffer.description[1] =
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ }
+ surroundView2dSession->doneWithFrames(frames);
+ for (int i = 0; i < numSvBuffers; ++i) {
+ delete frames.svBuffers[i].hardwareBuffer.nativeHandle;
+ }
+ }
+ },
+ [&]() {
+ if (surroundView2dSession) {
+ surroundView2dSession->stopStream();
+ mIs2dStreamStarted = false;
+ }
+ },
+ [&]() {
+ mSurroundViewService->stop2dSession(
+ mFuzzedDataProvider.ConsumeBool() ? surroundView2dSession : nullptr);
+ },
+ });
+ surroundView2dFunc();
+ }
+
+ if (surroundView2dSession && mIs2dStreamStarted) {
+ surroundView2dSession->stopStream();
+ }
+}
+
+void SurroundViewFuzzer::invoke3dSessionAPI() {
+ sp<ISurroundView3dSession> surroundView3dSession;
+ while (mFuzzedDataProvider.remaining_bytes() > 0) {
+ auto surroundView3dFunc = mFuzzedDataProvider.PickValueInArray<
+ const std::function<void()>>({
+ [&]() {
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](const sp<ISurroundView3dSession>& session,
+ SvResult result) {
+ if (result == SvResult::OK) {
+ surroundView3dSession = session;
+ }
+ });
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ sp<SurroundViewStream> handler =
+ sp<SurroundViewStream>::make(surroundView3dSession);
+ surroundView3dSession->startStream(handler);
+ mIs3dStreamStarted = true;
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ const size_t numViews =
+ mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxViews);
+ std::vector<View3d> views(numViews);
+ for (size_t i = 0; i < numViews; ++i) {
+ views[i].viewId = mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ }
+ surroundView3dSession->setViews(views);
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ Sv3dConfig config;
+ config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
+ kMinConfigDimension, kMaxConfigDimension);
+ config.height = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
+ kMinConfigDimension, kMaxConfigDimension);
+ if (mFuzzedDataProvider.ConsumeBool()) {
+ config.carDetails = static_cast<SvQuality>(
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>());
+ } else {
+ config.carDetails = mFuzzedDataProvider.ConsumeBool()
+ ? (SvQuality::HIGH)
+ : (SvQuality::LOW);
+ }
+ surroundView3dSession->set3dConfig(config);
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ surroundView3dSession->get3dConfig([&](Sv3dConfig) {});
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ Point2dInt cameraPoint;
+ cameraPoint.x = mFuzzedDataProvider.ConsumeFloatingPoint<float>();
+ cameraPoint.y = mFuzzedDataProvider.ConsumeFloatingPoint<float>();
+ std::vector<Point2dInt> cameraPoints = {cameraPoint};
+ hidl_vec<hidl_string> cameraIds;
+ mSurroundViewService->getCameraIds(
+ [&cameraIds](const hidl_vec<hidl_string>& camIds) {
+ cameraIds = camIds;
+ });
+ hidl_string cameraId;
+ if (cameraIds.size() > 0 && mFuzzedDataProvider.ConsumeBool()) {
+ const size_t cameraIndex =
+ mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(
+ 0, cameraIds.size() - 1);
+ cameraId = cameraIds[cameraIndex];
+ } else {
+ cameraId =
+ mFuzzedDataProvider.ConsumeRandomLengthString(kMaxCharacters);
+ }
+ std::vector<Point3dFloat> points3d;
+ surroundView3dSession->projectCameraPointsTo3dSurface(
+ cameraPoints, cameraId,
+ [&points3d]([[maybe_unused]] const hidl_vec<Point3dFloat>&
+ points3dproj) { points3d = points3dproj; });
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ // success case
+ surroundView3dSession->updateOverlays(mOverlaysdata);
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ initSampleOverlaysData();
+ // Fail with ID mismatch
+ // Set id of second overlay in shared memory to 2 (expected is 1).
+ auto& overlaysDescVector = mOverlaysdata.overlaysMemoryDesc;
+ auto& pIMemory = mMemory;
+ int32_t indexPosition = mFuzzedDataProvider.ConsumeIntegralInRange<int32_t>(
+ 0, mNumOverlays - 1);
+ int32_t mismatchedValueIndex =
+ mFuzzedDataProvider.ConsumeIntegralInRange<int32_t>(
+ 0, mNumOverlays - 1);
+ setIndexOfOverlaysMemory(overlaysDescVector, pIMemory, indexPosition,
+ overlaysDescVector[mismatchedValueIndex].id);
+ surroundView3dSession->updateOverlays(mOverlaysdata);
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ // Fail with NULL memory
+ // Set shared memory to null.
+ mOverlaysdata.overlaysMemory = hidl_memory();
+ surroundView3dSession->updateOverlays(mOverlaysdata);
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ SvFramesDesc frames;
+ frames.timestampNs = mFuzzedDataProvider.ConsumeIntegral<uint64_t>();
+ frames.sequenceId = mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ size_t numSvBuffers = mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(
+ kMinSvBuffers, kMaxSvBuffers);
+ frames.svBuffers.resize(numSvBuffers);
+ for (int i = 0; i < numSvBuffers; ++i) {
+ frames.svBuffers[i].viewId =
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
+ frames.svBuffers[i].hardwareBuffer.description[0] =
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ frames.svBuffers[i].hardwareBuffer.description[1] =
+ mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ }
+ surroundView3dSession->doneWithFrames(frames);
+ for (int i = 0; i < numSvBuffers; ++i) {
+ delete frames.svBuffers[i].hardwareBuffer.nativeHandle;
+ }
+ }
+ },
+ [&]() {
+ if (surroundView3dSession) {
+ surroundView3dSession->stopStream();
+ mIs3dStreamStarted = false;
+ }
+ },
+ [&]() {
+ mSurroundViewService->stop3dSession(
+ mFuzzedDataProvider.ConsumeBool() ? surroundView3dSession : nullptr);
+ },
+ });
+ surroundView3dFunc();
+ }
+ if (surroundView3dSession && mIs3dStreamStarted) {
+ surroundView3dSession->stopStream();
+ }
+}
+
+void SurroundViewFuzzer::process() {
+ mFuzzedDataProvider.ConsumeBool() ? invoke2dSessionAPI() : invoke3dSessionAPI();
+}
+
+std::pair<hidl_memory, sp<IMemory>> SurroundViewFuzzer::getMappedSharedMemory(int32_t bytesSize) {
+ const auto nullResult = std::make_pair(hidl_memory(), nullptr);
+
+ sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
+ if (ashmemAllocator.get() == nullptr) {
+ return nullResult;
+ }
+
+ // Allocate shared memory.
+ hidl_memory hidlMemory;
+ bool allocateSuccess = false;
+ Return<void> result =
+ ashmemAllocator->allocate(bytesSize, [&](bool success, const hidl_memory& hidlMem) {
+ if (!success) {
+ return;
+ }
+ allocateSuccess = success;
+ hidlMemory = hidlMem;
+ });
+
+ // Check result of allocated memory.
+ if (!result.isOk() || !allocateSuccess) {
+ return nullResult;
+ }
+
+ // Map shared memory.
+ sp<IMemory> pIMemory = mapMemory(hidlMemory);
+ if (pIMemory.get() == nullptr) {
+ return nullResult;
+ }
+
+ return std::make_pair(hidlMemory, pIMemory);
+}
+
+void SurroundViewFuzzer::setIndexOfOverlaysMemory(
+ const std::vector<OverlayMemoryDesc>& overlaysMemDesc, sp<IMemory> pIMemory,
+ int32_t indexPosition, uint16_t indexValue) {
+ // Count the number of vertices until the index.
+ int32_t totalVerticesCount = 0;
+ for (int32_t i = 0; i < indexPosition; ++i) {
+ totalVerticesCount += overlaysMemDesc[i].verticesCount;
+ }
+
+ const int32_t indexBytePosition =
+ (indexPosition * kIdByteSize) + (kVertexByteSize * totalVerticesCount);
+
+ uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+ pSharedMemoryData += indexBytePosition;
+ uint16_t* pIndex16bit = (uint16_t*)pSharedMemoryData;
+
+ // Modify shared memory.
+ pIMemory->update();
+ *pIndex16bit = indexValue;
+ pIMemory->commit();
+}
+
+void SurroundViewFuzzer::initSampleOverlaysData() {
+ const size_t mNumOverlays =
+ mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(kMinOverlays, kMaxOverlays);
+ mOverlaysdata.overlaysMemoryDesc.resize(mNumOverlays);
+
+ int32_t sharedMemBytesSize = 0;
+ std::vector<OverlayMemoryDesc> overlaysDescVector = {};
+ OverlayMemoryDesc overlayMemDesc[mNumOverlays];
+ for (size_t i = 0; i < mNumOverlays; ++i) {
+ overlayMemDesc[i].id = i;
+ overlayMemDesc[i].verticesCount =
+ mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxVertices);
+ overlayMemDesc[i].overlayPrimitive = mFuzzedDataProvider.ConsumeBool()
+ ? (OverlayPrimitive::TRIANGLES)
+ : (OverlayPrimitive::TRIANGLES_STRIP);
+ mOverlaysdata.overlaysMemoryDesc[i] = overlayMemDesc[i];
+
+ sharedMemBytesSize += kIdByteSize + kVertexByteSize * overlayMemDesc[i].verticesCount;
+ overlaysDescVector.push_back(overlayMemDesc[i]);
+ }
+
+ std::pair<hidl_memory, sp<IMemory>> sharedMem = getMappedSharedMemory(sharedMemBytesSize);
+ sp<IMemory> pIMemory = std::get<1>(sharedMem);
+ if (pIMemory.get() == nullptr) {
+ mOverlaysdata = OverlaysData();
+ mMemory = nullptr;
+ return;
+ }
+
+ // Get pointer to shared memory data and set all bytes to 0.
+ uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+ pIMemory->update();
+ memset(pSharedMemoryData, 0, sharedMemBytesSize);
+ pIMemory->commit();
+
+ // Set indexes in shared memory.
+ for (size_t i = 0; i < mNumOverlays; ++i) {
+ setIndexOfOverlaysMemory(overlaysDescVector, pIMemory, i, overlayMemDesc[i].id);
+ }
+
+ mOverlaysdata.overlaysMemoryDesc = overlaysDescVector;
+ mOverlaysdata.overlaysMemory = std::get<0>(sharedMem);
+ mMemory = pIMemory;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < 1) {
+ return 0;
+ }
+ SurroundViewFuzzer surroundViewFuzzer(data, size);
+ surroundViewFuzzer.process();
+ return 0;
+}
+} // namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer
diff --git a/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.h b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.h
new file mode 100644
index 0000000..23e5a31
--- /dev/null
+++ b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#pragma once
+#include <SurroundViewService.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer {
+
+using ::android::sp;
+using ::android::hidl::memory::V1_0::IMemory;
+
+constexpr size_t kMinOverlays = 2;
+
+class SurroundViewFuzzer {
+ public:
+ SurroundViewFuzzer(const uint8_t* data, size_t size) : mFuzzedDataProvider(data, size) {
+ mSurroundViewService = sp<SurroundViewService>::make();
+ }
+ ~SurroundViewFuzzer() = default;
+ void process();
+
+ private:
+ void invoke2dSessionAPI();
+ void invoke3dSessionAPI();
+ std::pair<hidl_memory, sp<IMemory>> getMappedSharedMemory(int32_t bytesSize);
+ void initSampleOverlaysData();
+ void setIndexOfOverlaysMemory(const std::vector<OverlayMemoryDesc>& overlaysMemDesc,
+ sp<IMemory> pIMemory, int32_t indexPosition, uint16_t indexValue);
+ OverlaysData mOverlaysdata = {};
+ size_t mNumOverlays = kMinOverlays;
+ sp<IMemory> mMemory = nullptr;
+ FuzzedDataProvider mFuzzedDataProvider;
+ sp<SurroundViewService> mSurroundViewService = nullptr;
+ bool mIs2dStreamStarted = false;
+ bool mIs3dStreamStarted = false;
+};
+} // namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer
diff --git a/automotive/sv/1.0/default/tests/fuzzer/SurroundViewStream.cpp b/automotive/sv/1.0/default/tests/fuzzer/SurroundViewStream.cpp
new file mode 100644
index 0000000..b81a08c
--- /dev/null
+++ b/automotive/sv/1.0/default/tests/fuzzer/SurroundViewStream.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "SurroundViewStream.h"
+
+namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer {
+
+using std::lock_guard;
+
+SurroundViewStream::SurroundViewStream(sp<ISurroundViewSession> pSession)
+ : mSession(pSession), mReceiveFramesCount(0) {}
+
+Return<void> SurroundViewStream::notify(SvEvent svEvent) {
+ lock_guard<mutex> lock(mLock);
+ switch (svEvent) {
+ case SvEvent::STREAM_STARTED:
+ case SvEvent::CONFIG_UPDATED:
+ case SvEvent::STREAM_STOPPED:
+ case SvEvent::FRAME_DROPPED:
+ case SvEvent::TIMEOUT:
+ mReceivedEvents.emplace_back(svEvent);
+ break;
+ default:
+ break;
+ }
+
+ return android::hardware::Void();
+}
+
+Return<void> SurroundViewStream::receiveFrames(const SvFramesDesc& svFramesDesc) {
+ lock_guard<mutex> lock(mLock);
+ if ((mLastReceivedFrames.timestampNs >= svFramesDesc.timestampNs ||
+ mLastReceivedFrames.sequenceId >= svFramesDesc.sequenceId) &&
+ mReceiveFramesCount != 0) {
+ // The incoming frames are with invalid timestamp or sequenceId
+ mAllFramesValid = false;
+ }
+
+ for (int i = 0; i < svFramesDesc.svBuffers.size(); ++i) {
+ if (svFramesDesc.svBuffers[i].hardwareBuffer.nativeHandle == nullptr) {
+ mAllFramesValid = false;
+ // The incoming frames are with invalid nativeHandle
+ break;
+ }
+ }
+
+ ++mReceiveFramesCount;
+
+ // Store all the information except for the handle
+ mLastReceivedFrames.timestampNs = svFramesDesc.timestampNs;
+ mLastReceivedFrames.sequenceId = svFramesDesc.sequenceId;
+ mLastReceivedFrames.svBuffers.resize(svFramesDesc.svBuffers.size());
+ for (int i = 0; i < svFramesDesc.svBuffers.size(); ++i) {
+ mLastReceivedFrames.svBuffers[i].viewId = svFramesDesc.svBuffers[i].viewId;
+ mLastReceivedFrames.svBuffers[i].hardwareBuffer.description =
+ svFramesDesc.svBuffers[i].hardwareBuffer.description;
+ }
+
+ return android::hardware::Void();
+}
+} // namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer
diff --git a/automotive/sv/1.0/default/tests/fuzzer/SurroundViewStream.h b/automotive/sv/1.0/default/tests/fuzzer/SurroundViewStream.h
new file mode 100644
index 0000000..8135bc1
--- /dev/null
+++ b/automotive/sv/1.0/default/tests/fuzzer/SurroundViewStream.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/types.h>
+
+#include <thread>
+#include <vector>
+
+namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer {
+
+using android::sp;
+using android::hardware::Return;
+using std::mutex;
+using std::vector;
+
+class SurroundViewStream : public ISurroundViewStream {
+ public:
+ SurroundViewStream(sp<ISurroundViewSession> session);
+
+ Return<void> notify(SvEvent svEvent) override;
+ Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+
+ bool checkEventReceived(SvEvent svEvent);
+ SvFramesDesc getLastReceivedFrames();
+ int getReceiveFramesCount();
+ bool areAllFramesValid();
+ void setDoNotReturnFrames(bool flag);
+
+ private:
+ mutex mLock;
+
+ vector<SvEvent> mReceivedEvents;
+ sp<ISurroundViewSession> mSession;
+ SvFramesDesc mLastReceivedFrames;
+ int mReceiveFramesCount;
+ bool mAllFramesValid = true;
+};
+} // namespace android::hardware::automotive::sv::V1_0::implementation::fuzzer
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index 63797b4..01819fb 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -292,8 +292,9 @@
.prop = toInt(VehicleProperty::EV_CHARGE_CURRENT_DRAW_LIMIT),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {/*max current draw allowed by vehicle in amperes=*/20},
},
- .initialValue = {.floatValues = {(float)VehicleUnit::AMPERE}}},
+ .initialValue = {.floatValues = {(float)12.5}}},
{.config =
{
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 430bf3c..e6628f2 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -16,6 +16,7 @@
local_include_dirs: ["include"],
srcs: [
"CancellationSignal.cpp",
+ "FakeFingerprintEngine.cpp",
"Fingerprint.cpp",
"Session.cpp",
"WorkerThread.cpp",
@@ -27,6 +28,7 @@
"android.hardware.biometrics.fingerprint-V2-ndk",
"android.hardware.biometrics.common-V2-ndk",
],
+ static_libs: ["android.hardware.biometrics.fingerprint.VirtualProps"],
}
cc_test_host {
@@ -41,3 +43,33 @@
],
test_suites: ["general-tests"],
}
+
+cc_test {
+ name: "android.hardware.biometrics.fingerprint.FakeFingerprintEngineTest",
+ local_include_dirs: ["include"],
+ srcs: [
+ "CancellationSignal.cpp",
+ "tests/FakeFingerprintEngineTest.cpp",
+ "FakeFingerprintEngine.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.biometrics.fingerprint.VirtualProps",
+ "android.hardware.biometrics.fingerprint-V2-ndk",
+ "android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.keymaster-V3-ndk",
+ ],
+ vendor: true,
+ test_suites: ["general-tests"],
+ require_root: true,
+}
+
+sysprop_library {
+ name: "android.hardware.biometrics.fingerprint.VirtualProps",
+ srcs: ["fingerprint.sysprop"],
+ property_owner: "Vendor",
+ vendor: true,
+}
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
new file mode 100644
index 0000000..d1fe183
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FakeFingerprintEngine.h"
+
+#include <fingerprint.sysprop.h>
+#include "CancellationSignal.h"
+
+#include <android-base/logging.h>
+#include <chrono>
+#include <regex>
+#include <thread>
+
+#define SLEEP_MS(x) \
+ if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
+#define BEGIN_OP(x) \
+ do { \
+ LOG(INFO) << __func__; \
+ SLEEP_MS(x); \
+ } while (0)
+#define IS_TRUE(x) ((x == "1") || (x == "true"))
+
+// This is for non-test situations, such as casual cuttlefish users, that don't
+// set an explicit value.
+// Some operations (i.e. enroll, authenticate) will be executed in tight loops
+// by parts of the UI or fail if there is no latency. For example, the
+// fingerprint settings page constantly runs auth and the enrollment UI uses a
+// cancel/restart cycle that requires some latency while the activities change.
+#define DEFAULT_LATENCY 2000
+
+using namespace ::android::fingerprint::virt;
+using namespace ::aidl::android::hardware::biometrics::fingerprint;
+
+int64_t getSystemNanoTime() {
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now.tv_sec * 1000000000LL + now.tv_nsec;
+}
+
+bool hasElapsed(int64_t start, int64_t durationMillis) {
+ auto now = getSystemNanoTime();
+ if (now < start) return true;
+ if (durationMillis <= 0) return true;
+ return ((now - start) / 1000000LL) > durationMillis;
+}
+
+std::vector<std::string> split(const std::string& str, const std::string& sep) {
+ std::regex regex(sep);
+ std::vector<std::string> parts(std::sregex_token_iterator(str.begin(), str.end(), regex, -1),
+ std::sregex_token_iterator());
+ return parts;
+}
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+ std::uniform_int_distribution<int64_t> dist;
+ auto challenge = dist(mRandom);
+ FingerprintHalProperties::challenge(challenge);
+ cb->onChallengeGenerated(challenge);
+}
+
+void FakeFingerprintEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
+ BEGIN_OP(0);
+ FingerprintHalProperties::challenge({});
+ cb->onChallengeRevoked(challenge);
+}
+
+void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
+ const keymaster::HardwareAuthToken& hat,
+ const std::future<void>& cancel) {
+ BEGIN_OP(FingerprintHalProperties::operation_enroll_latency().value_or(DEFAULT_LATENCY));
+
+ // Do proper HAT verification in the real implementation.
+ if (hat.mac.empty()) {
+ LOG(ERROR) << "Fail: hat";
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+ return;
+ }
+
+ if (FingerprintHalProperties::operation_enroll_fails().value_or(false)) {
+ LOG(ERROR) << "Fail: operation_enroll_fails";
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+
+ // format is "<id>:<progress_ms>,<progress_ms>,...:<result>
+ auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
+ auto parts = split(nextEnroll, ":");
+ if (parts.size() != 3) {
+ LOG(ERROR) << "Fail: invalid next_enrollment";
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+ auto enrollmentId = std::stoi(parts[0]);
+ auto progress = split(parts[1], ",");
+ for (size_t i = 0; i < progress.size(); i++) {
+ auto left = progress.size() - i - 1;
+ SLEEP_MS(std::stoi(progress[i]));
+
+ if (shouldCancel(cancel)) {
+ LOG(ERROR) << "Fail: cancel";
+ cb->onError(Error::CANCELED, 0 /* vendorCode */);
+ return;
+ }
+
+ cb->onAcquired(AcquiredInfo::GOOD, 0 /* vendorCode */);
+ if (left == 0 && !IS_TRUE(parts[2])) { // end and failed
+ LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
+ FingerprintHalProperties::next_enrollment({});
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ } else { // progress and update props if last time
+ if (left == 0) {
+ auto enrollments = FingerprintHalProperties::enrollments();
+ enrollments.emplace_back(enrollmentId);
+ FingerprintHalProperties::enrollments(enrollments);
+ FingerprintHalProperties::next_enrollment({});
+ LOG(INFO) << "Enrolled: " << enrollmentId;
+ }
+ cb->onEnrollmentProgress(enrollmentId, left);
+ }
+ }
+}
+
+void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* operationId */,
+ const std::future<void>& cancel) {
+ BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));
+
+ auto now = getSystemNanoTime();
+ int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(0);
+ do {
+ if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
+ LOG(ERROR) << "Fail: operation_authenticate_fails";
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+
+ if (FingerprintHalProperties::lockout().value_or(false)) {
+ LOG(ERROR) << "Fail: lockout";
+ cb->onLockoutPermanent();
+ cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
+ return;
+ }
+
+ if (shouldCancel(cancel)) {
+ LOG(ERROR) << "Fail: cancel";
+ cb->onError(Error::CANCELED, 0 /* vendorCode */);
+ return;
+ }
+
+ auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
+ auto enrolls = FingerprintHalProperties::enrollments();
+ auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+ if (id > 0 && isEnrolled) {
+ cb->onAuthenticationSucceeded(id, {} /* hat */);
+ return;
+ }
+
+ SLEEP_MS(100);
+ } while (!hasElapsed(now, duration));
+
+ LOG(ERROR) << "Fail: not enrolled";
+ cb->onAuthenticationFailed();
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+}
+
+void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
+ const std::future<void>& cancel) {
+ BEGIN_OP(FingerprintHalProperties::operation_detect_interaction_latency().value_or(
+ DEFAULT_LATENCY));
+
+ if (FingerprintHalProperties::operation_detect_interaction_fails().value_or(false)) {
+ LOG(ERROR) << "Fail: operation_detect_interaction_fails";
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+
+ if (shouldCancel(cancel)) {
+ LOG(ERROR) << "Fail: cancel";
+ cb->onError(Error::CANCELED, 0 /* vendorCode */);
+ return;
+ }
+
+ auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
+ auto enrolls = FingerprintHalProperties::enrollments();
+ auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+ if (id <= 0 || !isEnrolled) {
+ LOG(ERROR) << "Fail: not enrolled";
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+ return;
+ }
+
+ cb->onInteractionDetected();
+}
+
+void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+
+ std::vector<int32_t> ids;
+ for (auto& enrollment : FingerprintHalProperties::enrollments()) {
+ auto id = enrollment.value_or(0);
+ if (id > 0) {
+ ids.push_back(id);
+ }
+ }
+
+ cb->onEnrollmentsEnumerated(ids);
+}
+
+void FakeFingerprintEngine::removeEnrollmentsImpl(ISessionCallback* cb,
+ const std::vector<int32_t>& enrollmentIds) {
+ BEGIN_OP(0);
+
+ std::vector<std::optional<int32_t>> newEnrollments;
+ std::vector<int32_t> removed;
+ for (auto& enrollment : FingerprintHalProperties::enrollments()) {
+ auto id = enrollment.value_or(0);
+ if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) != enrollmentIds.end()) {
+ removed.push_back(id);
+ } else if (id > 0) {
+ newEnrollments.emplace_back(id);
+ }
+ }
+ FingerprintHalProperties::enrollments(newEnrollments);
+
+ cb->onEnrollmentsRemoved(enrollmentIds);
+}
+
+void FakeFingerprintEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+ cb->onAuthenticatorIdRetrieved(FingerprintHalProperties::authenticator_id().value_or(0));
+}
+
+void FakeFingerprintEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+ auto id = FingerprintHalProperties::authenticator_id().value_or(0);
+ auto newId = id + 1;
+ FingerprintHalProperties::authenticator_id(newId);
+ cb->onAuthenticatorIdInvalidated(newId);
+}
+
+void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb,
+ const keymaster::HardwareAuthToken& /*hat*/) {
+ BEGIN_OP(0);
+ FingerprintHalProperties::lockout(false);
+ cb->onLockoutCleared();
+}
+
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index 1f14de6..71dc660 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -16,15 +16,19 @@
#include "Fingerprint.h"
+#include <fingerprint.sysprop.h>
#include "Session.h"
+#include <android-base/logging.h>
+
+using namespace ::android::fingerprint::virt;
+
namespace aidl::android::hardware::biometrics::fingerprint {
namespace {
constexpr size_t MAX_WORKER_QUEUE_SIZE = 5;
constexpr int SENSOR_ID = 1;
constexpr common::SensorStrength SENSOR_STRENGTH = common::SensorStrength::STRONG;
constexpr int MAX_ENROLLMENTS_PER_USER = 5;
-constexpr FingerprintSensorType SENSOR_TYPE = FingerprintSensorType::REAR;
constexpr bool SUPPORTS_NAVIGATION_GESTURES = true;
constexpr char HW_COMPONENT_ID[] = "fingerprintSensor";
constexpr char HW_VERSION[] = "vendor/model/revision";
@@ -51,8 +55,18 @@
0 /* sensorLocationY */, 0 /* sensorRadius */,
"" /* display */};
+ FingerprintSensorType sensorType = FingerprintSensorType::UNKNOWN;
+ std::string sensorTypeProp = FingerprintHalProperties::type().value_or("");
+ if (sensorTypeProp == "" || sensorTypeProp == "default" || sensorTypeProp == "rear") {
+ sensorType = FingerprintSensorType::REAR;
+ }
+ if (sensorType == FingerprintSensorType::UNKNOWN) {
+ UNIMPLEMENTED(FATAL) << "unrecognized or unimplemented fingerprint behavior: "
+ << sensorTypeProp;
+ }
+
*out = {{commonProps,
- SENSOR_TYPE,
+ sensorType,
{sensorLocation},
SUPPORTS_NAVIGATION_GESTURES,
false /* supportsDetectInteraction */}};
diff --git a/biometrics/fingerprint/aidl/default/README.md b/biometrics/fingerprint/aidl/default/README.md
new file mode 100644
index 0000000..046602f
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/README.md
@@ -0,0 +1,74 @@
+# Virtual Fingerprint HAL
+
+This is a virtual HAL implementation that is backed by system properties
+instead of actual hardware. It's intended for testing and UI development
+on debuggable builds to allow devices to masquerade as alternative device
+types and for emulators.
+
+## Getting Started
+
+First, set the type of sensor the device should use, enable the virtual
+extensions in the framework, and reboot.
+
+This doesn't work with HIDL and you typically need to have a PIN or password
+set for things to work correctly, so this is a good time to set those too.
+
+```shell
+$ adb root
+$ adb shell settings put secure biometric_virtual_enabled 1
+$ adb shell setprop persist.vendor.fingerprint.virtual.type rear
+$ adb shell locksettings set-pin 0000
+$ adb shell settings put secure com.android.server.biometrics.AuthService.hidlDisabled 1
+$ adb reboot
+```
+
+### Enrollments
+
+Next, setup enrollments on the device. This can either be done through
+the UI, or via adb.
+
+#### UI Enrollment
+
+ 1. Tee up the results of the enrollment before starting the process:
+
+ ```shell
+ $ adb shell setprop vendor.fingerprint.virtual.next_enrollment 1:100,100,100:true
+ ```
+ 2. Navigate to `Settings -> Security -> Fingerprint Unlock` and follow the prompts.
+ 3. Verify the enrollments in the UI:
+
+ ```shell
+ $ adb shell getprop persist.vendor.fingerprint.virtual.enrollments
+ ```
+
+#### Direct Enrollment
+
+To set enrollment directly without the UI:
+
+```shell
+$ adb root
+$ adb shell setprop persist.vendor.fingerprint.virtual.enrollments 1
+$ adb shell cmd fingerprint sync
+```
+
+Note: You may need to do this twice. The templates are checked
+as part of some lazy operations, like user switching and startup, which can
+cause the framework to delete the enrollments before the sync operation runs.
+Until this is fixed, just run the commands twice as a workaround.
+
+### Authenticate
+
+To authenticate successfully set the enrolled id that should succeed. Unset it
+or change the value to make authenticate operations fail:
+
+````shell
+$ adb shell setprop vendor.fingerprint.virtual.enrollment_hit 1
+````
+
+### View HAL State
+
+To view all the properties of the HAL (see `fingerprint.sysprop` for the API):
+
+```shell
+$ adb shell getprop | grep vendor.fingerprint.virtual
+```
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index 452ed12..078d3d9 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -101,7 +101,7 @@
if (shouldCancel(cancFuture)) {
mCb->onError(Error::CANCELED, 0 /* vendorCode */);
} else {
- mEngine->enrollImpl(mCb.get(), hat);
+ mEngine->enrollImpl(mCb.get(), hat, cancFuture);
}
enterIdling();
}));
@@ -123,7 +123,7 @@
if (shouldCancel(cancFuture)) {
mCb->onError(Error::CANCELED, 0 /* vendorCode */);
} else {
- mEngine->authenticateImpl(mCb.get(), operationId);
+ mEngine->authenticateImpl(mCb.get(), operationId, cancFuture);
}
enterIdling();
}));
@@ -144,7 +144,7 @@
if (shouldCancel(cancFuture)) {
mCb->onError(Error::CANCELED, 0 /* vendorCode */);
} else {
- mEngine->detectInteractionImpl(mCb.get());
+ mEngine->detectInteractionImpl(mCb.get(), cancFuture);
}
enterIdling();
}));
diff --git a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
new file mode 100644
index 0000000..4724ff4
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
@@ -0,0 +1,85 @@
+props {
+ owner: Vendor
+ module: "android.fingerprint.virt.FingerprintHalProperties"
+ prop {
+ api_name: "authenticator_id"
+ type: Long
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.authenticator_id"
+ }
+ prop {
+ api_name: "challenge"
+ type: Long
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.challenge"
+ }
+ prop {
+ api_name: "enrollment_hit"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.enrollment_hit"
+ }
+ prop {
+ api_name: "enrollments"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "persist.vendor.fingerprint.virtual.enrollments"
+ }
+ prop {
+ api_name: "lockout"
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.lockout"
+ }
+ prop {
+ api_name: "next_enrollment"
+ type: String
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.next_enrollment"
+ }
+ prop {
+ api_name: "operation_authenticate_duration"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
+ }
+ prop {
+ api_name: "operation_authenticate_fails"
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
+ }
+ prop {
+ api_name: "operation_authenticate_latency"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
+ }
+ prop {
+ api_name: "operation_detect_interaction_fails"
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
+ }
+ prop {
+ api_name: "operation_detect_interaction_latency"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
+ }
+ prop {
+ api_name: "operation_enroll_fails"
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
+ }
+ prop {
+ api_name: "operation_enroll_latency"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
+ }
+ prop {
+ api_name: "type"
+ type: String
+ access: ReadWrite
+ prop_name: "persist.vendor.fingerprint.virtual.type"
+ enum_values: "default|rear|udfps|side"
+ }
+}
diff --git a/biometrics/fingerprint/aidl/default/fingerprint.sysprop b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
new file mode 100644
index 0000000..12c8648
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
@@ -0,0 +1,135 @@
+# fingerprint.sysprop
+# module becomes static class (Java) / namespace (C++) for serving API
+module: "android.fingerprint.virt.FingerprintHalProperties"
+owner: Vendor
+
+# type of fingerprint sensor
+prop {
+ prop_name: "persist.vendor.fingerprint.virtual.type"
+ type: String
+ scope: Public
+ access: ReadWrite
+ enum_values: "default|rear|udfps|side"
+ api_name: "type"
+}
+
+# ids of call current enrollments
+prop {
+ prop_name: "persist.vendor.fingerprint.virtual.enrollments"
+ type: IntegerList
+ scope: Public
+ access: ReadWrite
+ api_name: "enrollments"
+}
+
+# authenticate and detectInteraction will succeed with this
+# enrollment id, when present, otherwise they will error
+prop {
+ prop_name: "vendor.fingerprint.virtual.enrollment_hit"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "enrollment_hit"
+}
+
+# the next enrollment in the format: "<id>:<delay>,<delay>,...:<result>"
+# for example: "2:0:true"
+# this property is reset after enroll completes
+prop {
+ prop_name: "vendor.fingerprint.virtual.next_enrollment"
+ type: String
+ scope: Public
+ access: ReadWrite
+ api_name: "next_enrollment"
+}
+
+# value for getAuthenticatorId or 0
+prop {
+ prop_name: "vendor.fingerprint.virtual.authenticator_id"
+ type: Long
+ scope: Public
+ access: ReadWrite
+ api_name: "authenticator_id"
+}
+
+# value for generateChallenge
+prop {
+ prop_name: "vendor.fingerprint.virtual.challenge"
+ type: Long
+ scope: Public
+ access: ReadWrite
+ api_name: "challenge"
+}
+
+# if locked out
+prop {
+ prop_name: "vendor.fingerprint.virtual.lockout"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "lockout"
+}
+
+# force all authenticate operations to fail
+prop {
+ prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_authenticate_fails"
+}
+
+# force all detectInteraction operations to fail
+prop {
+ prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_detect_interaction_fails"
+}
+
+# force all enroll operations to fail
+prop {
+ prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_enroll_fails"
+}
+
+# add a latency to authentication operations
+prop {
+ prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_authenticate_latency"
+}
+
+# add a latency to detectInteraction operations
+prop {
+ prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_detect_interaction_latency"
+}
+
+# add a latency to enroll operations
+prop {
+ prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_enroll_latency"
+}
+
+# millisecond duration for authenticate operations
+# (waits for changes to enrollment_hit)
+prop {
+ prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_authenticate_duration"
+}
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index b927770..8659b79 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -16,71 +16,33 @@
#pragma once
-#include <android-base/logging.h>
+#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
+
#include <random>
+#include "CancellationSignal.h"
+
+using namespace ::aidl::android::hardware::biometrics::common;
+
namespace aidl::android::hardware::biometrics::fingerprint {
+// A fake engine that is backed by system properties instead of hardware.
class FakeFingerprintEngine {
public:
FakeFingerprintEngine() : mRandom(std::mt19937::default_seed) {}
- void generateChallengeImpl(ISessionCallback* cb) {
- LOG(INFO) << "generateChallengeImpl";
- std::uniform_int_distribution<int64_t> dist;
- auto challenge = dist(mRandom);
- cb->onChallengeGenerated(challenge);
- }
-
- void revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
- LOG(INFO) << "revokeChallengeImpl";
- cb->onChallengeRevoked(challenge);
- }
-
- void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat) {
- LOG(INFO) << "enrollImpl";
- // Do proper HAT verification in the real implementation.
- if (hat.mac.empty()) {
- cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
- return;
- }
- cb->onEnrollmentProgress(0 /* enrollmentId */, 0 /* remaining */);
- }
-
- void authenticateImpl(ISessionCallback* cb, int64_t /* operationId */) {
- LOG(INFO) << "authenticateImpl";
- cb->onAuthenticationSucceeded(0 /* enrollmentId */, {} /* hat */);
- }
-
- void detectInteractionImpl(ISessionCallback* cb) {
- LOG(INFO) << "detectInteractionImpl";
- cb->onInteractionDetected();
- }
-
- void enumerateEnrollmentsImpl(ISessionCallback* cb) {
- LOG(INFO) << "enumerateEnrollmentsImpl";
- cb->onEnrollmentsEnumerated({} /* enrollmentIds */);
- }
-
- void removeEnrollmentsImpl(ISessionCallback* cb, const std::vector<int32_t>& enrollmentIds) {
- LOG(INFO) << "removeEnrollmentsImpl";
- cb->onEnrollmentsRemoved(enrollmentIds);
- }
-
- void getAuthenticatorIdImpl(ISessionCallback* cb) {
- LOG(INFO) << "getAuthenticatorIdImpl";
- cb->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
- }
-
- void invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
- LOG(INFO) << "invalidateAuthenticatorIdImpl";
- cb->onAuthenticatorIdInvalidated(0 /* newAuthenticatorId */);
- }
-
- void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/) {
- LOG(INFO) << "resetLockoutImpl";
- cb->onLockoutCleared();
- }
+ void generateChallengeImpl(ISessionCallback* cb);
+ void revokeChallengeImpl(ISessionCallback* cb, int64_t challenge);
+ void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ const std::future<void>& cancel);
+ void authenticateImpl(ISessionCallback* cb, int64_t operationId,
+ const std::future<void>& cancel);
+ void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
+ void enumerateEnrollmentsImpl(ISessionCallback* cb);
+ void removeEnrollmentsImpl(ISessionCallback* cb, const std::vector<int32_t>& enrollmentIds);
+ void getAuthenticatorIdImpl(ISessionCallback* cb);
+ void invalidateAuthenticatorIdImpl(ISessionCallback* cb);
+ void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
std::mt19937 mRandom;
};
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
new file mode 100644
index 0000000..742d933
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_process.h>
+#include <fingerprint.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
+
+#include "FakeFingerprintEngine.h"
+
+using namespace ::android::fingerprint::virt;
+using namespace ::aidl::android::hardware::biometrics::fingerprint;
+using namespace ::aidl::android::hardware::keymaster;
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class TestSessionCallback : public BnSessionCallback {
+ public:
+ ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
+ mLastChallenge = challenge;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
+ mLastChallengeRevoked = challenge;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onError(fingerprint::Error error, int32_t) override {
+ mError = error;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onEnrollmentProgress(int32_t enrollmentId, int32_t remaining) override {
+ if (remaining == 0) mLastEnrolled = enrollmentId;
+ return ndk::ScopedAStatus::ok();
+ };
+
+ ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t enrollmentId,
+ const keymaster::HardwareAuthToken&) override {
+ mLastAuthenticated = enrollmentId;
+ mAuthenticateFailed = false;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticationFailed() override {
+ mLastAuthenticated = 0;
+ mAuthenticateFailed = true;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onInteractionDetected() override {
+ mInteractionDetectedCount++;
+ return ndk::ScopedAStatus::ok();
+ };
+ ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onEnrollmentsEnumerated(
+ const std::vector<int32_t>& enrollmentIds) override {
+ mLastEnrollmentEnumerated = enrollmentIds;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onEnrollmentsRemoved(const std::vector<int32_t>& enrollmentIds) override {
+ mLastEnrollmentRemoved = enrollmentIds;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t authenticatorId) override {
+ mLastAuthenticatorId = authenticatorId;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t authenticatorId) override {
+ mLastAuthenticatorId = authenticatorId;
+ mAuthenticatorIdInvalidated = true;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onLockoutPermanent() override {
+ mLockoutPermanent = true;
+ return ndk::ScopedAStatus::ok();
+ };
+ ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
+ ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+
+ Error mError = Error::UNKNOWN;
+ int64_t mLastChallenge = -1;
+ int64_t mLastChallengeRevoked = -1;
+ int32_t mLastEnrolled = -1;
+ int32_t mLastAuthenticated = -1;
+ int64_t mLastAuthenticatorId = -1;
+ std::vector<int32_t> mLastEnrollmentEnumerated;
+ std::vector<int32_t> mLastEnrollmentRemoved;
+ bool mAuthenticateFailed = false;
+ bool mAuthenticatorIdInvalidated = false;
+ bool mLockoutPermanent = false;
+ int mInteractionDetectedCount = 0;
+};
+
+class FakeFingerprintEngineTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ FingerprintHalProperties::operation_enroll_latency(0);
+ FingerprintHalProperties::operation_authenticate_latency(0);
+ FingerprintHalProperties::operation_detect_interaction_latency(0);
+ mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
+ }
+
+ FakeFingerprintEngine mEngine;
+ std::shared_ptr<TestSessionCallback> mCallback;
+ std::promise<void> mCancel;
+};
+
+TEST_F(FakeFingerprintEngineTest, GenerateChallenge) {
+ mEngine.generateChallengeImpl(mCallback.get());
+ ASSERT_EQ(FingerprintHalProperties::challenge().value(), mCallback->mLastChallenge);
+}
+
+TEST_F(FakeFingerprintEngineTest, RevokeChallenge) {
+ auto challenge = FingerprintHalProperties::challenge().value_or(10);
+ mEngine.revokeChallengeImpl(mCallback.get(), challenge);
+ ASSERT_FALSE(FingerprintHalProperties::challenge().has_value());
+ ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
+}
+
+TEST_F(FakeFingerprintEngineTest, ResetLockout) {
+ FingerprintHalProperties::lockout(true);
+ mEngine.resetLockoutImpl(mCallback.get(), {});
+ ASSERT_FALSE(FingerprintHalProperties::lockout().value_or(true));
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticatorId) {
+ FingerprintHalProperties::authenticator_id(50);
+ mEngine.getAuthenticatorIdImpl(mCallback.get());
+ ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
+ ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticatorIdInvalidate) {
+ FingerprintHalProperties::authenticator_id(500);
+ mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
+ ASSERT_NE(500, FingerprintHalProperties::authenticator_id().value());
+ ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
+}
+
+TEST_F(FakeFingerprintEngineTest, Enroll) {
+ FingerprintHalProperties::enrollments({});
+ FingerprintHalProperties::next_enrollment("4:0,0:true");
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+ ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
+ ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
+ ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
+ ASSERT_EQ(4, mCallback->mLastEnrolled);
+}
+
+TEST_F(FakeFingerprintEngineTest, EnrollCancel) {
+ FingerprintHalProperties::enrollments({});
+ auto next = "4:0,0:true";
+ FingerprintHalProperties::next_enrollment(next);
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mCancel.set_value();
+ mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+ ASSERT_EQ(Error::CANCELED, mCallback->mError);
+ ASSERT_EQ(-1, mCallback->mLastEnrolled);
+ ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
+ ASSERT_EQ(next, FingerprintHalProperties::next_enrollment().value_or(""));
+}
+
+TEST_F(FakeFingerprintEngineTest, EnrollFail) {
+ FingerprintHalProperties::enrollments({});
+ auto next = "2:0,0:false";
+ FingerprintHalProperties::next_enrollment(next);
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+ ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
+ ASSERT_EQ(-1, mCallback->mLastEnrolled);
+ ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
+ ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
+}
+
+TEST_F(FakeFingerprintEngineTest, Authenticate) {
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit(2);
+ mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+ ASSERT_FALSE(mCallback->mAuthenticateFailed);
+ ASSERT_EQ(2, mCallback->mLastAuthenticated);
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) {
+ FingerprintHalProperties::enrollments({2});
+ FingerprintHalProperties::enrollment_hit(2);
+ mCancel.set_value();
+ mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+ ASSERT_EQ(Error::CANCELED, mCallback->mError);
+ ASSERT_EQ(-1, mCallback->mLastAuthenticated);
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticateNotSet) {
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit({});
+ mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+ ASSERT_TRUE(mCallback->mAuthenticateFailed);
+ ASSERT_EQ(mCallback->mError, Error::UNABLE_TO_PROCESS);
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticateNotEnrolled) {
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit(3);
+ mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+ ASSERT_TRUE(mCallback->mAuthenticateFailed);
+ ASSERT_EQ(mCallback->mError, Error::UNABLE_TO_PROCESS);
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) {
+ FingerprintHalProperties::enrollments({22, 2});
+ FingerprintHalProperties::enrollment_hit(2);
+ FingerprintHalProperties::lockout(true);
+ mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+ ASSERT_TRUE(mCallback->mLockoutPermanent);
+ ASSERT_NE(mCallback->mError, Error::UNKNOWN);
+}
+
+TEST_F(FakeFingerprintEngineTest, InteractionDetect) {
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit(2);
+ mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+ ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
+}
+
+TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit(2);
+ mCancel.set_value();
+ mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+ ASSERT_EQ(Error::CANCELED, mCallback->mError);
+ ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
+}
+
+TEST_F(FakeFingerprintEngineTest, InteractionDetectNotSet) {
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit({});
+ mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+ ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
+}
+
+TEST_F(FakeFingerprintEngineTest, InteractionDetectNotEnrolled) {
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit(25);
+ mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+ ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
+}
+
+TEST_F(FakeFingerprintEngineTest, EnumerateEnrolled) {
+ FingerprintHalProperties::enrollments({2, 4, 8});
+ mEngine.enumerateEnrollmentsImpl(mCallback.get());
+ ASSERT_EQ(3, mCallback->mLastEnrollmentEnumerated.size());
+ for (auto id : FingerprintHalProperties::enrollments()) {
+ ASSERT_TRUE(std::find(mCallback->mLastEnrollmentEnumerated.begin(),
+ mCallback->mLastEnrollmentEnumerated.end(),
+ id) != mCallback->mLastEnrollmentEnumerated.end());
+ }
+}
+
+TEST_F(FakeFingerprintEngineTest, RemoveEnrolled) {
+ FingerprintHalProperties::enrollments({2, 4, 8, 1});
+ mEngine.removeEnrollmentsImpl(mCallback.get(), {2, 8});
+ auto enrolls = FingerprintHalProperties::enrollments();
+ ASSERT_EQ(2, mCallback->mLastEnrollmentRemoved.size());
+ for (auto id : {2, 8}) {
+ ASSERT_TRUE(std::find(mCallback->mLastEnrollmentRemoved.begin(),
+ mCallback->mLastEnrollmentRemoved.end(),
+ id) != mCallback->mLastEnrollmentRemoved.end());
+ }
+ ASSERT_EQ(2, enrolls.size());
+ for (auto id : {1, 4}) {
+ ASSERT_TRUE(std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end());
+ }
+}
+
+} // namespace aidl::android::hardware::biometrics::fingerprint
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
index 30d5624..a474f66 100644
--- a/biometrics/fingerprint/aidl/vts/Android.bp
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -15,8 +15,8 @@
],
srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
static_libs: [
- "android.hardware.biometrics.common-V1-ndk",
- "android.hardware.biometrics.fingerprint-V1-ndk",
+ "android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.biometrics.fingerprint-V2-ndk",
"android.hardware.keymaster-V3-ndk",
],
shared_libs: [
diff --git a/bluetooth/1.0/default/test/fuzzer/Android.bp b/bluetooth/1.0/default/test/fuzzer/Android.bp
index 81f328e..691136f 100644
--- a/bluetooth/1.0/default/test/fuzzer/Android.bp
+++ b/bluetooth/1.0/default/test/fuzzer/Android.bp
@@ -46,7 +46,6 @@
"android.hardware.bluetooth-async",
"android.hardware.bluetooth-hci",
"libcutils",
- "libutils",
],
shared_libs: [
"android.hardware.bluetooth@1.0",
@@ -54,6 +53,7 @@
"libhidlbase",
"libbt-vendor-fuzz",
"liblog",
+ "libutils",
],
fuzz_config: {
cc: [
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index ff84558..e3b17f5 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -289,9 +289,9 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.graphics.allocator</name>
- <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
+ <!-- New, non-Go devices should use 4.0 or the AIDL hal. -->
<version>2.0</version>
<version>3.0</version>
<version>4.0</version>
diff --git a/health/aidl/OWNERS b/health/aidl/OWNERS
index cd06415..fcad499 100644
--- a/health/aidl/OWNERS
+++ b/health/aidl/OWNERS
@@ -1,2 +1,4 @@
# Bug component: 30545
elsk@google.com
+smoreland@google.com
+stayfan@google.com
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index c328879..b1949dd 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -15,7 +15,7 @@
stability: "vintf",
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
@@ -37,7 +37,7 @@
imports: ["android.hardware.radio"],
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
@@ -66,7 +66,7 @@
imports: ["android.hardware.radio"],
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
@@ -95,7 +95,7 @@
imports: ["android.hardware.radio"],
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
@@ -117,7 +117,7 @@
imports: ["android.hardware.radio"],
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
@@ -146,7 +146,7 @@
imports: ["android.hardware.radio"],
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
@@ -178,7 +178,7 @@
],
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
@@ -210,7 +210,7 @@
imports: ["android.hardware.radio"],
backend: {
cpp: {
- enabled: false,
+ enabled: true,
},
java: {
sdk_version: "module_current",
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyMode.aidl
new file mode 100644
index 0000000..071e6b5
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum EmergencyMode {
+ EMERGENCY_WWAN = 1,
+ EMERGENCY_WLAN = 2,
+ EMERGENCY_CALLBACK = 3,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
new file mode 100644
index 0000000..2797aff
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+@JavaDerive(toString=true) @VintfStability
+parcelable EmergencyNetworkScanTrigger {
+ android.hardware.radio.AccessNetwork[] accessNetwork;
+ android.hardware.radio.network.EmergencyScanType scanType;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
new file mode 100644
index 0000000..cb598f3
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+@JavaDerive(toString=true) @VintfStability
+parcelable EmergencyRegResult {
+ android.hardware.radio.AccessNetwork accessNetwork;
+ android.hardware.radio.network.RegState regState;
+ android.hardware.radio.network.Domain emcDomain;
+ boolean isEmcBearerSupported;
+ byte nwProvidedEmc;
+ byte nwProvidedEmf;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyScanType.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyScanType.aidl
new file mode 100644
index 0000000..5e86c76
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyScanType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum EmergencyScanType {
+ NO_PREFERENCE = 0,
+ LIMITED_SERVICE = 1,
+ FULL_SERVICE = 2,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index 2b70e45..832738f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -70,4 +70,8 @@
oneway void supplyNetworkDepersonalization(in int serial, in String netPin);
oneway void setUsageSetting(in int serial, in android.hardware.radio.network.UsageSetting usageSetting);
oneway void getUsageSetting(in int serial);
+ oneway void setEmergencyMode(int serial, in android.hardware.radio.network.EmergencyMode emcModeType);
+ oneway void triggerEmergencyNetworkScan(int serial, in android.hardware.radio.network.EmergencyNetworkScanTrigger request);
+ oneway void cancelEmergencyNetworkScan(in int serial);
+ oneway void exitEmergencyMode(in int serial);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
index bd03c51..0f017ea 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -48,4 +48,5 @@
oneway void restrictedStateChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.PhoneRestrictedState state);
oneway void suppSvcNotify(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.SuppSvcNotification suppSvc);
oneway void voiceRadioTechChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.RadioTechnology rat);
+ oneway void emergencyNetworkScanResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.EmergencyRegResult result);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 5f6c736..24d587e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -69,4 +69,8 @@
oneway void supplyNetworkDepersonalizationResponse(in android.hardware.radio.RadioResponseInfo info, in int remainingRetries);
oneway void setUsageSettingResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void getUsageSettingResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.UsageSetting usageSetting);
+ oneway void setEmergencyModeResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.EmergencyRegResult regState);
+ oneway void triggerEmergencyNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
+ oneway void exitEmergencyModeResponse(in android.hardware.radio.RadioResponseInfo info);
+ oneway void cancelEmergencyNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
}
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyMode.aidl b/radio/aidl/android/hardware/radio/network/EmergencyMode.aidl
new file mode 100644
index 0000000..25031a9
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/EmergencyMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum EmergencyMode {
+ /**
+ * Mode Type Emergency WWAN, indicates that the current domain selected for the Emergency call
+ * is cellular.
+ */
+ EMERGENCY_WWAN = 1,
+
+ /**
+ * Mode Type Emergency WLAN, indicates that the current domain selected for the Emergency call
+ * is WLAN/WIFI.
+ */
+ EMERGENCY_WLAN = 2,
+
+ /**
+ * Mode Type Emergency Callback, indicates that the current mode set request is for Emergency
+ * callback.
+ */
+ EMERGENCY_CALLBACK = 3,
+}
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl b/radio/aidl/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
new file mode 100644
index 0000000..0a22e4c
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+import android.hardware.radio.AccessNetwork;
+import android.hardware.radio.network.EmergencyScanType;
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable EmergencyNetworkScanTrigger{
+ /**
+ * Access network to be prioritized during emergency scan. The 1st entry has the highest
+ * priority.
+ */
+ AccessNetwork[] accessNetwork;
+
+ /**
+ * Scan type indicates the type of scans to be performed i.e. limited scan, full service scan or
+ * any scan.
+ */
+ EmergencyScanType scanType;
+}
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
new file mode 100644
index 0000000..cf5caa4
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+import android.hardware.radio.AccessNetwork;
+import android.hardware.radio.network.RegState;
+import android.hardware.radio.network.Domain;
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable EmergencyRegResult {
+ /**
+ * Indicates the cellular access network of the current emergency capable system.
+ */
+ AccessNetwork accessNetwork;
+
+ /**
+ * Registration state of the current emergency capable system.
+ */
+ RegState regState;
+
+ /**
+ * EMC domain indicates the current domain of the acquired system.
+ */
+ Domain emcDomain;
+
+ /**
+ * This indicates if camped network support VoLTE emergency bearers.
+ * This should only be set if the UE is in LTE mode.
+ */
+ boolean isEmcBearerSupported;
+
+ /**
+ * The value of the network provided EMC 5G Registration ACCEPT.
+ * This should be set only if the UE is in 5G mode.
+ */
+ byte nwProvidedEmc;
+
+ /**
+ * The value of the network provided EMF ( EPS Fallback) in 5G Registration ACCEPT.
+ * This should not be set if UE is not in 5G mode.
+ */
+ byte nwProvidedEmf;
+}
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyScanType.aidl b/radio/aidl/android/hardware/radio/network/EmergencyScanType.aidl
new file mode 100644
index 0000000..72c5490
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/EmergencyScanType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum EmergencyScanType {
+ /**
+ * Scan Type No Preference, indicates that the modem can scan for emergency
+ * service as per modem’s implementation.
+ */
+ NO_PREFERENCE = 0,
+
+ /**
+ * Scan Type limited, indicates that the modem will scan for
+ * emergency service in limited service mode.
+ */
+ LIMITED_SERVICE = 1,
+
+ /**
+ * Scan Type Full Service, indicates that the modem will scan for
+ * emergency service in Full service mode.
+ */
+ FULL_SERVICE = 2,
+}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index cce52ff..0ac8b0e 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -27,6 +27,8 @@
import android.hardware.radio.network.RadioBandMode;
import android.hardware.radio.network.SignalThresholdInfo;
import android.hardware.radio.network.UsageSetting;
+import android.hardware.radio.network.EmergencyNetworkScanTrigger;
+import android.hardware.radio.network.EmergencyMode;
/**
* This interface is used by telephony and telecom to talk to cellular radio for network APIs.
@@ -437,4 +439,44 @@
* @param serial Serial number of request.
*/
oneway void getUsageSetting(in int serial);
+
+ /**
+ * Set the Emergency Mode
+ *
+ * @param serial Serial number of the request.
+ * @param emcModeType Defines the radio emergency mode type/radio network required/
+ * type of service to be scanned.
+ *
+ * Response function is IRadioEmergencyResponse.setEmergencyModeResponse()
+ */
+ void setEmergencyMode(int serial, in EmergencyMode emcModeType );
+
+ /**
+ * Triggers an Emergency network scan.
+ *
+ * @param serial Serial number of the request.
+ * @param request Defines the radio target networks/preferred network/
+ * Max Scan Time and type of service to be scanned.
+ *
+ * Response function is IRadioEmergencyResponse.triggerEmergencyNetworkScanResponse()
+ */
+ void triggerEmergencyNetworkScan( int serial, in EmergencyNetworkScanTrigger request);
+
+ /**
+ * Cancels ongoing Emergency network scan
+ *
+ * @param serial Serial number of the request.
+ *
+ * Response function is IRadioEmergencyResponse.cancelEmergencyNetworkScan()
+ */
+ void cancelEmergencyNetworkScan(in int serial);
+
+ /**
+ * Exits ongoing Emergency Mode
+ *
+ * @param serial Serial number of the request.
+ *
+ * Response function is IRadioEmergencyResponse.exitEmergencyModeResponse()
+ */
+ void exitEmergencyMode(in int serial);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
index f471433..47d932d 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -27,6 +27,7 @@
import android.hardware.radio.network.PhysicalChannelConfig;
import android.hardware.radio.network.SignalStrength;
import android.hardware.radio.network.SuppSvcNotification;
+import android.hardware.radio.network.EmergencyRegResult;
/**
* Interface declaring unsolicited radio indications for network APIs.
@@ -190,4 +191,12 @@
* @param rat Current new voice rat
*/
void voiceRadioTechChanged(in RadioIndicationType type, in RadioTechnology rat);
+
+ /**
+ * Emergency Scan Results.
+ *
+ * @param type Type of radio indication
+ * @param result the result of the Emergency Network Scan
+ */
+ void emergencyNetworkScanResult(in RadioIndicationType type, in EmergencyRegResult result);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index dcf0004..d98a31b 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -29,6 +29,7 @@
import android.hardware.radio.network.RegStateResult;
import android.hardware.radio.network.SignalStrength;
import android.hardware.radio.network.UsageSetting;
+import android.hardware.radio.network.EmergencyRegResult;
/**
* Interface declaring response functions to solicited radio requests for network APIs.
@@ -572,4 +573,51 @@
* RadioError:SIM_ABSENT
*/
oneway void getUsageSettingResponse(in RadioResponseInfo info, in UsageSetting usageSetting);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error.
+ * @param regState the current registration state of the modem.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:MODEM_ERR
+ * RadioError:INVALID_ARGUMENTS
+ */
+ void setEmergencyModeResponse(in RadioResponseInfo info, in EmergencyRegResult regState);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:MODEM_ERR
+ * RadioError:INVALID_ARGUMENTS
+ */
+ void triggerEmergencyNetworkScanResponse(in RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:MODEM_ERR
+ */
+ void exitEmergencyModeResponse(in RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:MODEM_ERR
+ */
+ void cancelEmergencyNetworkScanResponse(in RadioResponseInfo info);
}
diff --git a/sensors/aidl/android/hardware/sensors/ISensors.aidl b/sensors/aidl/android/hardware/sensors/ISensors.aidl
index 2ac1884..2c68489 100644
--- a/sensors/aidl/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/android/hardware/sensors/ISensors.aidl
@@ -229,8 +229,7 @@
*
* @param mem shared memory info data structure.
* @param out channelHandle The registered channel handle.
- * @return The direct channel handle, which is positive if successfully registered, and -1
- * otherwise.
+ * @return The direct channel handle, which is positive if successfully registered.
* @return Status::ok on success
* EX_ILLEGAL_ARGUMENT if the shared memory information is not consistent.
* EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
@@ -245,7 +244,7 @@
* @see OperationMode
* @param mode The operation mode.
* @return Status::ok on success
- * EX_UNSUPPORTED_OPERATION if requested mode is not supported.
+ * EX_UNSUPPORTED_OPERATION or EX_ILLEGAL_ARGUMENT if requested mode is not supported.
* EX_SECURITY if the operation is not allowed.
*/
void setOperationMode(in OperationMode mode);
diff --git a/sensors/aidl/default/multihal/HalProxyAidl.cpp b/sensors/aidl/default/multihal/HalProxyAidl.cpp
index 628914c..e6bcdad 100644
--- a/sensors/aidl/default/multihal/HalProxyAidl.cpp
+++ b/sensors/aidl/default/multihal/HalProxyAidl.cpp
@@ -141,10 +141,6 @@
*_aidl_return = reportToken;
});
- if (!status.isOk()) {
- *_aidl_return = -1;
- }
-
return status;
}
@@ -216,10 +212,6 @@
native_handle_delete(const_cast<native_handle_t *>(
sharedMemInfo.memoryHandle.getNativeHandle()));
- if (!status.isOk()) {
- *_aidl_return = -1;
- }
-
return status;
}
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index 83d0dc9..d536e29 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -599,10 +599,12 @@
ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::DATA_INJECTION).isOk());
ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
} else {
- ASSERT_EQ(getSensors()
- ->setOperationMode(ISensors::OperationMode::DATA_INJECTION)
- .getExceptionCode(),
- EX_UNSUPPORTED_OPERATION);
+ int errorCode =
+ getSensors()
+ ->setOperationMode(ISensors::OperationMode::DATA_INJECTION)
+ .getExceptionCode();
+ ASSERT_TRUE((errorCode == EX_UNSUPPORTED_OPERATION) ||
+ (errorCode == EX_ILLEGAL_ARGUMENT));
}
}
@@ -938,10 +940,10 @@
if (isDirectReportRateSupported(sensor, rateLevel)) {
ASSERT_TRUE(status.isOk());
if (rateLevel != ISensors::RateLevel::STOP) {
- ASSERT_GT(*reportToken, 0);
- } else {
- ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ ASSERT_GT(*reportToken, 0);
}
+ } else {
+ ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
}
}
@@ -982,11 +984,15 @@
::ndk::ScopedAStatus status = registerDirectChannel(mem->getSharedMemInfo(), &channelHandle);
if (supportsSharedMemType) {
ASSERT_TRUE(status.isOk());
- ASSERT_EQ(channelHandle, 0);
+ ASSERT_GT(channelHandle, 0);
+
+ // Verify that the memory has been zeroed
+ for (size_t i = 0; i < mem->getSize(); i++) {
+ ASSERT_EQ(buffer[i], 0x00);
+ }
} else {
int32_t error = supportsAnyDirectChannel ? EX_ILLEGAL_ARGUMENT : EX_UNSUPPORTED_OPERATION;
ASSERT_EQ(status.getExceptionCode(), error);
- ASSERT_EQ(channelHandle, -1);
}
*directChannelHandle = channelHandle;
}
@@ -1038,7 +1044,7 @@
// Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
ndk::ScopedAStatus status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
ISensors::RateLevel::NORMAL, &reportToken);
- ASSERT_EQ(status.getServiceSpecificError(), android::BAD_VALUE);
+ ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
ISensors::RateLevel::STOP, &reportToken);
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 2cc1e6a..36cde9b 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -14,6 +14,7 @@
vendor_available: true,
srcs: ["android/hardware/uwb/*.aidl"],
stability: "vintf",
+ host_supported: true,
backend: {
java: {
sdk_version: "module_Tiramisu",
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index acdbdcd..c4140be 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -63,7 +63,6 @@
"libbinder_random_parcel",
"libcutils",
"liblog",
- "libutils",
"libvibratorexampleimpl",
],
target: {
@@ -71,12 +70,14 @@
shared_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
host: {
static_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
darwin: {
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
index 7f0e97d..f062409 100644
--- a/wifi/1.6/default/wifi_chip.cpp
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -1003,14 +1003,14 @@
br_ifaces_ap_instances_[br_ifname] = ap_instances;
if (!iface_util_->createBridge(br_ifname)) {
LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
- invalidateAndClearBridgedAp(br_ifname);
+ deleteApIface(br_ifname);
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
for (auto const& instance : ap_instances) {
// Bind ap instance interface to AP bridge
if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
- invalidateAndClearBridgedAp(br_ifname);
+ deleteApIface(br_ifname);
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
}
@@ -1044,8 +1044,7 @@
// nan/rtt objects over AP iface. But, there is no harm to do it
// here and not make that assumption all over the place.
invalidateAndRemoveDependencies(ifname);
- // Clear the bridge interface and the iface instance.
- invalidateAndClearBridgedAp(ifname);
+ deleteApIface(ifname);
invalidateAndClear(ap_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
@@ -2005,21 +2004,28 @@
br_ifaces_ap_instances_.clear();
}
-void WifiChip::invalidateAndClearBridgedAp(const std::string& br_name) {
- if (br_name.empty()) return;
- // delete managed interfaces
+void WifiChip::deleteApIface(const std::string& if_name) {
+ if (if_name.empty()) return;
+ // delete bridged interfaces if have
for (auto const& it : br_ifaces_ap_instances_) {
- if (it.first == br_name) {
+ if (it.first == if_name) {
for (auto const& iface : it.second) {
- iface_util_->removeIfaceFromBridge(br_name, iface);
+ iface_util_->removeIfaceFromBridge(if_name, iface);
legacy_hal_.lock()->deleteVirtualInterface(iface);
}
- iface_util_->deleteBridge(br_name);
- br_ifaces_ap_instances_.erase(br_name);
- break;
+ iface_util_->deleteBridge(if_name);
+ br_ifaces_ap_instances_.erase(if_name);
+ // ifname is bridged AP, return here.
+ return;
}
}
- return;
+
+ // No bridged AP case, delete AP iface
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(if_name);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to remove interface: " << if_name << " "
+ << legacyErrorToString(legacy_status);
+ }
}
bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
diff --git a/wifi/1.6/default/wifi_chip.h b/wifi/1.6/default/wifi_chip.h
index f952a68..e8ddaa6 100644
--- a/wifi/1.6/default/wifi_chip.h
+++ b/wifi/1.6/default/wifi_chip.h
@@ -272,7 +272,7 @@
bool writeRingbufferFilesInternal();
std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
void invalidateAndClearBridgedApAll();
- void invalidateAndClearBridgedAp(const std::string& br_name);
+ void deleteApIface(const std::string& if_name);
bool findUsingNameFromBridgedApInstances(const std::string& name);
WifiStatus triggerSubsystemRestartInternal();
std::pair<WifiStatus, sp<V1_6::IWifiRttController>> createRttControllerInternal_1_6(