Merge "Fix remaining instrumentation tests."
diff --git a/audio/2.0/Android.bp b/audio/2.0/Android.bp
index 1643c12..d6e481f 100644
--- a/audio/2.0/Android.bp
+++ b/audio/2.0/Android.bp
@@ -18,6 +18,7 @@
],
interfaces: [
"android.hardware.audio.common@2.0",
+ "android.hardware.audio.effect@2.0",
"android.hidl.base@1.0",
],
types: [
diff --git a/automotive/vehicle/2.0/IVehicle.hal b/automotive/vehicle/2.0/IVehicle.hal
index d962de0..1b1d391 100644
--- a/automotive/vehicle/2.0/IVehicle.hal
+++ b/automotive/vehicle/2.0/IVehicle.hal
@@ -43,7 +43,7 @@
* For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the
* latest available value.
*
- * Some properties like AUDIO_VOLUME requires to pass additional data in
+ * Some properties like RADIO_PRESET requires to pass additional data in
* GET request in VehiclePropValue object.
*
* If there is no data available yet, which can happen during initial stage,
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp
index 295ee32..dfbb976 100644
--- a/camera/device/3.2/default/CameraDevice.cpp
+++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -40,9 +40,11 @@
mCameraDeviceNames(cameraDeviceNames) {
mCameraIdInt = atoi(mCameraId.c_str());
// Should not reach here as provider also validate ID
- if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) {
+ if (mCameraIdInt < 0) {
ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str());
mInitFail = true;
+ } else if (mCameraIdInt >= mModule->getNumberOfCameras()) {
+ ALOGI("%s: Adding a new camera id: %s", __FUNCTION__, mCameraId.c_str());
}
mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt);
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index 3027555..5c01e35 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -53,6 +53,15 @@
ANDROID_LENS_END_3_3,
+ /** android.request.availableSessionKeys [static, int32[], ndk_public]
+ *
+ * <p>A subset of the available request keys that the camera device
+ * can pass as part of the capture session initialization.</p>
+ */
+ ANDROID_REQUEST_AVAILABLE_SESSION_KEYS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_REQUEST_END,
+
+ ANDROID_REQUEST_END_3_3,
+
/** android.info.version [static, byte, public]
*
* <p>A short string for manufacturer version information about the camera device, such as
@@ -68,6 +77,14 @@
* Enumeration definitions for the various entries that need them
*/
+/** android.control.aeMode enumeration values added since v3.2
+ * @see ANDROID_CONTROL_AE_MODE
+ */
+enum CameraMetadataEnumAndroidControlAeMode :
+ @3.2::CameraMetadataEnumAndroidControlAeMode {
+ ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH,
+};
+
/** android.control.captureIntent enumeration values added since v3.2
* @see ANDROID_CONTROL_CAPTURE_INTENT
*/
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index ed974a5..e9588a7 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -66,6 +66,46 @@
using ::android::hardware::camera::common::V1_0::CameraMetadataType;
using ::android::hardware::camera::common::V1_0::Status;
+void CameraProvider::addDeviceNames(int camera_id, CameraDeviceStatus status, bool cam_new)
+{
+ char cameraId[kMaxCameraIdLen];
+ snprintf(cameraId, sizeof(cameraId), "%d", camera_id);
+ std::string cameraIdStr(cameraId);
+
+ mCameraIds.add(cameraIdStr);
+
+ // initialize mCameraDeviceNames and mOpenLegacySupported
+ mOpenLegacySupported[cameraIdStr] = false;
+ int deviceVersion = mModule->getDeviceVersion(camera_id);
+ auto deviceNamePair = std::make_pair(cameraIdStr,
+ getHidlDeviceName(cameraIdStr, deviceVersion));
+ mCameraDeviceNames.add(deviceNamePair);
+ if (cam_new) {
+ mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status);
+ }
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
+ mModule->isOpenLegacyDefined()) {
+ // try open_legacy to see if it actually works
+ struct hw_device_t* halDev = nullptr;
+ int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
+ if (ret == 0) {
+ mOpenLegacySupported[cameraIdStr] = true;
+ halDev->close(halDev);
+ deviceNamePair = std::make_pair(cameraIdStr,
+ getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0));
+ mCameraDeviceNames.add(deviceNamePair);
+ if (cam_new) {
+ mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status);
+ }
+ } else if (ret == -EBUSY || ret == -EUSERS) {
+ // Looks like this provider instance is not initialized during
+ // system startup and there are other camera users already.
+ // Not a good sign but not fatal.
+ ALOGW("%s: open_legacy try failed!", __FUNCTION__);
+ }
+ }
+}
+
/**
* static callback forwarding methods from HAL to instance
*/
@@ -75,6 +115,7 @@
int new_status) {
CameraProvider* cp = const_cast<CameraProvider*>(
static_cast<const CameraProvider*>(callbacks));
+ bool found = false;
if (cp == nullptr) {
ALOGE("%s: callback ops is null", __FUNCTION__);
@@ -92,8 +133,13 @@
if (cameraIdStr.compare(deviceNamePair.first) == 0) {
cp->mCallbacks->cameraDeviceStatusChange(
deviceNamePair.second, status);
+ found = true;
}
}
+
+ if (!found) {
+ cp->addDeviceNames(camera_id, status, true);
+ }
}
}
@@ -251,32 +297,8 @@
snprintf(cameraId, sizeof(cameraId), "%d", i);
std::string cameraIdStr(cameraId);
mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;
- mCameraIds.add(cameraIdStr);
- // initialize mCameraDeviceNames and mOpenLegacySupported
- mOpenLegacySupported[cameraIdStr] = false;
- int deviceVersion = mModule->getDeviceVersion(i);
- mCameraDeviceNames.add(
- std::make_pair(cameraIdStr,
- getHidlDeviceName(cameraIdStr, deviceVersion)));
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
- mModule->isOpenLegacyDefined()) {
- // try open_legacy to see if it actually works
- struct hw_device_t* halDev = nullptr;
- int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
- if (ret == 0) {
- mOpenLegacySupported[cameraIdStr] = true;
- halDev->close(halDev);
- mCameraDeviceNames.add(
- std::make_pair(cameraIdStr,
- getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)));
- } else if (ret == -EBUSY || ret == -EUSERS) {
- // Looks like this provider instance is not initialized during
- // system startup and there are other camera users already.
- // Not a good sign but not fatal.
- ALOGW("%s: open_legacy try failed!", __FUNCTION__);
- }
- }
+ addDeviceNames(i);
}
return false; // mInitFailed
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h
index 4980711..2cf251e 100644
--- a/camera/provider/2.4/default/CameraProvider.h
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -112,6 +112,9 @@
const struct camera_module_callbacks* callbacks,
const char* camera_id,
int new_status);
+
+ void addDeviceNames(int camera_id, CameraDeviceStatus status = CameraDeviceStatus::PRESENT,
+ bool cam_new = false);
};
extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name);
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 1aaef1e..c444dde 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -229,7 +229,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.power</name>
- <version>1.0-1</version>
+ <version>1.0-2</version>
<interface>
<name>IPower</name>
<instance>default</instance>
diff --git a/current.txt b/current.txt
index c18153a..a5ab307 100644
--- a/current.txt
+++ b/current.txt
@@ -255,4 +255,4 @@
fb92e2b40f8e9d494e8fd3b4ac18499a3216342e7cff160714c3bbf3660b6e79 android.hardware.gnss@1.0::IGnssConfiguration
251594ea9b27447bfa005ebd806e58fb0ae4aad84a69938129c9800ec0c64eda android.hardware.gnss@1.0::IGnssMeasurementCallback
4e7169919d24fbe5573e5bcd683d0bd7abf553a4e6c34c41f9dfc1e12050db07 android.hardware.gnss@1.0::IGnssNavigationMessageCallback
-
+b280c4704dfcc548a9bf127b59b7c3578f460c50cce70a06b66fe0df8b27cff0 android.hardware.wifi@1.0::types
diff --git a/graphics/allocator/2.0/default/Android.bp b/graphics/allocator/2.0/default/Android.bp
index 9968f41..ed2ecbb 100644
--- a/graphics/allocator/2.0/default/Android.bp
+++ b/graphics/allocator/2.0/default/Android.bp
@@ -1,10 +1,15 @@
cc_library_shared {
name: "android.hardware.graphics.allocator@2.0-impl",
defaults: ["hidl_defaults"],
- proprietary: true,
+ vendor: true,
relative_install_path: "hw",
- srcs: ["Gralloc.cpp", "Gralloc0Allocator.cpp", "Gralloc1Allocator.cpp"],
- cppflags: ["-Wall", "-Wextra"],
+ srcs: ["passthrough.cpp"],
+ static_libs: [
+ "android.hardware.graphics.allocator@2.0-passthrough",
+ ],
+ header_libs: [
+ "android.hardware.graphics.allocator@2.0-hal",
+ ],
shared_libs: [
"android.hardware.graphics.allocator@2.0",
"libbase",
@@ -15,9 +20,6 @@
"liblog",
"libutils",
],
- header_libs: [
- "libgrallocmapperincludes",
- ],
}
cc_binary {
@@ -36,13 +38,3 @@
"libutils",
],
}
-
-cc_library_static {
- name: "libgralloc1-adapter",
- defaults: ["hidl_defaults"],
- srcs: ["gralloc1-adapter.cpp", "Gralloc1On0Adapter.cpp"],
- include_dirs: ["system/core/libsync/include"],
- cflags: ["-Wall", "-Wextra"],
- export_include_dirs: ["."],
- whole_static_libs: ["libgrallocusage"],
-}
diff --git a/graphics/allocator/2.0/default/Gralloc.cpp b/graphics/allocator/2.0/default/Gralloc.cpp
deleted file mode 100644
index 273d3f5..0000000
--- a/graphics/allocator/2.0/default/Gralloc.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GrallocPassthrough"
-
-#include "Gralloc.h"
-#include "Gralloc0Allocator.h"
-#include "Gralloc1Allocator.h"
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
- const hw_module_t* module = nullptr;
- int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
- if (err) {
- ALOGE("failed to get gralloc module");
- return nullptr;
- }
-
- uint8_t major = (module->module_api_version >> 8) & 0xff;
- switch (major) {
- case 1:
- return new Gralloc1Allocator(module);
- case 0:
- return new Gralloc0Allocator(module);
- default:
- ALOGE("unknown gralloc module major version %d", major);
- return nullptr;
- }
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc.h b/graphics/allocator/2.0/default/Gralloc.h
deleted file mode 100644
index c79eeaa..0000000
--- a/graphics/allocator/2.0/default/Gralloc.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
-#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-extern "C" IAllocator* HIDL_FETCH_IAllocator(const char* name);
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
diff --git a/graphics/allocator/2.0/default/Gralloc0Allocator.cpp b/graphics/allocator/2.0/default/Gralloc0Allocator.cpp
deleted file mode 100644
index 3b62bb3..0000000
--- a/graphics/allocator/2.0/default/Gralloc0Allocator.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Gralloc0Allocator"
-
-#include "Gralloc0Allocator.h"
-#include "GrallocBufferDescriptor.h"
-
-#include <vector>
-
-#include <string.h>
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::mapper::V2_0::implementation::
- grallocDecodeBufferDescriptor;
-
-Gralloc0Allocator::Gralloc0Allocator(const hw_module_t* module) {
- int result = gralloc_open(module, &mDevice);
- if (result) {
- LOG_ALWAYS_FATAL("failed to open gralloc0 device: %s",
- strerror(-result));
- }
-}
-
-Gralloc0Allocator::~Gralloc0Allocator() {
- gralloc_close(mDevice);
-}
-
-Return<void> Gralloc0Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
- char buf[4096] = {};
- if (mDevice->dump) {
- mDevice->dump(mDevice, buf, sizeof(buf));
- buf[sizeof(buf) - 1] = '\0';
- }
-
- hidl_cb(hidl_string(buf));
-
- return Void();
-}
-
-Return<void> Gralloc0Allocator::allocate(const BufferDescriptor& descriptor,
- uint32_t count, allocate_cb hidl_cb) {
- IMapper::BufferDescriptorInfo descriptorInfo;
- if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
- hidl_cb(Error::BAD_DESCRIPTOR, 0, hidl_vec<hidl_handle>());
- return Void();
- }
-
- Error error = Error::NONE;
- uint32_t stride = 0;
- std::vector<hidl_handle> buffers;
- buffers.reserve(count);
-
- // allocate the buffers
- for (uint32_t i = 0; i < count; i++) {
- buffer_handle_t tmpBuffer;
- uint32_t tmpStride;
- error = allocateOne(descriptorInfo, &tmpBuffer, &tmpStride);
- if (error != Error::NONE) {
- break;
- }
-
- if (stride == 0) {
- stride = tmpStride;
- } else if (stride != tmpStride) {
- // non-uniform strides
- mDevice->free(mDevice, tmpBuffer);
- stride = 0;
- error = Error::UNSUPPORTED;
- break;
- }
-
- buffers.emplace_back(hidl_handle(tmpBuffer));
- }
-
- // return the buffers
- hidl_vec<hidl_handle> hidl_buffers;
- if (error == Error::NONE) {
- hidl_buffers.setToExternal(buffers.data(), buffers.size());
- }
- hidl_cb(error, stride, hidl_buffers);
-
- // free the buffers
- for (const auto& buffer : buffers) {
- mDevice->free(mDevice, buffer.getNativeHandle());
- }
-
- return Void();
-}
-
-Error Gralloc0Allocator::allocateOne(const IMapper::BufferDescriptorInfo& info,
- buffer_handle_t* outBuffer,
- uint32_t* outStride) {
- if (info.layerCount > 1 || (info.usage >> 32) != 0) {
- return Error::BAD_VALUE;
- }
-
- buffer_handle_t buffer = nullptr;
- int stride = 0;
- int result = mDevice->alloc(mDevice, info.width, info.height,
- static_cast<int>(info.format), info.usage,
- &buffer, &stride);
- if (result) {
- switch (result) {
- case -EINVAL:
- return Error::BAD_VALUE;
- default:
- return Error::NO_RESOURCES;
- }
- }
-
- *outBuffer = buffer;
- *outStride = stride;
-
- return Error::NONE;
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc0Allocator.h b/graphics/allocator/2.0/default/Gralloc0Allocator.h
deleted file mode 100644
index 0e90527..0000000
--- a/graphics/allocator/2.0/default/Gralloc0Allocator.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
-#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <hardware/gralloc.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using android::hardware::graphics::mapper::V2_0::Error;
-
-class Gralloc0Allocator : public IAllocator {
- public:
- Gralloc0Allocator(const hw_module_t* module);
- virtual ~Gralloc0Allocator();
-
- // IAllocator interface
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
- allocate_cb hidl_cb) override;
-
- private:
- Error allocateOne(const IMapper::BufferDescriptorInfo& info,
- buffer_handle_t* outBuffer, uint32_t* outStride);
-
- alloc_device_t* mDevice;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
diff --git a/graphics/allocator/2.0/default/Gralloc1Allocator.cpp b/graphics/allocator/2.0/default/Gralloc1Allocator.cpp
deleted file mode 100644
index 6cbb791..0000000
--- a/graphics/allocator/2.0/default/Gralloc1Allocator.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Gralloc1Allocator"
-
-#include "Gralloc1Allocator.h"
-#include "GrallocBufferDescriptor.h"
-
-#include <vector>
-
-#include <string.h>
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::common::V1_0::BufferUsage;
-using android::hardware::graphics::mapper::V2_0::implementation::
- grallocDecodeBufferDescriptor;
-
-Gralloc1Allocator::Gralloc1Allocator(const hw_module_t* module)
- : mDevice(nullptr), mCapabilities(), mDispatch() {
- int result = gralloc1_open(module, &mDevice);
- if (result) {
- LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
- strerror(-result));
- }
-
- initCapabilities();
- initDispatch();
-}
-
-Gralloc1Allocator::~Gralloc1Allocator() {
- gralloc1_close(mDevice);
-}
-
-void Gralloc1Allocator::initCapabilities() {
- uint32_t count = 0;
- mDevice->getCapabilities(mDevice, &count, nullptr);
-
- std::vector<int32_t> capabilities(count);
- mDevice->getCapabilities(mDevice, &count, capabilities.data());
- capabilities.resize(count);
-
- for (auto capability : capabilities) {
- if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
- mCapabilities.layeredBuffers = true;
- break;
- }
- }
-}
-
-template <typename T>
-void Gralloc1Allocator::initDispatch(gralloc1_function_descriptor_t desc,
- T* outPfn) {
- auto pfn = mDevice->getFunction(mDevice, desc);
- if (!pfn) {
- LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
- }
-
- *outPfn = reinterpret_cast<T>(pfn);
-}
-
-void Gralloc1Allocator::initDispatch() {
- initDispatch(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump);
- initDispatch(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR,
- &mDispatch.createDescriptor);
- initDispatch(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR,
- &mDispatch.destroyDescriptor);
- initDispatch(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions);
- initDispatch(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat);
- if (mCapabilities.layeredBuffers) {
- initDispatch(GRALLOC1_FUNCTION_SET_LAYER_COUNT,
- &mDispatch.setLayerCount);
- }
- initDispatch(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE,
- &mDispatch.setConsumerUsage);
- initDispatch(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE,
- &mDispatch.setProducerUsage);
- initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride);
- initDispatch(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate);
- initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
-}
-
-Return<void> Gralloc1Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
- uint32_t len = 0;
- mDispatch.dump(mDevice, &len, nullptr);
-
- std::vector<char> buf(len + 1);
- mDispatch.dump(mDevice, &len, buf.data());
- buf.resize(len + 1);
- buf[len] = '\0';
-
- hidl_string reply;
- reply.setToExternal(buf.data(), len);
- hidl_cb(reply);
-
- return Void();
-}
-
-Return<void> Gralloc1Allocator::allocate(const BufferDescriptor& descriptor,
- uint32_t count, allocate_cb hidl_cb) {
- IMapper::BufferDescriptorInfo descriptorInfo;
- if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
- hidl_cb(Error::BAD_DESCRIPTOR, 0, hidl_vec<hidl_handle>());
- return Void();
- }
-
- gralloc1_buffer_descriptor_t desc;
- Error error = createDescriptor(descriptorInfo, &desc);
- if (error != Error::NONE) {
- hidl_cb(error, 0, hidl_vec<hidl_handle>());
- return Void();
- }
-
- uint32_t stride = 0;
- std::vector<hidl_handle> buffers;
- buffers.reserve(count);
-
- // allocate the buffers
- for (uint32_t i = 0; i < count; i++) {
- buffer_handle_t tmpBuffer;
- uint32_t tmpStride;
- error = allocateOne(desc, &tmpBuffer, &tmpStride);
- if (error != Error::NONE) {
- break;
- }
-
- if (stride == 0) {
- stride = tmpStride;
- } else if (stride != tmpStride) {
- // non-uniform strides
- mDispatch.release(mDevice, tmpBuffer);
- stride = 0;
- error = Error::UNSUPPORTED;
- break;
- }
-
- buffers.emplace_back(hidl_handle(tmpBuffer));
- }
-
- mDispatch.destroyDescriptor(mDevice, desc);
-
- // return the buffers
- hidl_vec<hidl_handle> hidl_buffers;
- if (error == Error::NONE) {
- hidl_buffers.setToExternal(buffers.data(), buffers.size());
- }
- hidl_cb(error, stride, hidl_buffers);
-
- // free the buffers
- for (const auto& buffer : buffers) {
- mDispatch.release(mDevice, buffer.getNativeHandle());
- }
-
- return Void();
-}
-
-Error Gralloc1Allocator::toError(int32_t error) {
- switch (error) {
- case GRALLOC1_ERROR_NONE:
- return Error::NONE;
- case GRALLOC1_ERROR_BAD_DESCRIPTOR:
- return Error::BAD_DESCRIPTOR;
- case GRALLOC1_ERROR_BAD_HANDLE:
- return Error::BAD_BUFFER;
- case GRALLOC1_ERROR_BAD_VALUE:
- return Error::BAD_VALUE;
- case GRALLOC1_ERROR_NOT_SHARED:
- return Error::NONE; // this is fine
- case GRALLOC1_ERROR_NO_RESOURCES:
- return Error::NO_RESOURCES;
- case GRALLOC1_ERROR_UNDEFINED:
- case GRALLOC1_ERROR_UNSUPPORTED:
- default:
- return Error::UNSUPPORTED;
- }
-}
-
-uint64_t Gralloc1Allocator::toProducerUsage(uint64_t usage) {
- // this is potentially broken as we have no idea which private flags
- // should be filtered out
- uint64_t producerUsage =
- usage &
- ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
- BufferUsage::GPU_DATA_BUFFER);
-
- switch (usage & BufferUsage::CPU_WRITE_MASK) {
- case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
- producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
- break;
- case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
- producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
- break;
- default:
- break;
- }
-
- switch (usage & BufferUsage::CPU_READ_MASK) {
- case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
- producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
- break;
- case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
- producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
- break;
- default:
- break;
- }
-
- // BufferUsage::GPU_DATA_BUFFER is always filtered out
-
- return producerUsage;
-}
-
-uint64_t Gralloc1Allocator::toConsumerUsage(uint64_t usage) {
- // this is potentially broken as we have no idea which private flags
- // should be filtered out
- uint64_t consumerUsage =
- usage &
- ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
- BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER);
-
- switch (usage & BufferUsage::CPU_READ_MASK) {
- case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
- consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
- break;
- case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
- consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
- break;
- default:
- break;
- }
-
- // BufferUsage::SENSOR_DIRECT_DATA is always filtered out
-
- if (usage & BufferUsage::GPU_DATA_BUFFER) {
- consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
- }
-
- return consumerUsage;
-}
-
-Error Gralloc1Allocator::createDescriptor(
- const IMapper::BufferDescriptorInfo& info,
- gralloc1_buffer_descriptor_t* outDescriptor) {
- gralloc1_buffer_descriptor_t descriptor;
-
- int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);
-
- if (error == GRALLOC1_ERROR_NONE) {
- error = mDispatch.setDimensions(mDevice, descriptor, info.width,
- info.height);
- }
- if (error == GRALLOC1_ERROR_NONE) {
- error = mDispatch.setFormat(mDevice, descriptor,
- static_cast<int32_t>(info.format));
- }
- if (error == GRALLOC1_ERROR_NONE) {
- if (mCapabilities.layeredBuffers) {
- error =
- mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
- } else if (info.layerCount > 1) {
- error = GRALLOC1_ERROR_UNSUPPORTED;
- }
- }
- if (error == GRALLOC1_ERROR_NONE) {
- error = mDispatch.setProducerUsage(mDevice, descriptor,
- toProducerUsage(info.usage));
- }
- if (error == GRALLOC1_ERROR_NONE) {
- error = mDispatch.setConsumerUsage(mDevice, descriptor,
- toConsumerUsage(info.usage));
- }
-
- if (error == GRALLOC1_ERROR_NONE) {
- *outDescriptor = descriptor;
- } else {
- mDispatch.destroyDescriptor(mDevice, descriptor);
- }
-
- return toError(error);
-}
-
-Error Gralloc1Allocator::allocateOne(gralloc1_buffer_descriptor_t descriptor,
- buffer_handle_t* outBuffer,
- uint32_t* outStride) {
- buffer_handle_t buffer = nullptr;
- int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
- if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
- return toError(error);
- }
-
- uint32_t stride = 0;
- error = mDispatch.getStride(mDevice, buffer, &stride);
- if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
- mDispatch.release(mDevice, buffer);
- return toError(error);
- }
-
- *outBuffer = buffer;
- *outStride = stride;
-
- return Error::NONE;
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc1Allocator.h b/graphics/allocator/2.0/default/Gralloc1Allocator.h
deleted file mode 100644
index 7b5a966..0000000
--- a/graphics/allocator/2.0/default/Gralloc1Allocator.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
-#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <hardware/gralloc1.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using android::hardware::graphics::mapper::V2_0::Error;
-
-class Gralloc1Allocator : public IAllocator {
- public:
- Gralloc1Allocator(const hw_module_t* module);
- virtual ~Gralloc1Allocator();
-
- // IAllocator interface
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
- allocate_cb hidl_cb) override;
-
- private:
- void initCapabilities();
-
- template <typename T>
- void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
- void initDispatch();
-
- static Error toError(int32_t error);
- static uint64_t toProducerUsage(uint64_t usage);
- static uint64_t toConsumerUsage(uint64_t usage);
-
- Error createDescriptor(const IMapper::BufferDescriptorInfo& info,
- gralloc1_buffer_descriptor_t* outDescriptor);
- Error allocateOne(gralloc1_buffer_descriptor_t descriptor,
- buffer_handle_t* outBuffer, uint32_t* outStride);
-
- gralloc1_device_t* mDevice;
-
- struct {
- bool layeredBuffers;
- } mCapabilities;
-
- struct {
- GRALLOC1_PFN_DUMP dump;
- GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor;
- GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor;
- GRALLOC1_PFN_SET_DIMENSIONS setDimensions;
- GRALLOC1_PFN_SET_FORMAT setFormat;
- GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount;
- GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage;
- GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage;
- GRALLOC1_PFN_GET_STRIDE getStride;
- GRALLOC1_PFN_ALLOCATE allocate;
- GRALLOC1_PFN_RELEASE release;
- } mDispatch;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
diff --git a/graphics/allocator/2.0/default/passthrough.cpp b/graphics/allocator/2.0/default/passthrough.cpp
new file mode 100644
index 0000000..132cab3
--- /dev/null
+++ b/graphics/allocator/2.0/default/passthrough.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/GrallocLoader.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::allocator::V2_0::passthrough::GrallocLoader;
+
+extern "C" IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
+ return GrallocLoader::load();
+}
diff --git a/graphics/allocator/2.0/default/service.cpp b/graphics/allocator/2.0/default/service.cpp
index 99f462c..bc0539a 100644
--- a/graphics/allocator/2.0/default/service.cpp
+++ b/graphics/allocator/2.0/default/service.cpp
@@ -20,8 +20,8 @@
#include <hidl/LegacySupport.h>
-using android::hardware::graphics::allocator::V2_0::IAllocator;
using android::hardware::defaultPassthroughServiceImplementation;
+using android::hardware::graphics::allocator::V2_0::IAllocator;
int main() {
return defaultPassthroughServiceImplementation<IAllocator>(4);
diff --git a/graphics/allocator/2.0/utils/OWNERS b/graphics/allocator/2.0/utils/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/allocator/2.0/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/allocator/2.0/utils/gralloc1-adapter/Android.bp b/graphics/allocator/2.0/utils/gralloc1-adapter/Android.bp
new file mode 100644
index 0000000..9cb53e3
--- /dev/null
+++ b/graphics/allocator/2.0/utils/gralloc1-adapter/Android.bp
@@ -0,0 +1,10 @@
+cc_library_static {
+ name: "libgralloc1-adapter",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ srcs: ["gralloc1-adapter.cpp", "Gralloc1On0Adapter.cpp"],
+ include_dirs: ["system/core/libsync/include"],
+ export_include_dirs: ["."],
+ whole_static_libs: ["libgrallocusage"],
+ shared_libs: ["libhardware", "liblog"],
+}
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp b/graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.cpp
similarity index 99%
rename from graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp
rename to graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.cpp
index 041ce77..b7ed58c 100644
--- a/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp
+++ b/graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.cpp
@@ -29,6 +29,7 @@
#include <sync/sync.h>
#include <inttypes.h>
+#include <unistd.h>
template <typename PFN, typename T>
static gralloc1_function_pointer_t asFP(T function)
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.h b/graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.h
similarity index 100%
rename from graphics/allocator/2.0/default/Gralloc1On0Adapter.h
rename to graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.h
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.cpp b/graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.cpp
similarity index 100%
rename from graphics/allocator/2.0/default/gralloc1-adapter.cpp
rename to graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.cpp
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.h b/graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.h
similarity index 100%
rename from graphics/allocator/2.0/default/gralloc1-adapter.h
rename to graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.h
diff --git a/graphics/allocator/2.0/utils/hal/Android.bp b/graphics/allocator/2.0/utils/hal/Android.bp
new file mode 100644
index 0000000..ac642ce
--- /dev/null
+++ b/graphics/allocator/2.0/utils/hal/Android.bp
@@ -0,0 +1,14 @@
+cc_library_headers {
+ name: "android.hardware.graphics.allocator@2.0-hal",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h
new file mode 100644
index 0000000..2f3022e
--- /dev/null
+++ b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Allocator.h included without LOG_TAG"
+#endif
+
+#include <memory>
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace hal {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+namespace detail {
+
+// AllocatorImpl implements IAllocator on top of AllocatorHal
+template <typename IALLOCATOR, typename ALLOCATOR_HAL>
+class AllocatorImpl : public IALLOCATOR {
+ public:
+ bool init(std::unique_ptr<ALLOCATOR_HAL> hal) {
+ mHal = std::move(hal);
+ return true;
+ }
+
+ // IAllocator 2.0 interface
+ Return<void> dumpDebugInfo(IAllocator::dumpDebugInfo_cb hidl_cb) override {
+ hidl_cb(mHal->dumpDebugInfo());
+ return Void();
+ }
+
+ Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
+ IAllocator::allocate_cb hidl_cb) override {
+ uint32_t stride;
+ std::vector<const native_handle_t*> buffers;
+ Error error = mHal->allocateBuffers(descriptor, count, &stride, &buffers);
+ if (error != Error::NONE) {
+ hidl_cb(error, 0, hidl_vec<hidl_handle>());
+ return Void();
+ }
+
+ hidl_vec<hidl_handle> hidlBuffers(buffers.cbegin(), buffers.cend());
+ hidl_cb(Error::NONE, stride, hidlBuffers);
+
+ // free the local handles
+ mHal->freeBuffers(buffers);
+
+ return Void();
+ }
+
+ protected:
+ std::unique_ptr<ALLOCATOR_HAL> mHal;
+};
+
+} // namespace detail
+
+using Allocator = detail::AllocatorImpl<IAllocator, AllocatorHal>;
+
+} // namespace hal
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/AllocatorHal.h b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/AllocatorHal.h
new file mode 100644
index 0000000..dec377a
--- /dev/null
+++ b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/AllocatorHal.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace hal {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+class AllocatorHal {
+ public:
+ virtual ~AllocatorHal() = default;
+
+ // dump the debug information
+ virtual std::string dumpDebugInfo() = 0;
+
+ // allocate buffers
+ virtual Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
+ uint32_t* outStride,
+ std::vector<const native_handle_t*>* outBuffers) = 0;
+
+ // free buffers
+ virtual void freeBuffers(const std::vector<const native_handle_t*>& buffers) = 0;
+};
+
+} // namespace hal
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/Android.bp b/graphics/allocator/2.0/utils/passthrough/Android.bp
new file mode 100644
index 0000000..b956565
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/Android.bp
@@ -0,0 +1,29 @@
+cc_library_static {
+ name: "android.hardware.graphics.allocator@2.0-passthrough",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ srcs: [
+ "Gralloc0Hal.cpp",
+ "Gralloc1Hal.cpp",
+ "GrallocLoader.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ "libhardware",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ "libhardware",
+ ],
+ header_libs: [
+ "android.hardware.graphics.allocator@2.0-hal",
+ "libgrallocmapperincludes",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.allocator@2.0-hal",
+ ],
+ export_include_dirs: ["include"],
+ cflags: ["-DLOG_TAG=\"AllocatorHal\""],
+}
diff --git a/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp b/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp
new file mode 100644
index 0000000..8edb7dc
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/Gralloc0Hal.h>
+
+#include <string.h>
+
+#include <GrallocBufferDescriptor.h>
+#include <hardware/gralloc.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;
+
+Gralloc0Hal::~Gralloc0Hal() {
+ if (mDevice) {
+ gralloc_close(mDevice);
+ }
+}
+
+bool Gralloc0Hal::initWithModule(const hw_module_t* module) {
+ int result = gralloc_open(module, &mDevice);
+ if (result) {
+ ALOGE("failed to open gralloc0 device: %s", strerror(-result));
+ mDevice = nullptr;
+ return false;
+ }
+
+ return true;
+}
+
+std::string Gralloc0Hal::dumpDebugInfo() {
+ char buf[4096] = {};
+ if (mDevice->dump) {
+ mDevice->dump(mDevice, buf, sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ }
+
+ return buf;
+}
+
+Error Gralloc0Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
+ uint32_t* outStride,
+ std::vector<const native_handle_t*>* outBuffers) {
+ mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
+ if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
+ return Error::BAD_DESCRIPTOR;
+ }
+
+ Error error = Error::NONE;
+ uint32_t stride = 0;
+ std::vector<const native_handle_t*> buffers;
+ buffers.reserve(count);
+
+ // allocate the buffers
+ for (uint32_t i = 0; i < count; i++) {
+ const native_handle_t* tmpBuffer;
+ uint32_t tmpStride;
+ error = allocateOneBuffer(descriptorInfo, &tmpBuffer, &tmpStride);
+ if (error != Error::NONE) {
+ break;
+ }
+
+ buffers.push_back(tmpBuffer);
+
+ if (stride == 0) {
+ stride = tmpStride;
+ } else if (stride != tmpStride) {
+ // non-uniform strides
+ error = Error::UNSUPPORTED;
+ break;
+ }
+ }
+
+ if (error != Error::NONE) {
+ freeBuffers(buffers);
+ return error;
+ }
+
+ *outStride = stride;
+ *outBuffers = std::move(buffers);
+
+ return Error::NONE;
+}
+
+void Gralloc0Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
+ for (auto buffer : buffers) {
+ int result = mDevice->free(mDevice, buffer);
+ if (result != 0) {
+ ALOGE("failed to free buffer %p: %d", buffer, result);
+ }
+ }
+}
+
+Error Gralloc0Hal::allocateOneBuffer(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+ const native_handle_t** outBuffer, uint32_t* outStride) {
+ if (info.layerCount > 1 || (info.usage >> 32) != 0) {
+ return Error::BAD_VALUE;
+ }
+
+ const native_handle_t* buffer = nullptr;
+ int stride = 0;
+ int result = mDevice->alloc(mDevice, info.width, info.height, static_cast<int>(info.format),
+ info.usage, &buffer, &stride);
+ switch (result) {
+ case 0:
+ *outBuffer = buffer;
+ *outStride = stride;
+ return Error::NONE;
+ case -EINVAL:
+ return Error::BAD_VALUE;
+ default:
+ return Error::NO_RESOURCES;
+ }
+}
+
+} // namespace passthrough
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp b/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp
new file mode 100644
index 0000000..e343ecd
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/Gralloc1Hal.h>
+
+#include <string.h>
+
+#include <GrallocBufferDescriptor.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;
+
+Gralloc1Hal::~Gralloc1Hal() {
+ if (mDevice) {
+ gralloc1_close(mDevice);
+ }
+}
+
+bool Gralloc1Hal::initWithModule(const hw_module_t* module) {
+ int result = gralloc1_open(module, &mDevice);
+ if (result) {
+ ALOGE("failed to open gralloc1 device: %s", strerror(-result));
+ mDevice = nullptr;
+ return false;
+ }
+
+ initCapabilities();
+ if (!initDispatch()) {
+ gralloc1_close(mDevice);
+ mDevice = nullptr;
+ return false;
+ }
+
+ return true;
+}
+
+void Gralloc1Hal::initCapabilities() {
+ uint32_t count = 0;
+ mDevice->getCapabilities(mDevice, &count, nullptr);
+
+ std::vector<int32_t> capabilities(count);
+ mDevice->getCapabilities(mDevice, &count, capabilities.data());
+ capabilities.resize(count);
+
+ for (auto capability : capabilities) {
+ if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
+ mCapabilities.layeredBuffers = true;
+ break;
+ }
+ }
+}
+
+gralloc1_function_pointer_t Gralloc1Hal::getDispatchFunction(
+ gralloc1_function_descriptor_t desc) const {
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (!pfn) {
+ ALOGE("failed to get gralloc1 function %d", desc);
+ return nullptr;
+ }
+ return pfn;
+}
+
+bool Gralloc1Hal::initDispatch() {
+ if (!initDispatchFunction(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR, &mDispatch.createDescriptor) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR, &mDispatch.destroyDescriptor) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE, &mDispatch.setConsumerUsage) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE, &mDispatch.setProducerUsage) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate) ||
+ !initDispatchFunction(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release)) {
+ return false;
+ }
+
+ if (mCapabilities.layeredBuffers) {
+ if (!initDispatchFunction(GRALLOC1_FUNCTION_SET_LAYER_COUNT, &mDispatch.setLayerCount)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+std::string Gralloc1Hal::dumpDebugInfo() {
+ uint32_t len = 0;
+ mDispatch.dump(mDevice, &len, nullptr);
+
+ std::vector<char> buf(len + 1);
+ mDispatch.dump(mDevice, &len, buf.data());
+ buf.resize(len + 1);
+ buf[len] = '\0';
+
+ return buf.data();
+}
+
+Error Gralloc1Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
+ uint32_t* outStride,
+ std::vector<const native_handle_t*>* outBuffers) {
+ mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
+ if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
+ return Error::BAD_DESCRIPTOR;
+ }
+
+ gralloc1_buffer_descriptor_t desc;
+ Error error = createDescriptor(descriptorInfo, &desc);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ uint32_t stride = 0;
+ std::vector<const native_handle_t*> buffers;
+ buffers.reserve(count);
+
+ // allocate the buffers
+ for (uint32_t i = 0; i < count; i++) {
+ const native_handle_t* tmpBuffer;
+ uint32_t tmpStride;
+ error = allocateOneBuffer(desc, &tmpBuffer, &tmpStride);
+ if (error != Error::NONE) {
+ break;
+ }
+
+ buffers.push_back(tmpBuffer);
+
+ if (stride == 0) {
+ stride = tmpStride;
+ } else if (stride != tmpStride) {
+ // non-uniform strides
+ error = Error::UNSUPPORTED;
+ break;
+ }
+ }
+
+ mDispatch.destroyDescriptor(mDevice, desc);
+
+ if (error != Error::NONE) {
+ freeBuffers(buffers);
+ return error;
+ }
+
+ *outStride = stride;
+ *outBuffers = std::move(buffers);
+
+ return Error::NONE;
+}
+
+void Gralloc1Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
+ for (auto buffer : buffers) {
+ int32_t error = mDispatch.release(mDevice, buffer);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("failed to free buffer %p: %d", buffer, error);
+ }
+ }
+}
+
+Error Gralloc1Hal::toError(int32_t error) {
+ switch (error) {
+ case GRALLOC1_ERROR_NONE:
+ return Error::NONE;
+ case GRALLOC1_ERROR_BAD_DESCRIPTOR:
+ return Error::BAD_DESCRIPTOR;
+ case GRALLOC1_ERROR_BAD_HANDLE:
+ return Error::BAD_BUFFER;
+ case GRALLOC1_ERROR_BAD_VALUE:
+ return Error::BAD_VALUE;
+ case GRALLOC1_ERROR_NOT_SHARED:
+ return Error::NONE; // this is fine
+ case GRALLOC1_ERROR_NO_RESOURCES:
+ return Error::NO_RESOURCES;
+ case GRALLOC1_ERROR_UNDEFINED:
+ case GRALLOC1_ERROR_UNSUPPORTED:
+ default:
+ return Error::UNSUPPORTED;
+ }
+}
+
+uint64_t Gralloc1Hal::toProducerUsage(uint64_t usage) {
+ // this is potentially broken as we have no idea which private flags
+ // should be filtered out
+ uint64_t producerUsage =
+ usage & ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
+ BufferUsage::GPU_DATA_BUFFER);
+
+ switch (usage & BufferUsage::CPU_WRITE_MASK) {
+ case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
+ producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+ break;
+ case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
+ producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
+ break;
+ default:
+ break;
+ }
+
+ switch (usage & BufferUsage::CPU_READ_MASK) {
+ case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
+ producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
+ break;
+ case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
+ producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
+ break;
+ default:
+ break;
+ }
+
+ // BufferUsage::GPU_DATA_BUFFER is always filtered out
+
+ return producerUsage;
+}
+
+uint64_t Gralloc1Hal::toConsumerUsage(uint64_t usage) {
+ // this is potentially broken as we have no idea which private flags
+ // should be filtered out
+ uint64_t consumerUsage =
+ usage &
+ ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
+ BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER);
+
+ switch (usage & BufferUsage::CPU_READ_MASK) {
+ case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
+ consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
+ break;
+ case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
+ consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
+ break;
+ default:
+ break;
+ }
+
+ // BufferUsage::SENSOR_DIRECT_DATA is always filtered out
+
+ if (usage & BufferUsage::GPU_DATA_BUFFER) {
+ consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
+ }
+
+ return consumerUsage;
+}
+
+Error Gralloc1Hal::createDescriptor(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+ gralloc1_buffer_descriptor_t* outDescriptor) {
+ gralloc1_buffer_descriptor_t descriptor;
+
+ int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);
+
+ if (error == GRALLOC1_ERROR_NONE) {
+ error = mDispatch.setDimensions(mDevice, descriptor, info.width, info.height);
+ }
+ if (error == GRALLOC1_ERROR_NONE) {
+ error = mDispatch.setFormat(mDevice, descriptor, static_cast<int32_t>(info.format));
+ }
+ if (error == GRALLOC1_ERROR_NONE) {
+ if (mCapabilities.layeredBuffers) {
+ error = mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
+ } else if (info.layerCount > 1) {
+ error = GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ }
+ if (error == GRALLOC1_ERROR_NONE) {
+ error = mDispatch.setProducerUsage(mDevice, descriptor, toProducerUsage(info.usage));
+ }
+ if (error == GRALLOC1_ERROR_NONE) {
+ error = mDispatch.setConsumerUsage(mDevice, descriptor, toConsumerUsage(info.usage));
+ }
+
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outDescriptor = descriptor;
+ } else {
+ mDispatch.destroyDescriptor(mDevice, descriptor);
+ }
+
+ return toError(error);
+}
+
+Error Gralloc1Hal::allocateOneBuffer(gralloc1_buffer_descriptor_t descriptor,
+ const native_handle_t** outBuffer, uint32_t* outStride) {
+ const native_handle_t* buffer = nullptr;
+ int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
+ if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
+ return toError(error);
+ }
+
+ uint32_t stride = 0;
+ error = mDispatch.getStride(mDevice, buffer, &stride);
+ if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
+ mDispatch.release(mDevice, buffer);
+ return toError(error);
+ }
+
+ *outBuffer = buffer;
+ *outStride = stride;
+
+ return Error::NONE;
+}
+
+} // namespace passthrough
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp b/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp
new file mode 100644
index 0000000..dae7a78
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/GrallocLoader.h>
+
+#include <allocator-hal/2.0/Allocator.h>
+#include <allocator-hal/2.0/AllocatorHal.h>
+#include <allocator-passthrough/2.0/Gralloc0Hal.h>
+#include <allocator-passthrough/2.0/Gralloc1Hal.h>
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+const hw_module_t* GrallocLoader::loadModule() {
+ const hw_module_t* module;
+ int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (error) {
+ ALOGE("failed to get gralloc module");
+ return nullptr;
+ }
+
+ return module;
+}
+
+int GrallocLoader::getModuleMajorApiVersion(const hw_module_t* module) {
+ return (module->module_api_version >> 8) & 0xff;
+}
+
+std::unique_ptr<hal::AllocatorHal> GrallocLoader::createHal(const hw_module_t* module) {
+ int major = getModuleMajorApiVersion(module);
+ switch (major) {
+ case 1: {
+ auto hal = std::make_unique<Gralloc1Hal>();
+ return hal->initWithModule(module) ? std::move(hal) : nullptr;
+ }
+ case 0: {
+ auto hal = std::make_unique<Gralloc0Hal>();
+ return hal->initWithModule(module) ? std::move(hal) : nullptr;
+ }
+ default:
+ ALOGE("unknown gralloc module major version %d", major);
+ return nullptr;
+ }
+}
+
+IAllocator* GrallocLoader::createAllocator(std::unique_ptr<hal::AllocatorHal> hal) {
+ auto allocator = std::make_unique<hal::Allocator>();
+ return allocator->init(std::move(hal)) ? allocator.release() : nullptr;
+}
+
+} // namespace passthrough
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h
new file mode 100644
index 0000000..8f433b0
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+
+struct alloc_device_t;
+struct hw_module_t;
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+class Gralloc0Hal : public virtual hal::AllocatorHal {
+ public:
+ ~Gralloc0Hal();
+ bool initWithModule(const hw_module_t* module);
+
+ std::string dumpDebugInfo() override;
+
+ Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count, uint32_t* outStride,
+ std::vector<const native_handle_t*>* outBuffers) override;
+
+ void freeBuffers(const std::vector<const native_handle_t*>& buffers) override;
+
+ protected:
+ Error allocateOneBuffer(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+ const native_handle_t** outBuffer, uint32_t* outStride);
+
+ alloc_device_t* mDevice = nullptr;
+};
+
+} // namespace passthrough
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h
new file mode 100644
index 0000000..3126e91
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+#include <hardware/gralloc1.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+class Gralloc1Hal : public virtual hal::AllocatorHal {
+ public:
+ ~Gralloc1Hal();
+ bool initWithModule(const hw_module_t* module);
+
+ std::string dumpDebugInfo() override;
+
+ Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count, uint32_t* outStride,
+ std::vector<const native_handle_t*>* outBuffers) override;
+
+ void freeBuffers(const std::vector<const native_handle_t*>& buffers) override;
+
+ protected:
+ template <typename T>
+ bool initDispatchFunction(gralloc1_function_descriptor_t desc, T* outPfn) {
+ auto pfn = getDispatchFunction(desc);
+ if (pfn) {
+ *outPfn = reinterpret_cast<T>(pfn);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ gralloc1_function_pointer_t getDispatchFunction(gralloc1_function_descriptor_t desc) const;
+
+ virtual void initCapabilities();
+ virtual bool initDispatch();
+
+ static Error toError(int32_t error);
+ static uint64_t toProducerUsage(uint64_t usage);
+ static uint64_t toConsumerUsage(uint64_t usage);
+
+ Error createDescriptor(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+ gralloc1_buffer_descriptor_t* outDescriptor);
+
+ Error allocateOneBuffer(gralloc1_buffer_descriptor_t descriptor,
+ const native_handle_t** outBuffer, uint32_t* outStride);
+
+ gralloc1_device_t* mDevice = nullptr;
+
+ struct {
+ bool layeredBuffers;
+ } mCapabilities = {};
+
+ struct {
+ GRALLOC1_PFN_DUMP dump;
+ GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor;
+ GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor;
+ GRALLOC1_PFN_SET_DIMENSIONS setDimensions;
+ GRALLOC1_PFN_SET_FORMAT setFormat;
+ GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount;
+ GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage;
+ GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage;
+ GRALLOC1_PFN_GET_STRIDE getStride;
+ GRALLOC1_PFN_ALLOCATE allocate;
+ GRALLOC1_PFN_RELEASE release;
+ } mDispatch = {};
+};
+
+} // namespace passthrough
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h
new file mode 100644
index 0000000..a0b9503
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+
+struct hw_module_t;
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+class GrallocLoader {
+ public:
+ static IAllocator* load() {
+ const hw_module_t* module = loadModule();
+ if (!module) {
+ return nullptr;
+ }
+ auto hal = createHal(module);
+ if (!hal) {
+ return nullptr;
+ }
+ return createAllocator(std::move(hal));
+ }
+
+ // load the gralloc module
+ static const hw_module_t* loadModule();
+
+ // return the major api version of the module
+ static int getModuleMajorApiVersion(const hw_module_t* module);
+
+ // create an AllocatorHal instance
+ static std::unique_ptr<hal::AllocatorHal> createHal(const hw_module_t* module);
+
+ // create an IAllocator instance
+ static IAllocator* createAllocator(std::unique_ptr<hal::AllocatorHal> hal);
+};
+
+} // namespace passthrough
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/health/2.0/Android.bp b/health/2.0/Android.bp
index 97704bf..c444165 100644
--- a/health/2.0/Android.bp
+++ b/health/2.0/Android.bp
@@ -18,6 +18,7 @@
types: [
"Result",
"DiskStats",
+ "HealthInfo",
"StorageAttribute",
"StorageInfo",
],
diff --git a/health/2.0/IHealth.hal b/health/2.0/IHealth.hal
index a33bb15..230b5d0 100644
--- a/health/2.0/IHealth.hal
+++ b/health/2.0/IHealth.hal
@@ -69,7 +69,7 @@
* NOT_SUPPORTED if this property is not supported
* (e.g. the file that stores this property does not exist),
* UNKNOWN for other errors.
- * @return value battery capacity, or INT32_MIN if not successful.
+ * @return value battery capacity, or 0 if not successful.
*/
getChargeCounter() generates (Result result, int32_t value);
@@ -84,7 +84,7 @@
* NOT_SUPPORTED if this property is not supported
* (e.g. the file that stores this property does not exist),
* UNKNOWN for other errors.
- * @return value instantaneous battery current, or INT32_MIN if not
+ * @return value instantaneous battery current, or 0 if not
* successful.
*/
getCurrentNow() generates (Result result, int32_t value);
@@ -101,7 +101,7 @@
* NOT_SUPPORTED if this property is not supported
* (e.g. the file that stores this property does not exist),
* UNKNOWN for other errors.
- * @return value average battery current, or INT32_MIN if not successful.
+ * @return value average battery current, or 0 if not successful.
*/
getCurrentAverage() generates (Result result, int32_t value);
@@ -113,7 +113,7 @@
* NOT_SUPPORTED if this property is not supported
* (e.g. the file that stores this property does not exist),
* UNKNOWN for other errors.
- * @return value remaining battery capacity, or INT32_MIN if not successful.
+ * @return value remaining battery capacity, or 0 if not successful.
*/
getCapacity() generates (Result result, int32_t value);
@@ -123,7 +123,7 @@
* @return result SUCCESS if successful,
* NOT_SUPPORTED if this property is not supported,
* UNKNOWN for other errors.
- * @return value remaining energy, or INT64_MIN if not successful.
+ * @return value remaining energy, or 0 if not successful.
*/
getEnergyCounter() generates (Result result, int64_t value);
@@ -160,4 +160,15 @@
* The mapping is index 0->sda, 1->sdb and so on.
*/
getDiskStats() generates (Result result, vec<DiskStats> value);
+
+ /**
+ * Get Health Information.
+ *
+ * @return result SUCCESS if successful,
+ * NOT_SUPPORTED if this API is not supported,
+ * UNKNOWN for other errors.
+ * @return value Health information, to be ignored if result is not
+ * SUCCESS.
+ */
+ getHealthInfo() generates (Result result, @2.0::HealthInfo value);
};
diff --git a/health/2.0/IHealthInfoCallback.hal b/health/2.0/IHealthInfoCallback.hal
index 8e17bb9..15352ee 100644
--- a/health/2.0/IHealthInfoCallback.hal
+++ b/health/2.0/IHealthInfoCallback.hal
@@ -16,8 +16,6 @@
package android.hardware.health@2.0;
-import @1.0::HealthInfo;
-
/**
* IHealthInfoCallback is the callback interface to
* {@link IHealthInfoBus.registerCallback}.
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
index 96f6d70..7a3e650 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -18,6 +18,7 @@
#include <health2/Health.h>
+#include <hal_conversion.h>
#include <hidl/HidlTransportSupport.h>
extern void healthd_battery_update_internal(bool);
@@ -108,27 +109,27 @@
}
Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
- getProperty(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, INT32_MIN, _hidl_cb);
+ getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
return Void();
}
Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
- getProperty(battery_monitor_, BATTERY_PROP_CURRENT_NOW, INT32_MIN, _hidl_cb);
+ getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
return Void();
}
Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
- getProperty(battery_monitor_, BATTERY_PROP_CURRENT_AVG, INT32_MIN, _hidl_cb);
+ getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
return Void();
}
Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
- getProperty(battery_monitor_, BATTERY_PROP_CAPACITY, INT32_MIN, _hidl_cb);
+ getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
return Void();
}
Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
- getProperty(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, INT64_MIN, _hidl_cb);
+ getProperty<int64_t>(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
return Void();
}
@@ -154,10 +155,28 @@
return Result::SUCCESS;
}
-void Health::notifyListeners(const HealthInfo& info) {
+void Health::notifyListeners(HealthInfo* healthInfo) {
+ std::vector<StorageInfo> info;
+ get_storage_info(info);
+
+ std::vector<DiskStats> stats;
+ get_disk_stats(stats);
+
+ int32_t currentAvg = 0;
+
+ struct BatteryProperty prop;
+ status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
+ if (ret == OK) {
+ currentAvg = static_cast<int32_t>(prop.valueInt64);
+ }
+
+ healthInfo->batteryCurrentAverage = currentAvg;
+ healthInfo->diskStats = stats;
+ healthInfo->storageInfos = info;
+
std::lock_guard<std::mutex> _lock(callbacks_lock_);
for (auto it = callbacks_.begin(); it != callbacks_.end();) {
- auto ret = (*it)->healthInfoChanged(info);
+ auto ret = (*it)->healthInfoChanged(*healthInfo);
if (!ret.isOk() && ret.isDeadObject()) {
it = callbacks_.erase(it);
} else {
@@ -199,6 +218,39 @@
return Void();
}
+Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
+ using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+
+ update();
+ struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
+
+ V1_0::HealthInfo batteryInfo;
+ convertToHealthInfo(&p, batteryInfo);
+
+ std::vector<StorageInfo> info;
+ get_storage_info(info);
+
+ std::vector<DiskStats> stats;
+ get_disk_stats(stats);
+
+ int32_t currentAvg = 0;
+
+ struct BatteryProperty prop;
+ status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
+ if (ret == OK) {
+ currentAvg = static_cast<int32_t>(prop.valueInt64);
+ }
+
+ V2_0::HealthInfo healthInfo = {};
+ healthInfo.legacy = std::move(batteryInfo);
+ healthInfo.batteryCurrentAverage = currentAvg;
+ healthInfo.diskStats = stats;
+ healthInfo.storageInfos = info;
+
+ _hidl_cb(Result::SUCCESS, healthInfo);
+ return Void();
+}
+
void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
(void)unregisterCallbackInternal(who.promote());
}
diff --git a/health/2.0/default/include/health2/Health.h b/health/2.0/default/include/health2/Health.h
index 41ba9e9..134cdc6 100644
--- a/health/2.0/default/include/health2/Health.h
+++ b/health/2.0/default/include/health2/Health.h
@@ -22,7 +22,6 @@
namespace implementation {
using V1_0::BatteryStatus;
-using V1_0::HealthInfo;
using ::android::hidl::base::V1_0::IBase;
@@ -38,7 +37,7 @@
Health(struct healthd_config* c);
// TODO(b/62229583): clean up and hide these functions after update() logic is simplified.
- void notifyListeners(const HealthInfo& info);
+ void notifyListeners(HealthInfo* info);
// Methods from IHealth follow.
Return<Result> registerCallback(const sp<IHealthInfoCallback>& callback) override;
@@ -52,6 +51,7 @@
Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+ Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
diff --git a/health/2.0/libhealthhalutils/Android.bp b/health/2.0/libhealthhalutils/Android.bp
new file mode 100644
index 0000000..5686520
--- /dev/null
+++ b/health/2.0/libhealthhalutils/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Convenience library for (hwbinder) clients to choose the correct health
+// service instance.
+cc_library_static {
+ name: "libhealthhalutils",
+ srcs: ["HealthHalUtils.cpp"],
+ cflags: ["-Wall", "-Werror"],
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "android.hardware.health@2.0",
+ "libbase",
+ "libhidlbase",
+ ],
+}
diff --git a/health/2.0/libhealthhalutils/HealthHalUtils.cpp b/health/2.0/libhealthhalutils/HealthHalUtils.cpp
new file mode 100644
index 0000000..9e1cc70
--- /dev/null
+++ b/health/2.0/libhealthhalutils/HealthHalUtils.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HealthHalUtils"
+
+#include <android-base/logging.h>
+#include <healthhalutils/HealthHalUtils.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+
+sp<IHealth> get_health_service() {
+ for (auto&& instanceName : {"default", "backup"}) {
+ auto ret = IHealth::getService(instanceName);
+ if (ret != nullptr) {
+ return ret;
+ }
+ LOG(INFO) << "health: cannot get " << instanceName << " service";
+ }
+ return nullptr;
+}
+
+} // namespace V2_0
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/2.0/libhealthhalutils/include/healthhalutils/HealthHalUtils.h b/health/2.0/libhealthhalutils/include/healthhalutils/HealthHalUtils.h
new file mode 100644
index 0000000..66acc7c
--- /dev/null
+++ b/health/2.0/libhealthhalutils/include/healthhalutils/HealthHalUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HEALTHD_HEALTH_HAL_UTILS_H
+#define HEALTHD_HEALTH_HAL_UTILS_H
+
+#include <android/hardware/health/2.0/IHealth.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+
+// Simplified version of BatteryService.HealthServiceWrapper.init().
+// Returns the "default" health instance when it is available, and "backup" instance
+// otherwise. Before health 1.0 HAL is removed, this function should be used instead
+// of IHealth::getService().
+sp<IHealth> get_health_service();
+
+} // namespace V2_0
+} // namespace health
+} // namespace hardware
+} // namespace android
+
+#endif // HEALTHD_HEALTH_HAL_UTILS_H
diff --git a/health/2.0/libstoragehealthdefault/Android.bp b/health/2.0/libstoragehealthdefault/Android.bp
index 986e1ef..cef04fe 100644
--- a/health/2.0/libstoragehealthdefault/Android.bp
+++ b/health/2.0/libstoragehealthdefault/Android.bp
@@ -1,5 +1,22 @@
-// Copyright 2018 The Android Open Source Project
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Default implementation for (passthrough) clients that statically links to
+// android.hardware.health@2.0-impl but do no query for storage related
+// information.
cc_library_static {
srcs: ["StorageHealthDefault.cpp"],
name: "libhealthstoragedefault",
diff --git a/health/2.0/types.hal b/health/2.0/types.hal
index 4e7a081..fe33c88 100644
--- a/health/2.0/types.hal
+++ b/health/2.0/types.hal
@@ -124,3 +124,31 @@
*/
StorageAttribute attr;
};
+
+/**
+ * Combined Health Information.
+ */
+struct HealthInfo {
+ /**
+ * V1.0 HealthInfo.
+ * If a member is unsupported, it is filled with:
+ * - 0 (for integers);
+ * - false (for booleans);
+ * - empty string (for strings);
+ * - UNKNOWN (for BatteryStatus and BatteryHealth).
+ */
+ @1.0::HealthInfo legacy;
+ /**
+ * Average battery current in uA. Will be 0 if unsupported.
+ */
+ int32_t batteryCurrentAverage;
+ /**
+ * Disk Statistics. Will be an empty vector if unsupported.
+ */
+ vec<DiskStats> diskStats;
+ /**
+ * Information on storage devices. Will be an empty vector if
+ * unsupported.
+ */
+ vec<StorageInfo> storageInfos;
+};
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index b2c6160..972bc7f 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -35,7 +35,6 @@
namespace V2_0 {
using V1_0::BatteryStatus;
-using V1_0::HealthInfo;
// Test environment for graphics.composer
class HealthHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
@@ -203,6 +202,43 @@
return true;
}
+template <typename T>
+bool verifyEnum(T value) {
+ for (auto it : hidl_enum_iterator<T>()) {
+ if (it == value) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool verifyHealthInfo(const HealthInfo& health_info) {
+ if (!verifyStorageInfo(health_info.storageInfos) || !verifyDiskStats(health_info.diskStats)) {
+ return false;
+ }
+
+ using V1_0::BatteryStatus;
+ using V1_0::BatteryHealth;
+
+ if (!((health_info.legacy.batteryChargeCounter > 0) &&
+ (health_info.legacy.batteryCurrent != INT32_MIN) &&
+ (0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
+ verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
+ (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN) &&
+ verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Tests the values returned by getChargeCounter(),
+ * getCurrentNow(), getCurrentAverage(), getCapacity(), getEnergyCounter(),
+ * getChargeStatus(), getStorageInfo(), getDiskStats() and getHealthInfo() from
+ * interface IHealth.
+ */
TEST_F(HealthHidlTest, Properties) {
EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0);
@@ -222,15 +258,17 @@
EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(
result, toString(value),
- value == BatteryStatus::CHARGING || value == BatteryStatus::DISCHARGING ||
- value == BatteryStatus::NOT_CHARGING || value == BatteryStatus::FULL);
+ value != BatteryStatus::UNKNOWN && verifyEnum<BatteryStatus>(value));
}));
EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) {
- EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), (verifyStorageInfo(value)));
+ EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value));
}));
EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyDiskStats(value));
}));
+ EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) {
+ EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value));
+ }));
}
} // namespace V2_0
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 748fed3..6b8dcdc 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -26,11 +26,18 @@
"attestation_record.cpp",
"authorization_set.cpp",
"key_param_output.cpp",
+ "Keymaster3.cpp",
+ "Keymaster4.cpp",
],
export_include_dirs: ["include"],
shared_libs: [
+ "android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
+ "libbase",
"libcrypto",
+ "libhardware",
"libhidlbase",
+ "libhidltransport",
+ "libutils",
]
}
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.0/support/Keymaster3.cpp
new file mode 100644
index 0000000..6dfe85b
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster3.cpp
@@ -0,0 +1,325 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <keymasterV4_0/Keymaster3.h>
+
+#include <android-base/logging.h>
+#include <hardware/hw_auth_token.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using android::hardware::details::StatusOf;
+
+namespace {
+
+ErrorCode convert(V3_0::ErrorCode error) {
+ return static_cast<ErrorCode>(error);
+}
+
+V3_0::KeyPurpose convert(KeyPurpose purpose) {
+ return static_cast<V3_0::KeyPurpose>(purpose);
+}
+
+V3_0::KeyFormat convert(KeyFormat purpose) {
+ return static_cast<V3_0::KeyFormat>(purpose);
+}
+
+V3_0::KeyParameter convert(const KeyParameter& param) {
+ V3_0::KeyParameter converted;
+ converted.tag = static_cast<V3_0::Tag>(param.tag);
+ static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+ memcpy(&converted.f, ¶m.f, sizeof(param.f));
+ converted.blob = param.blob;
+ return converted;
+}
+
+KeyParameter convert(const V3_0::KeyParameter& param) {
+ KeyParameter converted;
+ converted.tag = static_cast<Tag>(param.tag);
+ static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+ memcpy(&converted.f, ¶m.f, sizeof(param.f));
+ converted.blob = param.blob;
+ return converted;
+}
+
+hidl_vec<V3_0::KeyParameter> convert(const hidl_vec<KeyParameter>& params) {
+ hidl_vec<V3_0::KeyParameter> converted(params.size());
+ for (size_t i = 0; i < params.size(); ++i) {
+ converted[i] = convert(params[i]);
+ }
+ return converted;
+}
+
+hidl_vec<KeyParameter> convert(const hidl_vec<V3_0::KeyParameter>& params) {
+ hidl_vec<KeyParameter> converted(params.size());
+ for (size_t i = 0; i < params.size(); ++i) {
+ converted[i] = convert(params[i]);
+ }
+ return converted;
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+ const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+ return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+constexpr size_t kHmacSize = 32;
+
+inline static hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
+ static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+ sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+ sizeof(token.timestamp) + kHmacSize ==
+ sizeof(hw_auth_token_t),
+ "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+ hidl_vec<uint8_t> result;
+ result.resize(sizeof(hw_auth_token_t));
+ auto pos = result.begin();
+ *pos++ = 0; // Version byte
+ pos = copy_bytes_to_iterator(token.challenge, pos);
+ pos = copy_bytes_to_iterator(token.userId, pos);
+ pos = copy_bytes_to_iterator(token.authenticatorId, pos);
+ auto auth_type = htonl(static_cast<uint32_t>(token.authenticatorType));
+ pos = copy_bytes_to_iterator(auth_type, pos);
+ auto timestamp = htonq(token.timestamp);
+ pos = copy_bytes_to_iterator(timestamp, pos);
+ if (token.mac.size() != kHmacSize) {
+ std::fill(pos, pos + kHmacSize, 0);
+ } else {
+ std::copy(token.mac.begin(), token.mac.end(), pos);
+ }
+
+ return result;
+}
+
+hidl_vec<V3_0::KeyParameter> convertAndAddAuthToken(const hidl_vec<KeyParameter>& params,
+ const HardwareAuthToken& authToken) {
+ hidl_vec<V3_0::KeyParameter> converted(params.size() + 1);
+ for (size_t i = 0; i < params.size(); ++i) {
+ converted[i] = convert(params[i]);
+ }
+ converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
+ converted[params.size()].blob = authToken2HidlVec(authToken);
+
+ return converted;
+}
+
+KeyCharacteristics convert(const V3_0::KeyCharacteristics& chars) {
+ KeyCharacteristics converted;
+ converted.hardwareEnforced = convert(chars.teeEnforced);
+ converted.softwareEnforced = convert(chars.softwareEnforced);
+ return converted;
+}
+
+} // namespace
+
+void Keymaster3::getVersionIfNeeded() {
+ if (haveVersion_) return;
+
+ auto rc = km3_dev_->getHardwareFeatures(
+ [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
+ bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
+ const hidl_string& keymasterAuthorName) {
+ securityLevel_ =
+ isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
+ supportsEllipticCurve_ = supportsEllipticCurve;
+ supportsSymmetricCryptography_ = supportsSymmetricCryptography;
+ supportsAttestation_ = supportsAttestation;
+ supportsAllDigests_ = supportsAllDigests;
+ keymasterName_ = keymasterName;
+ authorName_ = keymasterAuthorName;
+ });
+
+ CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
+
+ if (securityLevel_ == SecurityLevel::SOFTWARE) {
+ majorVersion_ = 3;
+ } else if (supportsAttestation_) {
+ majorVersion_ = 3; // Could be 2, doesn't matter.
+ } else if (supportsSymmetricCryptography_) {
+ majorVersion_ = 1;
+ } else {
+ majorVersion_ = 0;
+ }
+}
+
+Keymaster::VersionResult Keymaster3::halVersion() {
+ getVersionIfNeeded();
+ return {ErrorCode::OK, majorVersion_, securityLevel_, supportsEllipticCurve_};
+}
+
+Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
+ getVersionIfNeeded();
+ _hidl_cb(securityLevel_, keymasterName_ + " (wrapped by keystore::Keymaster3)", authorName_);
+ return Void();
+}
+
+Return<ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
+ auto rc = km3_dev_->addRngEntropy(data);
+ if (!rc.isOk()) {
+ return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ }
+ return convert(rc);
+}
+
+Return<void> Keymaster3::generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+ const V3_0::KeyCharacteristics& characteristics) {
+ _hidl_cb(convert(error), keyBlob, convert(characteristics));
+ };
+ auto rc = km3_dev_->generateKey(convert(keyParams), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const V3_0::KeyCharacteristics& chars) {
+ _hidl_cb(convert(error), convert(chars));
+ };
+
+ auto rc = km3_dev_->getKeyCharacteristics(keyBlob, clientId, appData, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+ const V3_0::KeyCharacteristics& chars) {
+ _hidl_cb(convert(error), keyBlob, convert(chars));
+ };
+ auto rc = km3_dev_->importKey(convert(params), convert(keyFormat), keyData, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) {
+ _hidl_cb(convert(error), keyMaterial);
+ };
+ auto rc = km3_dev_->exportKey(convert(exportFormat), keyBlob, clientId, appData, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
+ _hidl_cb(convert(error), certChain);
+ };
+ auto rc = km3_dev_->attestKey(keyToAttest, convert(attestParams), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) {
+ _hidl_cb(convert(error), upgradedKeyBlob);
+ };
+ auto rc = km3_dev_->upgradeKey(keyBlobToUpgrade, convert(upgradeParams), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+ auto rc = km3_dev_->deleteKey(keyBlob);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ return convert(rc);
+}
+
+Return<ErrorCode> Keymaster3::deleteAllKeys() {
+ auto rc = km3_dev_->deleteAllKeys();
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ return convert(rc);
+}
+
+Return<ErrorCode> Keymaster3::destroyAttestationIds() {
+ auto rc = km3_dev_->destroyAttestationIds();
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ return convert(rc);
+}
+
+Return<void> Keymaster3::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams,
+ const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(convert(error), convert(outParams), operationHandle);
+ };
+
+ auto rc =
+ km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& /* verificationToken */,
+ update_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, uint32_t inputConsumed,
+ const hidl_vec<V3_0::KeyParameter>& outParams, const hidl_vec<uint8_t>& output) {
+ _hidl_cb(convert(error), inputConsumed, convert(outParams), output);
+ };
+
+ auto rc =
+ km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& /* verificationToken */,
+ finish_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+ const hidl_vec<uint8_t>& output) {
+ _hidl_cb(convert(error), convert(outParams), output);
+ };
+
+ auto rc = km3_dev_->finish(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+ signature, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
+ auto rc = km3_dev_->abort(operationHandle);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ return convert(rc);
+}
+
+} // namespace support
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
new file mode 100644
index 0000000..fdf78ae
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster4.cpp
@@ -0,0 +1,48 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <keymasterV4_0/Keymaster4.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+void Keymaster4::getVersionIfNeeded() {
+ if (haveVersion_) return;
+
+ auto rc = dev_->getHardwareInfo([&](SecurityLevel securityLevel, auto...) {
+ securityLevel_ = securityLevel;
+ haveVersion_ = true;
+ });
+
+ CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+Keymaster::VersionResult Keymaster4::halVersion() {
+ getVersionIfNeeded();
+ return {ErrorCode::OK, halMajorVersion(), securityLevel_, true};
+}
+
+} // namespace support
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index de3e270..81cf365 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -441,6 +441,11 @@
return Authorization(TAG_KEY_SIZE, key_size);
}
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::TRIPLE_DES);
+ return Authorization(TAG_KEY_SIZE, key_size);
+}
+
AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
Authorization(TAG_ALGORITHM, Algorithm::HMAC);
Authorization(TAG_KEY_SIZE, key_size);
@@ -474,6 +479,11 @@
return EncryptionKey();
}
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) {
+ TripleDesKey(key_size);
+ return EncryptionKey();
+}
+
AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
new file mode 100644
index 0000000..2686fcd
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -0,0 +1,58 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+/**
+ * Keymaster abstracts the underlying V4_0::IKeymasterDevice. There is one implementation
+ * (Keymaster4) which is a trivial passthrough and one that wraps a V3_0::IKeymasterDevice.
+ *
+ * The reason for adding this additional layer, rather than simply using the latest HAL directly and
+ * subclassing it to wrap any older HAL, is because this provides a place to put additional methods
+ * which clients can use when they need to distinguish between different underlying HAL versions,
+ * while still having to use only the latest interface.
+ */
+class Keymaster : public IKeymasterDevice {
+ public:
+ virtual ~Keymaster() {}
+
+ struct VersionResult {
+ ErrorCode error;
+ uint8_t majorVersion;
+ SecurityLevel securityLevel;
+ bool supportsEc;
+ };
+
+ virtual VersionResult halVersion() = 0;
+};
+
+} // namespace support
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
new file mode 100644
index 0000000..051e570
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
@@ -0,0 +1,129 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+
+#include "Keymaster.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::details::return_status;
+
+class Keymaster3 : public Keymaster {
+ public:
+ using WrappedIKeymasterDevice = IKeymaster3Device;
+ Keymaster3(sp<IKeymaster3Device> km3_dev) : km3_dev_(km3_dev), haveVersion_(false) {}
+
+ VersionResult halVersion() override;
+
+ Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
+
+ Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+ _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ return Void();
+ }
+
+ Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
+ computeSharedHmac_cb _hidl_cb) override {
+ _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ return Void();
+ }
+
+ Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
+ const HardwareAuthToken&,
+ verifyAuthorization_cb _hidl_cb) override {
+ _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ return Void();
+ }
+
+ Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override;
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override;
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+
+ Return<void> importWrappedKey(const hidl_vec<uint8_t>&, const hidl_vec<uint8_t>&,
+ const hidl_vec<uint8_t>&, importWrappedKey_cb _hidl_cb) {
+ _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {});
+ return Void();
+ }
+
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override;
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override;
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override;
+ Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+ Return<ErrorCode> deleteAllKeys() override;
+ Return<ErrorCode> destroyAttestationIds() override;
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ begin_cb _hidl_cb) override;
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, update_cb _hidl_cb) override;
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
+ Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+ private:
+ void getVersionIfNeeded();
+
+ sp<IKeymaster3Device> km3_dev_;
+
+ bool haveVersion_;
+ uint8_t majorVersion_;
+ SecurityLevel securityLevel_;
+ bool supportsEllipticCurve_;
+ bool supportsSymmetricCryptography_;
+ bool supportsAttestation_;
+ bool supportsAllDigests_;
+ std::string keymasterName_;
+ std::string authorName_;
+};
+
+} // namespace support
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
new file mode 100644
index 0000000..ffddcac
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
@@ -0,0 +1,153 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
+
+#include "Keymaster.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using android::sp;
+using IKeymaster4Device = ::android::hardware::keymaster::V4_0::IKeymasterDevice;
+
+class Keymaster4 : public Keymaster {
+ public:
+ using WrappedIKeymasterDevice = IKeymaster4Device;
+ Keymaster4(sp<IKeymasterDevice> km4_dev) : haveVersion_(false), dev_(km4_dev) {}
+
+ uint8_t halMajorVersion() { return 4; }
+
+ VersionResult halVersion() override;
+
+ Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
+ return dev_->getHardwareInfo(_hidl_cb);
+ }
+
+ Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+ return dev_->getHmacSharingParameters(_hidl_cb);
+ }
+
+ Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+ computeSharedHmac_cb _hidl_cb) override {
+ return dev_->computeSharedHmac(params, _hidl_cb);
+ }
+
+ Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
+ const HardwareAuthToken& authToken,
+ verifyAuthorization_cb _hidl_cb) override {
+ return dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
+ }
+
+ Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
+ return dev_->addRngEntropy(data);
+ }
+
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override {
+ return dev_->generateKey(keyParams, _hidl_cb);
+ }
+
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override {
+ return dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
+ }
+
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
+ return dev_->importKey(params, keyFormat, keyData, _hidl_cb);
+ }
+
+ Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+ const hidl_vec<uint8_t>& wrappingKeyBlob,
+ const hidl_vec<uint8_t>& maskingKey,
+ importWrappedKey_cb _hidl_cb) {
+ return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, _hidl_cb);
+ }
+
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override {
+ return dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
+ }
+
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override {
+ return dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
+ }
+
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override {
+ return dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
+ }
+
+ Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
+ return dev_->deleteKey(keyBlob);
+ }
+
+ Return<ErrorCode> deleteAllKeys() override { return dev_->deleteAllKeys(); }
+
+ Return<ErrorCode> destroyAttestationIds() override { return dev_->destroyAttestationIds(); }
+
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ begin_cb _hidl_cb) override {
+ return dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
+ }
+
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, update_cb _hidl_cb) override {
+ return dev_->update(operationHandle, inParams, input, authToken, verificationToken,
+ _hidl_cb);
+ }
+
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
+ return dev_->finish(operationHandle, inParams, input, signature, authToken,
+ verificationToken, _hidl_cb);
+ }
+
+ Return<ErrorCode> abort(uint64_t operationHandle) override {
+ return dev_->abort(operationHandle);
+ }
+
+ private:
+ void getVersionIfNeeded();
+
+ bool haveVersion_;
+ SecurityLevel securityLevel_;
+ sp<IKeymaster4Device> dev_;
+};
+
+} // namespace support
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
index f67f192..09a06fe 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -258,6 +258,7 @@
AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
AuthorizationSetBuilder& EcdsaKey(EcCurve curve);
AuthorizationSetBuilder& AesKey(uint32_t key_size);
+ AuthorizationSetBuilder& TripleDesKey(uint32_t key_size);
AuthorizationSetBuilder& HmacKey(uint32_t key_size);
AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
@@ -265,6 +266,7 @@
AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+ AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size);
AuthorizationSetBuilder& SigningKey();
AuthorizationSetBuilder& EncryptionKey();
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 2f9f88b..73e03fb 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -329,6 +329,92 @@
return accessTagValue(ttag, param);
}
+inline bool operator==(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) {
+ return false;
+ }
+
+ switch (a.tag) {
+ /* Boolean tags */
+ case Tag::INVALID:
+ case Tag::CALLER_NONCE:
+ case Tag::INCLUDE_UNIQUE_ID:
+ case Tag::BOOTLOADER_ONLY:
+ case Tag::NO_AUTH_REQUIRED:
+ case Tag::ALLOW_WHILE_ON_BODY:
+ case Tag::ROLLBACK_RESISTANCE:
+ case Tag::RESET_SINCE_ID_ROTATION:
+ case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+ return true;
+
+ /* Integer tags */
+ case Tag::KEY_SIZE:
+ case Tag::MIN_MAC_LENGTH:
+ case Tag::MIN_SECONDS_BETWEEN_OPS:
+ case Tag::MAX_USES_PER_BOOT:
+ case Tag::OS_VERSION:
+ case Tag::OS_PATCHLEVEL:
+ case Tag::MAC_LENGTH:
+ case Tag::AUTH_TIMEOUT:
+ return a.f.integer == b.f.integer;
+
+ /* Long integer tags */
+ case Tag::RSA_PUBLIC_EXPONENT:
+ case Tag::USER_SECURE_ID:
+ return a.f.longInteger == b.f.longInteger;
+
+ /* Date-time tags */
+ case Tag::ACTIVE_DATETIME:
+ case Tag::ORIGINATION_EXPIRE_DATETIME:
+ case Tag::USAGE_EXPIRE_DATETIME:
+ case Tag::CREATION_DATETIME:
+ return a.f.dateTime == b.f.dateTime;
+
+ /* Bytes tags */
+ case Tag::APPLICATION_ID:
+ case Tag::APPLICATION_DATA:
+ case Tag::ROOT_OF_TRUST:
+ case Tag::UNIQUE_ID:
+ case Tag::ATTESTATION_CHALLENGE:
+ case Tag::ATTESTATION_APPLICATION_ID:
+ case Tag::ATTESTATION_ID_BRAND:
+ case Tag::ATTESTATION_ID_DEVICE:
+ case Tag::ATTESTATION_ID_PRODUCT:
+ case Tag::ATTESTATION_ID_SERIAL:
+ case Tag::ATTESTATION_ID_IMEI:
+ case Tag::ATTESTATION_ID_MEID:
+ case Tag::ATTESTATION_ID_MANUFACTURER:
+ case Tag::ATTESTATION_ID_MODEL:
+ case Tag::ASSOCIATED_DATA:
+ case Tag::NONCE:
+ return a.blob == b.blob;
+
+ /* Enum tags */
+ case Tag::PURPOSE:
+ return a.f.purpose == b.f.purpose;
+ case Tag::ALGORITHM:
+ return a.f.algorithm == b.f.algorithm;
+ case Tag::BLOCK_MODE:
+ return a.f.blockMode == b.f.blockMode;
+ case Tag::DIGEST:
+ return a.f.digest == b.f.digest;
+ case Tag::PADDING:
+ return a.f.paddingMode == b.f.paddingMode;
+ case Tag::EC_CURVE:
+ return a.f.ecCurve == b.f.ecCurve;
+ case Tag::BLOB_USAGE_REQUIREMENTS:
+ return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
+ case Tag::USER_AUTH_TYPE:
+ return a.f.integer == b.f.integer;
+ case Tag::ORIGIN:
+ return a.f.origin == b.f.origin;
+ case Tag::HARDWARE_TYPE:
+ return a.f.hardwareType == b.f.hardwareType;
+ }
+
+ return false;
+}
+
} // namespace V4_0
} // namespace keymaster
} // namespace hardware
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
index 0c890bd..e31804d 100644
--- a/keymaster/4.0/types.hal
+++ b/keymaster/4.0/types.hal
@@ -136,6 +136,51 @@
* if device is still on-body (requires secure
* on-body sensor. */
+ /**
+ * TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
+ * unusable except when the user has provided proof of physical presence. Proof of physical
+ * presence must be a signal that cannot be triggered by an attacker who doesn't have one of:
+ *
+ * a) Physical control of the device or
+ *
+ * b) Control of the secure environment that holds the key.
+ *
+ * For instance, proof of user identity may be considered proof of presence if it meets the
+ * requirements. However, proof of identity established in one security domain (e.g. TEE) does
+ * not constitute proof of presence in another security domain (e.g. StrongBox), and no
+ * mechanism analogous to the authentication token is defined for communicating proof of
+ * presence across security domains.
+ *
+ * Some examples:
+ *
+ * A hardware button hardwired to a pin on a StrongBox device in such a way that nothing
+ * other than a button press can trigger the signal constitutes proof of physical presence
+ * for StrongBox keys.
+ *
+ * Fingerprint authentication provides proof of presence (and identity) for TEE keys if the
+ * TEE has exclusive control of the fingerprint scanner and performs fingerprint matching.
+ *
+ * Password authentication does not provide proof of presence to either TEE or StrongBox,
+ * even if TEE or StrongBox does the password matching, because password input is handled by
+ * the non-secure world, which means an attacker who has compromised Android can spoof
+ * password authentication.
+ *
+ * Note that no mechanism is defined for delivering proof of presence to Keymaster,
+ * except perhaps as implied by an auth token. This means that Keymaster must be able to check
+ * proof of presence some other way. Further, the proof of presence must be performed between
+ * begin() and the first call to update() or finish(). If the first update() or the finish()
+ * call is made without proof of presence, the keymaster method must return
+ * ErrorCode::PROOF_OF_PRESENCE_REQUIRED and abort the operation. The caller must delay the
+ * update() or finish() call until proof of presence has been provided, which means the caller
+ * must also have some mechanism for verifying that the proof has been provided.
+ *
+ * Only one operation requiring TUP may be in flight at a time. If begin() has already been
+ * called on one key with TRUSTED_USER_PRESENCE_REQUIRED, and another begin() comes in for that
+ * key or another with TRUSTED_USER_PRESENCE_REQUIRED, Keymaster must return
+ * ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED.
+ */
+ TRUSTED_USER_PRESENCE_REQUIRED = TagType:BOOL | 507,
+
/* Application access control */
APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
@@ -195,6 +240,7 @@
/** Block ciphers algorithms */
AES = 32,
+ TRIPLE_DES = 33,
/** MAC algorithms */
HMAC = 128,
@@ -381,6 +427,8 @@
CANNOT_ATTEST_IDS = -66,
ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
HARDWARE_TYPE_UNAVAILABLE = -68,
+ PROOF_OF_PRESENCE_REQUIRED = -69,
+ CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
UNIMPLEMENTED = -100,
VERSION_MISMATCH = -101,
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 3c3063c..e705d66 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -18,6 +18,8 @@
name: "VtsHalKeymasterV4_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
+ "HmacKeySharingTest.cpp",
+ "KeymasterHidlTest.cpp",
"keymaster_hidl_hal_test.cpp",
],
static_libs: [
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
new file mode 100644
index 0000000..96c47a8
--- /dev/null
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KeymasterHidlTest.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace test {
+
+/**
+ * HmacKeySharingTest extends KeymasterHidlTest with some utilities that make writing HMAC sharing
+ * tests easier.
+ */
+class HmacKeySharingTest : public KeymasterHidlTest {
+ protected:
+ struct GetParamsResult {
+ ErrorCode error;
+ HmacSharingParameters params;
+ auto tie() { return std::tie(error, params); }
+ };
+
+ struct ComputeHmacResult {
+ ErrorCode error;
+ HidlBuf sharing_check;
+ auto tie() { return std::tie(error, sharing_check); }
+ };
+
+ using KeymasterVec = std::vector<sp<IKeymasterDevice>>;
+ using ByteString = std::basic_string<uint8_t>;
+ // using NonceVec = std::vector<HidlBuf>;
+
+ GetParamsResult getHmacSharingParameters(IKeymasterDevice& keymaster) {
+ GetParamsResult result;
+ EXPECT_TRUE(keymaster
+ .getHmacSharingParameters([&](auto error, auto params) {
+ result.tie() = std::tie(error, params);
+ })
+ .isOk());
+ return result;
+ }
+
+ hidl_vec<HmacSharingParameters> getHmacSharingParameters(const KeymasterVec& keymasters) {
+ std::vector<HmacSharingParameters> paramsVec;
+ for (auto& keymaster : keymasters) {
+ auto result = getHmacSharingParameters(*keymaster);
+ EXPECT_EQ(ErrorCode::OK, result.error);
+ if (result.error == ErrorCode::OK) paramsVec.push_back(std::move(result.params));
+ }
+ return paramsVec;
+ }
+
+ ComputeHmacResult computeSharedHmac(IKeymasterDevice& keymaster,
+ const hidl_vec<HmacSharingParameters>& params) {
+ ComputeHmacResult result;
+ EXPECT_TRUE(keymaster
+ .computeSharedHmac(params,
+ [&](auto error, auto params) {
+ result.tie() = std::tie(error, params);
+ })
+ .isOk());
+ return result;
+ }
+
+ std::vector<ComputeHmacResult> computeSharedHmac(
+ const KeymasterVec& keymasters, const hidl_vec<HmacSharingParameters>& paramsVec) {
+ std::vector<ComputeHmacResult> resultVec;
+ for (auto& keymaster : keymasters) {
+ resultVec.push_back(computeSharedHmac(*keymaster, paramsVec));
+ }
+ return resultVec;
+ }
+
+ std::vector<ByteString> copyNonces(const hidl_vec<HmacSharingParameters>& paramsVec) {
+ std::vector<ByteString> nonces;
+ for (auto& param : paramsVec) {
+ nonces.emplace_back(param.nonce.data(), param.nonce.size());
+ }
+ return nonces;
+ }
+
+ void verifyResponses(const HidlBuf& expected, const std::vector<ComputeHmacResult>& responses) {
+ for (auto& response : responses) {
+ EXPECT_EQ(ErrorCode::OK, response.error);
+ EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
+ }
+ }
+};
+
+TEST_F(HmacKeySharingTest, GetParameters) {
+ auto result1 = getHmacSharingParameters(keymaster());
+ EXPECT_EQ(ErrorCode::OK, result1.error);
+
+ auto result2 = getHmacSharingParameters(keymaster());
+ EXPECT_EQ(ErrorCode::OK, result2.error);
+
+ ASSERT_EQ(result1.params.seed, result2.params.seed)
+ << "A given keymaster should always return the same seed.";
+ ASSERT_EQ(result1.params.nonce, result2.params.nonce)
+ << "A given keymaster should always return the same nonce until restart.";
+}
+
+TEST_F(HmacKeySharingTest, ComputeSharedHmac) {
+ auto params = getHmacSharingParameters(all_keymasters());
+ ASSERT_EQ(all_keymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
+
+ auto nonces = copyNonces(params);
+ EXPECT_EQ(all_keymasters().size(), nonces.size());
+ std::sort(nonces.begin(), nonces.end());
+ std::unique(nonces.begin(), nonces.end());
+ EXPECT_EQ(all_keymasters().size(), nonces.size());
+
+ auto responses = computeSharedHmac(all_keymasters(), params);
+ ASSERT_GT(responses.size(), 0U);
+ verifyResponses(responses[0].sharing_check, responses);
+
+ // Do it a second time. Should get the same answers.
+ params = getHmacSharingParameters(all_keymasters());
+ ASSERT_EQ(all_keymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
+
+ responses = computeSharedHmac(all_keymasters(), params);
+ ASSERT_GT(responses.size(), 0U);
+ verifyResponses(responses[0].sharing_check, responses);
+}
+
+template <class F>
+class final_action {
+ public:
+ explicit final_action(F f) : f_(move(f)) {}
+ ~final_action() { f_(); }
+
+ private:
+ F f_;
+};
+
+template <class F>
+inline final_action<F> finally(const F& f) {
+ return final_action<F>(f);
+}
+
+TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
+ // Important: The execution of this test gets the keymaster implementations on the device out of
+ // sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
+ // devices, this still has the potential to cause confusion. To mitigate that, we always
+ // (barring crashes :-/) re-run the unmodified agreement process on our way out.
+ auto fixup_hmac = finally(
+ [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+
+ auto params = getHmacSharingParameters(all_keymasters());
+ ASSERT_EQ(all_keymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
+
+ // All should be well in the normal case
+ auto responses = computeSharedHmac(all_keymasters(), params);
+
+ ASSERT_GT(responses.size(), 0U);
+ HidlBuf correct_response = responses[0].sharing_check;
+ verifyResponses(correct_response, responses);
+
+ // Pick a random param, a random byte within the param's nonce, and a random bit within
+ // the byte. Flip that bit.
+ size_t param_to_tweak = rand() % params.size();
+ uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
+ uint8_t bit_to_tweak = rand() % 8;
+ params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
+
+ responses = computeSharedHmac(all_keymasters(), params);
+ for (size_t i = 0; i < responses.size(); ++i) {
+ if (i == param_to_tweak) {
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+ << "Keymaster that provided tweaked param should fail to compute HMAC key";
+ } else {
+ EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+ EXPECT_NE(correct_response, responses[i].sharing_check)
+ << "Others should calculate a different HMAC key, due to the tweaked nonce.";
+ }
+ }
+}
+
+TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
+ // Important: The execution of this test gets the keymaster implementations on the device out of
+ // sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
+ // devices, this still has the potential to cause confusion. To mitigate that, we always
+ // (barring crashes :-/) re-run the unmodified agreement process on our way out.
+ auto fixup_hmac = finally(
+ [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+
+ auto params = getHmacSharingParameters(all_keymasters());
+ ASSERT_EQ(all_keymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
+
+ // All should be well in the normal case
+ auto responses = computeSharedHmac(all_keymasters(), params);
+
+ ASSERT_GT(responses.size(), 0U);
+ HidlBuf correct_response = responses[0].sharing_check;
+ verifyResponses(correct_response, responses);
+
+ // Pick a random param and modify the seed. We just increase the seed length by 1. It doesn't
+ // matter what value is in the additional byte; it changes the seed regardless.
+ auto param_to_tweak = rand() % params.size();
+ auto& to_tweak = params[param_to_tweak].seed;
+ to_tweak.resize(to_tweak.size() + 1);
+
+ responses = computeSharedHmac(all_keymasters(), params);
+ for (size_t i = 0; i < responses.size(); ++i) {
+ if (i == param_to_tweak) {
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+ << "Keymaster that provided tweaked param should fail to compute HMAC key ";
+ } else {
+ EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+ EXPECT_NE(correct_response, responses[i].sharing_check)
+ << "Others should calculate a different HMAC key, due to the tweaked nonce.";
+ }
+ }
+}
+
+} // namespace test
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
new file mode 100644
index 0000000..13b6b2f
--- /dev/null
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -0,0 +1,589 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KeymasterHidlTest.h"
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include <keymasterV4_0/key_param_output.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
+ if (set.size() == 0)
+ os << "(Empty)" << ::std::endl;
+ else {
+ os << "\n";
+ for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl;
+ }
+ return os;
+}
+
+namespace test {
+
+sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
+std::vector<sp<IKeymasterDevice>> KeymasterHidlTest::all_keymasters_;
+uint32_t KeymasterHidlTest::os_version_;
+uint32_t KeymasterHidlTest::os_patch_level_;
+SecurityLevel KeymasterHidlTest::securityLevel_;
+hidl_string KeymasterHidlTest::name_;
+hidl_string KeymasterHidlTest::author_;
+
+void KeymasterHidlTest::SetUpTestCase() {
+ string service_name = KeymasterHidlEnvironment::Instance()->getServiceName<IKeymasterDevice>();
+ keymaster_ = ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(service_name);
+ ASSERT_NE(keymaster_, nullptr);
+
+ ASSERT_TRUE(keymaster_
+ ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+ const hidl_string& author) {
+ securityLevel_ = securityLevel;
+ name_ = name;
+ author_ = author;
+ })
+ .isOk());
+
+ os_version_ = ::keymaster::GetOsVersion();
+ os_patch_level_ = ::keymaster::GetOsPatchlevel();
+
+ auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService();
+ ASSERT_NE(nullptr, service_manager.get());
+
+ all_keymasters_.push_back(keymaster_);
+ service_manager->listByInterface(
+ IKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
+ for (auto& name : names) {
+ if (name == service_name) continue;
+ auto keymaster =
+ ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(name);
+ ASSERT_NE(keymaster, nullptr);
+ all_keymasters_.push_back(keymaster);
+ }
+ });
+}
+
+ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
+ KeyCharacteristics* key_characteristics) {
+ EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug";
+ EXPECT_EQ(0U, key_blob->size()) << "Key blob not empty before generating key. Test bug.";
+ EXPECT_NE(key_characteristics, nullptr)
+ << "Previous characteristics not deleted before generating key. Test bug.";
+
+ ErrorCode error;
+ EXPECT_TRUE(keymaster_
+ ->generateKey(key_desc.hidl_data(),
+ [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+ const KeyCharacteristics& hidl_key_characteristics) {
+ error = hidl_error;
+ *key_blob = hidl_key_blob;
+ *key_characteristics = hidl_key_characteristics;
+ })
+ .isOk());
+ // On error, blob & characteristics should be empty.
+ if (error != ErrorCode::OK) {
+ EXPECT_EQ(0U, key_blob->size());
+ EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+ key_characteristics->hardwareEnforced.size()));
+ }
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc) {
+ return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeymasterHidlTest::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material, HidlBuf* key_blob,
+ KeyCharacteristics* key_characteristics) {
+ ErrorCode error;
+ EXPECT_TRUE(keymaster_
+ ->importKey(key_desc.hidl_data(), format, HidlBuf(key_material),
+ [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+ const KeyCharacteristics& hidl_key_characteristics) {
+ error = hidl_error;
+ *key_blob = hidl_key_blob;
+ *key_characteristics = hidl_key_characteristics;
+ })
+ .isOk());
+ // On error, blob & characteristics should be empty.
+ if (error != ErrorCode::OK) {
+ EXPECT_EQ(0U, key_blob->size());
+ EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+ key_characteristics->hardwareEnforced.size()));
+ }
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material) {
+ return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeymasterHidlTest::ImportWrappedKey(string wrapped_key, string wrapping_key,
+ const AuthorizationSet& wrapping_key_desc,
+ string masking_key) {
+ ErrorCode error;
+ ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
+ EXPECT_TRUE(keymaster_
+ ->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
+ [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+ const KeyCharacteristics& hidl_key_characteristics) {
+ error = hidl_error;
+ key_blob_ = hidl_key_blob;
+ key_characteristics_ = hidl_key_characteristics;
+ })
+ .isOk());
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::ExportKey(KeyFormat format, const HidlBuf& key_blob,
+ const HidlBuf& client_id, const HidlBuf& app_data,
+ HidlBuf* key_material) {
+ ErrorCode error;
+ EXPECT_TRUE(keymaster_
+ ->exportKey(format, key_blob, client_id, app_data,
+ [&](ErrorCode hidl_error_code, const HidlBuf& hidl_key_material) {
+ error = hidl_error_code;
+ *key_material = hidl_key_material;
+ })
+ .isOk());
+ // On error, blob should be empty.
+ if (error != ErrorCode::OK) {
+ EXPECT_EQ(0U, key_material->size());
+ }
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::ExportKey(KeyFormat format, HidlBuf* key_material) {
+ HidlBuf client_id, app_data;
+ return ExportKey(format, key_blob_, client_id, app_data, key_material);
+}
+
+ErrorCode KeymasterHidlTest::DeleteKey(HidlBuf* key_blob, bool keep_key_blob) {
+ auto rc = keymaster_->deleteKey(*key_blob);
+ if (!keep_key_blob) *key_blob = HidlBuf();
+ if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
+ return rc;
+}
+
+ErrorCode KeymasterHidlTest::DeleteKey(bool keep_key_blob) {
+ return DeleteKey(&key_blob_, keep_key_blob);
+}
+
+ErrorCode KeymasterHidlTest::DeleteAllKeys() {
+ ErrorCode error = keymaster_->deleteAllKeys();
+ return error;
+}
+
+void KeymasterHidlTest::CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob) {
+ auto rc = DeleteKey(key_blob, keep_key_blob);
+ EXPECT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
+}
+
+void KeymasterHidlTest::CheckedDeleteKey() {
+ CheckedDeleteKey(&key_blob_);
+}
+
+ErrorCode KeymasterHidlTest::GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
+ const HidlBuf& app_data,
+ KeyCharacteristics* key_characteristics) {
+ ErrorCode error = ErrorCode::UNKNOWN_ERROR;
+ EXPECT_TRUE(
+ keymaster_
+ ->getKeyCharacteristics(
+ key_blob, client_id, app_data,
+ [&](ErrorCode hidl_error, const KeyCharacteristics& hidl_key_characteristics) {
+ error = hidl_error, *key_characteristics = hidl_key_characteristics;
+ })
+ .isOk());
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::GetCharacteristics(const HidlBuf& key_blob,
+ KeyCharacteristics* key_characteristics) {
+ HidlBuf client_id, app_data;
+ return GetCharacteristics(key_blob, client_id, app_data, key_characteristics);
+}
+
+ErrorCode KeymasterHidlTest::Begin(KeyPurpose purpose, const HidlBuf& key_blob,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params,
+ OperationHandle* op_handle) {
+ SCOPED_TRACE("Begin");
+ ErrorCode error;
+ OperationHandle saved_handle = *op_handle;
+ EXPECT_TRUE(keymaster_
+ ->begin(purpose, key_blob, in_params.hidl_data(), HardwareAuthToken(),
+ [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+ uint64_t hidl_op_handle) {
+ error = hidl_error;
+ *out_params = hidl_out_params;
+ *op_handle = hidl_op_handle;
+ })
+ .isOk());
+ if (error != ErrorCode::OK) {
+ // Some implementations may modify *op_handle on error.
+ *op_handle = saved_handle;
+ }
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("Begin");
+ EXPECT_EQ(kOpHandleSentinel, op_handle_);
+ return Begin(purpose, key_blob_, in_params, out_params, &op_handle_);
+}
+
+ErrorCode KeymasterHidlTest::Begin(KeyPurpose purpose, const AuthorizationSet& in_params) {
+ SCOPED_TRACE("Begin");
+ AuthorizationSet out_params;
+ ErrorCode error = Begin(purpose, in_params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::Update(OperationHandle op_handle, const AuthorizationSet& in_params,
+ const string& input, AuthorizationSet* out_params,
+ string* output, size_t* input_consumed) {
+ SCOPED_TRACE("Update");
+ ErrorCode error;
+ EXPECT_TRUE(keymaster_
+ ->update(op_handle, in_params.hidl_data(), HidlBuf(input), HardwareAuthToken(),
+ VerificationToken(),
+ [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
+ const hidl_vec<KeyParameter>& hidl_out_params,
+ const HidlBuf& hidl_output) {
+ error = hidl_error;
+ out_params->push_back(AuthorizationSet(hidl_out_params));
+ output->append(hidl_output.to_string());
+ *input_consumed = hidl_input_consumed;
+ })
+ .isOk());
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::Update(const string& input, string* out, size_t* input_consumed) {
+ SCOPED_TRACE("Update");
+ AuthorizationSet out_params;
+ ErrorCode error = Update(op_handle_, AuthorizationSet() /* in_params */, input, &out_params,
+ out, input_consumed);
+ EXPECT_TRUE(out_params.empty());
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
+ const string& input, const string& signature,
+ AuthorizationSet* out_params, string* output) {
+ SCOPED_TRACE("Finish");
+ ErrorCode error;
+ EXPECT_TRUE(
+ keymaster_
+ ->finish(op_handle, in_params.hidl_data(), HidlBuf(input), HidlBuf(signature),
+ HardwareAuthToken(), VerificationToken(),
+ [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+ const HidlBuf& hidl_output) {
+ error = hidl_error;
+ *out_params = hidl_out_params;
+ output->append(hidl_output.to_string());
+ })
+ .isOk());
+ op_handle_ = kOpHandleSentinel; // So dtor doesn't Abort().
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::Finish(const string& message, string* output) {
+ SCOPED_TRACE("Finish");
+ AuthorizationSet out_params;
+ string finish_output;
+ ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message,
+ "" /* signature */, &out_params, output);
+ if (error != ErrorCode::OK) {
+ return error;
+ }
+ EXPECT_EQ(0U, out_params.size());
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::Finish(const string& message, const string& signature,
+ string* output) {
+ SCOPED_TRACE("Finish");
+ AuthorizationSet out_params;
+ ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message, signature,
+ &out_params, output);
+ op_handle_ = kOpHandleSentinel; // So dtor doesn't Abort().
+ if (error != ErrorCode::OK) {
+ return error;
+ }
+ EXPECT_EQ(0U, out_params.size());
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::Abort(OperationHandle op_handle) {
+ SCOPED_TRACE("Abort");
+ auto retval = keymaster_->abort(op_handle);
+ EXPECT_TRUE(retval.isOk());
+ return retval;
+}
+
+void KeymasterHidlTest::AbortIfNeeded() {
+ SCOPED_TRACE("AbortIfNeeded");
+ if (op_handle_ != kOpHandleSentinel) {
+ EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
+ op_handle_ = kOpHandleSentinel;
+ }
+}
+
+ErrorCode KeymasterHidlTest::AttestKey(const HidlBuf& key_blob,
+ const AuthorizationSet& attest_params,
+ hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+ SCOPED_TRACE("AttestKey");
+ ErrorCode error;
+ auto rc = keymaster_->attestKey(
+ key_blob, attest_params.hidl_data(),
+ [&](ErrorCode hidl_error, const hidl_vec<hidl_vec<uint8_t>>& hidl_cert_chain) {
+ error = hidl_error;
+ *cert_chain = hidl_cert_chain;
+ });
+
+ EXPECT_TRUE(rc.isOk()) << rc.description();
+ if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
+
+ return error;
+}
+
+ErrorCode KeymasterHidlTest::AttestKey(const AuthorizationSet& attest_params,
+ hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+ SCOPED_TRACE("AttestKey");
+ return AttestKey(key_blob_, attest_params, cert_chain);
+}
+
+string KeymasterHidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation,
+ const string& message, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("ProcessMessage");
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_));
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ string output;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(op_handle_, finish_params, message, unused, &finish_out_params, &output));
+ op_handle_ = kOpHandleSentinel;
+
+ out_params->push_back(begin_out_params);
+ out_params->push_back(finish_out_params);
+ return output;
+}
+
+string KeymasterHidlTest::SignMessage(const HidlBuf& key_blob, const string& message,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("SignMessage");
+ AuthorizationSet out_params;
+ string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return signature;
+}
+
+string KeymasterHidlTest::SignMessage(const string& message, const AuthorizationSet& params) {
+ SCOPED_TRACE("SignMessage");
+ return SignMessage(key_blob_, message, params);
+}
+
+string KeymasterHidlTest::MacMessage(const string& message, Digest digest, size_t mac_length) {
+ SCOPED_TRACE("MacMessage");
+ return SignMessage(
+ key_blob_, message,
+ AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
+}
+
+void KeymasterHidlTest::CheckHmacTestVector(const string& key, const string& message, Digest digest,
+ const string& expected_mac) {
+ SCOPED_TRACE("CheckHmacTestVector");
+ ASSERT_EQ(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(key.size() * 8)
+ .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+ .Digest(digest),
+ KeyFormat::RAW, key));
+ string signature = MacMessage(message, digest, expected_mac.size() * 8);
+ EXPECT_EQ(expected_mac, signature)
+ << "Test vector didn't match for key of size " << key.size() << " message of size "
+ << message.size() << " and digest " << digest;
+ CheckedDeleteKey();
+}
+
+void KeymasterHidlTest::CheckAesCtrTestVector(const string& key, const string& nonce,
+ const string& message,
+ const string& expected_ciphertext) {
+ SCOPED_TRACE("CheckAesCtrTestVector");
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(key.size() * 8)
+ .BlockMode(BlockMode::CTR)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE),
+ KeyFormat::RAW, key));
+
+ auto params = AuthorizationSetBuilder()
+ .Authorization(TAG_NONCE, nonce.data(), nonce.size())
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(key_blob_, message, params, &out_params);
+ EXPECT_EQ(expected_ciphertext, ciphertext);
+}
+
+void KeymasterHidlTest::CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+ PaddingMode padding_mode, const string& key,
+ const string& iv, const string& input,
+ const string& expected_output) {
+ auto authset = AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(key.size() * 7)
+ .BlockMode(block_mode)
+ .Padding(padding_mode);
+ if (iv.size()) authset.Authorization(TAG_CALLER_NONCE);
+ ASSERT_EQ(ErrorCode::OK, ImportKey(authset, KeyFormat::RAW, key));
+ auto begin_params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding_mode);
+ if (iv.size()) begin_params.Authorization(TAG_NONCE, iv.data(), iv.size());
+ AuthorizationSet output_params;
+ string output = ProcessMessage(key_blob_, purpose, input, begin_params, &output_params);
+ EXPECT_EQ(expected_output, output);
+}
+
+void KeymasterHidlTest::VerifyMessage(const HidlBuf& key_blob, const string& message,
+ const string& signature, const AuthorizationSet& params) {
+ SCOPED_TRACE("VerifyMessage");
+ AuthorizationSet begin_out_params;
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params, &op_handle_));
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ string output;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(op_handle_, finish_params, message, signature, &finish_out_params, &output));
+ op_handle_ = kOpHandleSentinel;
+ EXPECT_TRUE(output.empty());
+}
+
+void KeymasterHidlTest::VerifyMessage(const string& message, const string& signature,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("VerifyMessage");
+ VerifyMessage(key_blob_, message, signature, params);
+}
+
+string KeymasterHidlTest::EncryptMessage(const HidlBuf& key_blob, const string& message,
+ const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("EncryptMessage");
+ return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params);
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, const AuthorizationSet& params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("EncryptMessage");
+ return EncryptMessage(key_blob_, message, params, out_params);
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, const AuthorizationSet& params) {
+ SCOPED_TRACE("EncryptMessage");
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+ return ciphertext;
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, BlockMode block_mode,
+ PaddingMode padding) {
+ SCOPED_TRACE("EncryptMessage");
+ auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+ return ciphertext;
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, BlockMode block_mode,
+ PaddingMode padding, HidlBuf* iv_out) {
+ SCOPED_TRACE("EncryptMessage");
+ auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_EQ(1U, out_params.size());
+ auto ivVal = out_params.GetTagValue(TAG_NONCE);
+ EXPECT_TRUE(ivVal.isOk());
+ *iv_out = ivVal.value();
+ return ciphertext;
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, BlockMode block_mode,
+ PaddingMode padding, const HidlBuf& iv_in) {
+ SCOPED_TRACE("EncryptMessage");
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(padding)
+ .Authorization(TAG_NONCE, iv_in);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ return ciphertext;
+}
+
+string KeymasterHidlTest::DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet out_params;
+ string plaintext =
+ ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return plaintext;
+}
+
+string KeymasterHidlTest::DecryptMessage(const string& ciphertext, const AuthorizationSet& params) {
+ SCOPED_TRACE("DecryptMessage");
+ return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+string KeymasterHidlTest::DecryptMessage(const string& ciphertext, BlockMode block_mode,
+ PaddingMode padding_mode, const HidlBuf& iv) {
+ SCOPED_TRACE("DecryptMessage");
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(padding_mode)
+ .Authorization(TAG_NONCE, iv);
+ return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+std::pair<ErrorCode, HidlBuf> KeymasterHidlTest::UpgradeKey(const HidlBuf& key_blob) {
+ std::pair<ErrorCode, HidlBuf> retval;
+ keymaster_->upgradeKey(key_blob, hidl_vec<KeyParameter>(),
+ [&](ErrorCode error, const hidl_vec<uint8_t>& upgraded_blob) {
+ retval = std::tie(error, upgraded_blob);
+ });
+ return retval;
+}
+
+} // namespace test
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
new file mode 100644
index 0000000..0c73f05
--- /dev/null
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <android/hardware/keymaster/4.0/types.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <keymaster/keymaster_configuration.h>
+
+#include <keymasterV4_0/authorization_set.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
+
+namespace test {
+
+using ::android::sp;
+using ::std::string;
+
+class HidlBuf : public hidl_vec<uint8_t> {
+ typedef hidl_vec<uint8_t> super;
+
+ public:
+ HidlBuf() {}
+ HidlBuf(const super& other) : super(other) {}
+ HidlBuf(super&& other) : super(std::move(other)) {}
+ explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
+
+ HidlBuf& operator=(const super& other) {
+ super::operator=(other);
+ return *this;
+ }
+
+ HidlBuf& operator=(super&& other) {
+ super::operator=(std::move(other));
+ return *this;
+ }
+
+ HidlBuf& operator=(const string& other) {
+ resize(other.size());
+ std::copy(other.begin(), other.end(), begin());
+ return *this;
+ }
+
+ string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
+
+class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static KeymasterHidlEnvironment* Instance() {
+ static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
+ return instance;
+ }
+
+ void registerTestServices() override { registerTestService<IKeymasterDevice>(); }
+
+ private:
+ KeymasterHidlEnvironment(){};
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(KeymasterHidlEnvironment);
+};
+
+class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void TearDown() override {
+ if (key_blob_.size()) {
+ CheckedDeleteKey();
+ }
+ AbortIfNeeded();
+ }
+
+ // SetUpTestCase runs only once per test case, not once per test.
+ static void SetUpTestCase();
+ static void TearDownTestCase() {
+ keymaster_.clear();
+ all_keymasters_.clear();
+ }
+
+ static IKeymasterDevice& keymaster() { return *keymaster_; }
+ static const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
+ static uint32_t os_version() { return os_version_; }
+ static uint32_t os_patch_level() { return os_patch_level_; }
+
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
+ KeyCharacteristics* key_characteristics);
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc);
+
+ ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material, HidlBuf* key_blob,
+ KeyCharacteristics* key_characteristics);
+ ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material);
+
+ ErrorCode ImportWrappedKey(string wrapped_key, string wrapping_key,
+ const AuthorizationSet& wrapping_key_desc, string masking_key);
+
+ ErrorCode ExportKey(KeyFormat format, const HidlBuf& key_blob, const HidlBuf& client_id,
+ const HidlBuf& app_data, HidlBuf* key_material);
+ ErrorCode ExportKey(KeyFormat format, HidlBuf* key_material);
+
+ ErrorCode DeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
+ ErrorCode DeleteKey(bool keep_key_blob = false);
+
+ ErrorCode DeleteAllKeys();
+
+ void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
+ void CheckedDeleteKey();
+
+ ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
+ const HidlBuf& app_data, KeyCharacteristics* key_characteristics);
+ ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics);
+
+ ErrorCode Begin(KeyPurpose purpose, const HidlBuf& key_blob, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params, OperationHandle* op_handle);
+ ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params);
+ ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params);
+
+ ErrorCode Update(OperationHandle op_handle, const AuthorizationSet& in_params,
+ const string& input, AuthorizationSet* out_params, string* output,
+ size_t* input_consumed);
+ ErrorCode Update(const string& input, string* out, size_t* input_consumed);
+
+ ErrorCode Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
+ const string& input, const string& signature, AuthorizationSet* out_params,
+ string* output);
+ ErrorCode Finish(const string& message, string* output);
+ ErrorCode Finish(const string& message, const string& signature, string* output);
+ ErrorCode Finish(string* output) { return Finish(string(), output); }
+
+ ErrorCode Abort(OperationHandle op_handle);
+
+ void AbortIfNeeded();
+
+ ErrorCode AttestKey(const HidlBuf& key_blob, const AuthorizationSet& attest_params,
+ hidl_vec<hidl_vec<uint8_t>>* cert_chain);
+ ErrorCode AttestKey(const AuthorizationSet& attest_params,
+ hidl_vec<hidl_vec<uint8_t>>* cert_chain);
+
+ string ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const string& message,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params);
+
+ string SignMessage(const HidlBuf& key_blob, const string& message,
+ const AuthorizationSet& params);
+ string SignMessage(const string& message, const AuthorizationSet& params);
+
+ string MacMessage(const string& message, Digest digest, size_t mac_length);
+
+ void CheckHmacTestVector(const string& key, const string& message, Digest digest,
+ const string& expected_mac);
+
+ void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
+ const string& expected_ciphertext);
+
+ void CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+ PaddingMode padding_mode, const string& key, const string& iv,
+ const string& input, const string& expected_output);
+
+ void VerifyMessage(const HidlBuf& key_blob, const string& message, const string& signature,
+ const AuthorizationSet& params);
+ void VerifyMessage(const string& message, const string& signature,
+ const AuthorizationSet& params);
+
+ string EncryptMessage(const HidlBuf& key_blob, const string& message,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params);
+ string EncryptMessage(const string& message, const AuthorizationSet& params,
+ AuthorizationSet* out_params);
+ string EncryptMessage(const string& message, const AuthorizationSet& params);
+ string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding);
+ string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+ HidlBuf* iv_out);
+ string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+ const HidlBuf& iv_in);
+
+ string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
+ const AuthorizationSet& params);
+ string DecryptMessage(const string& ciphertext, const AuthorizationSet& params);
+ string DecryptMessage(const string& ciphertext, BlockMode block_mode, PaddingMode padding_mode,
+ const HidlBuf& iv);
+
+ std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob);
+
+ static bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
+
+ HidlBuf key_blob_;
+ KeyCharacteristics key_characteristics_;
+ OperationHandle op_handle_ = kOpHandleSentinel;
+
+ private:
+ static sp<IKeymasterDevice> keymaster_;
+ static std::vector<sp<IKeymasterDevice>> all_keymasters_;
+ static uint32_t os_version_;
+ static uint32_t os_patch_level_;
+
+ static SecurityLevel securityLevel_;
+ static hidl_string name_;
+ static hidl_string author_;
+};
+
+} // namespace test
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index c8858de..31d6ad1 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -22,21 +22,13 @@
#include <openssl/evp.h>
#include <openssl/x509.h>
-#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
-#include <android/hardware/keymaster/4.0/types.h>
#include <cutils/properties.h>
-#include <keymaster/keymaster_configuration.h>
-
-#include <VtsHalHidlTargetTestBase.h>
#include <keymasterV4_0/attestation_record.h>
-#include <keymasterV4_0/authorization_set.h>
#include <keymasterV4_0/key_param_output.h>
#include <keymasterV4_0/openssl_utils.h>
-using ::android::sp;
-
-using ::std::string;
+#include "KeymasterHidlTest.h"
static bool arm_deleteAllKeys = false;
static bool dump_Attestations = false;
@@ -60,91 +52,6 @@
namespace keymaster {
namespace V4_0 {
-bool operator==(const KeyParameter& a, const KeyParameter& b) {
- if (a.tag != b.tag) {
- return false;
- }
-
- switch (a.tag) {
- /* Boolean tags */
- case Tag::INVALID:
- case Tag::CALLER_NONCE:
- case Tag::INCLUDE_UNIQUE_ID:
- case Tag::BOOTLOADER_ONLY:
- case Tag::NO_AUTH_REQUIRED:
- case Tag::ALLOW_WHILE_ON_BODY:
- case Tag::ROLLBACK_RESISTANCE:
- case Tag::RESET_SINCE_ID_ROTATION:
- return true;
-
- /* Integer tags */
- case Tag::KEY_SIZE:
- case Tag::MIN_MAC_LENGTH:
- case Tag::MIN_SECONDS_BETWEEN_OPS:
- case Tag::MAX_USES_PER_BOOT:
- case Tag::OS_VERSION:
- case Tag::OS_PATCHLEVEL:
- case Tag::MAC_LENGTH:
- case Tag::AUTH_TIMEOUT:
- return a.f.integer == b.f.integer;
-
- /* Long integer tags */
- case Tag::RSA_PUBLIC_EXPONENT:
- case Tag::USER_SECURE_ID:
- return a.f.longInteger == b.f.longInteger;
-
- /* Date-time tags */
- case Tag::ACTIVE_DATETIME:
- case Tag::ORIGINATION_EXPIRE_DATETIME:
- case Tag::USAGE_EXPIRE_DATETIME:
- case Tag::CREATION_DATETIME:
- return a.f.dateTime == b.f.dateTime;
-
- /* Bytes tags */
- case Tag::APPLICATION_ID:
- case Tag::APPLICATION_DATA:
- case Tag::ROOT_OF_TRUST:
- case Tag::UNIQUE_ID:
- case Tag::ATTESTATION_CHALLENGE:
- case Tag::ATTESTATION_APPLICATION_ID:
- case Tag::ATTESTATION_ID_BRAND:
- case Tag::ATTESTATION_ID_DEVICE:
- case Tag::ATTESTATION_ID_PRODUCT:
- case Tag::ATTESTATION_ID_SERIAL:
- case Tag::ATTESTATION_ID_IMEI:
- case Tag::ATTESTATION_ID_MEID:
- case Tag::ATTESTATION_ID_MANUFACTURER:
- case Tag::ATTESTATION_ID_MODEL:
- case Tag::ASSOCIATED_DATA:
- case Tag::NONCE:
- return a.blob == b.blob;
-
- /* Enum tags */
- case Tag::PURPOSE:
- return a.f.purpose == b.f.purpose;
- case Tag::ALGORITHM:
- return a.f.algorithm == b.f.algorithm;
- case Tag::BLOCK_MODE:
- return a.f.blockMode == b.f.blockMode;
- case Tag::DIGEST:
- return a.f.digest == b.f.digest;
- case Tag::PADDING:
- return a.f.paddingMode == b.f.paddingMode;
- case Tag::EC_CURVE:
- return a.f.ecCurve == b.f.ecCurve;
- case Tag::BLOB_USAGE_REQUIREMENTS:
- return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
- case Tag::USER_AUTH_TYPE:
- return a.f.integer == b.f.integer;
- case Tag::ORIGIN:
- return a.f.origin == b.f.origin;
- case Tag::HARDWARE_TYPE:
- return a.f.hardwareType == b.f.hardwareType;
- }
-
- return false;
-}
-
bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
}
@@ -164,16 +71,6 @@
return a_sw == b_sw && a_tee == b_tee;
}
-::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
- if (set.size() == 0)
- os << "(Empty)" << ::std::endl;
- else {
- os << "\n";
- for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl;
- }
- return os;
-}
-
namespace test {
namespace {
@@ -369,524 +266,8 @@
return make_string(a, N);
}
-class HidlBuf : public hidl_vec<uint8_t> {
- typedef hidl_vec<uint8_t> super;
-
- public:
- HidlBuf() {}
- HidlBuf(const super& other) : super(other) {}
- HidlBuf(super&& other) : super(std::move(other)) {}
- explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
-
- HidlBuf& operator=(const super& other) {
- super::operator=(other);
- return *this;
- }
-
- HidlBuf& operator=(super&& other) {
- super::operator=(std::move(other));
- return *this;
- }
-
- HidlBuf& operator=(const string& other) {
- resize(other.size());
- for (size_t i = 0; i < other.size(); ++i) {
- (*this)[i] = static_cast<uint8_t>(other[i]);
- }
- return *this;
- }
-
- string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
-};
-
-constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
-
} // namespace
-class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static KeymasterHidlEnvironment* Instance() {
- static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
- return instance;
- }
-
- void registerTestServices() override { registerTestService<IKeymasterDevice>(); }
-
- private:
- KeymasterHidlEnvironment(){};
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(KeymasterHidlEnvironment);
-};
-
-class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- void TearDown() override {
- if (key_blob_.size()) {
- CheckedDeleteKey();
- }
- AbortIfNeeded();
- }
-
- // SetUpTestCase runs only once per test case, not once per test.
- static void SetUpTestCase() {
- string service_name =
- KeymasterHidlEnvironment::Instance()->getServiceName<IKeymasterDevice>();
- keymaster_ =
- ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(service_name);
- ASSERT_NE(keymaster_, nullptr);
-
- ASSERT_TRUE(keymaster_
- ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
- const hidl_string& author) {
- securityLevel_ = securityLevel;
- name_ = name;
- author_ = author;
- })
- .isOk());
-
- os_version_ = ::keymaster::GetOsVersion();
- os_patch_level_ = ::keymaster::GetOsPatchlevel();
- }
-
- static void TearDownTestCase() { keymaster_.clear(); }
-
- static IKeymasterDevice& keymaster() { return *keymaster_; }
- static uint32_t os_version() { return os_version_; }
- static uint32_t os_patch_level() { return os_patch_level_; }
-
- ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
- KeyCharacteristics* key_characteristics) {
- EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug";
- EXPECT_EQ(0U, key_blob->size()) << "Key blob not empty before generating key. Test bug.";
- EXPECT_NE(key_characteristics, nullptr)
- << "Previous characteristics not deleted before generating key. Test bug.";
-
- ErrorCode error;
- EXPECT_TRUE(keymaster_
- ->generateKey(key_desc.hidl_data(),
- [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
- const KeyCharacteristics& hidl_key_characteristics) {
- error = hidl_error;
- *key_blob = hidl_key_blob;
- *key_characteristics = hidl_key_characteristics;
- })
- .isOk());
- // On error, blob & characteristics should be empty.
- if (error != ErrorCode::OK) {
- EXPECT_EQ(0U, key_blob->size());
- EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
- key_characteristics->hardwareEnforced.size()));
- }
- return error;
- }
-
- ErrorCode GenerateKey(const AuthorizationSet& key_desc) {
- return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
- }
-
- ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
- const string& key_material, HidlBuf* key_blob,
- KeyCharacteristics* key_characteristics) {
- ErrorCode error;
- EXPECT_TRUE(keymaster_
- ->importKey(key_desc.hidl_data(), format, HidlBuf(key_material),
- [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
- const KeyCharacteristics& hidl_key_characteristics) {
- error = hidl_error;
- *key_blob = hidl_key_blob;
- *key_characteristics = hidl_key_characteristics;
- })
- .isOk());
- // On error, blob & characteristics should be empty.
- if (error != ErrorCode::OK) {
- EXPECT_EQ(0U, key_blob->size());
- EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
- key_characteristics->hardwareEnforced.size()));
- }
- return error;
- }
-
- ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
- const string& key_material) {
- return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
- }
-
- ErrorCode ExportKey(KeyFormat format, const HidlBuf& key_blob, const HidlBuf& client_id,
- const HidlBuf& app_data, HidlBuf* key_material) {
- ErrorCode error;
- EXPECT_TRUE(
- keymaster_
- ->exportKey(format, key_blob, client_id, app_data,
- [&](ErrorCode hidl_error_code, const HidlBuf& hidl_key_material) {
- error = hidl_error_code;
- *key_material = hidl_key_material;
- })
- .isOk());
- // On error, blob should be empty.
- if (error != ErrorCode::OK) {
- EXPECT_EQ(0U, key_material->size());
- }
- return error;
- }
-
- ErrorCode ExportKey(KeyFormat format, HidlBuf* key_material) {
- HidlBuf client_id, app_data;
- return ExportKey(format, key_blob_, client_id, app_data, key_material);
- }
-
- ErrorCode DeleteKey(HidlBuf* key_blob, bool keep_key_blob = false) {
- auto rc = keymaster_->deleteKey(*key_blob);
- if (!keep_key_blob) *key_blob = HidlBuf();
- if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
- return rc;
- }
-
- ErrorCode DeleteKey(bool keep_key_blob = false) { return DeleteKey(&key_blob_, keep_key_blob); }
-
- ErrorCode DeleteAllKeys() {
- ErrorCode error = keymaster_->deleteAllKeys();
- return error;
- }
-
- void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false) {
- auto rc = DeleteKey(key_blob, keep_key_blob);
- EXPECT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
- }
-
- void CheckedDeleteKey() { CheckedDeleteKey(&key_blob_); }
-
- ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
- const HidlBuf& app_data, KeyCharacteristics* key_characteristics) {
- ErrorCode error = ErrorCode::UNKNOWN_ERROR;
- EXPECT_TRUE(
- keymaster_
- ->getKeyCharacteristics(
- key_blob, client_id, app_data,
- [&](ErrorCode hidl_error, const KeyCharacteristics& hidl_key_characteristics) {
- error = hidl_error, *key_characteristics = hidl_key_characteristics;
- })
- .isOk());
- return error;
- }
-
- ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics) {
- HidlBuf client_id, app_data;
- return GetCharacteristics(key_blob, client_id, app_data, key_characteristics);
- }
-
- ErrorCode Begin(KeyPurpose purpose, const HidlBuf& key_blob, const AuthorizationSet& in_params,
- AuthorizationSet* out_params, OperationHandle* op_handle) {
- SCOPED_TRACE("Begin");
- ErrorCode error;
- OperationHandle saved_handle = *op_handle;
- EXPECT_TRUE(
- keymaster_
- ->begin(purpose, key_blob, in_params.hidl_data(), HardwareAuthToken(),
- [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
- uint64_t hidl_op_handle) {
- error = hidl_error;
- *out_params = hidl_out_params;
- *op_handle = hidl_op_handle;
- })
- .isOk());
- if (error != ErrorCode::OK) {
- // Some implementations may modify *op_handle on error.
- *op_handle = saved_handle;
- }
- return error;
- }
-
- ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
- AuthorizationSet* out_params) {
- SCOPED_TRACE("Begin");
- EXPECT_EQ(kOpHandleSentinel, op_handle_);
- return Begin(purpose, key_blob_, in_params, out_params, &op_handle_);
- }
-
- ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params) {
- SCOPED_TRACE("Begin");
- AuthorizationSet out_params;
- ErrorCode error = Begin(purpose, in_params, &out_params);
- EXPECT_TRUE(out_params.empty());
- return error;
- }
-
- ErrorCode Update(OperationHandle op_handle, const AuthorizationSet& in_params,
- const string& input, AuthorizationSet* out_params, string* output,
- size_t* input_consumed) {
- SCOPED_TRACE("Update");
- ErrorCode error;
- EXPECT_TRUE(keymaster_
- ->update(op_handle, in_params.hidl_data(), HidlBuf(input),
- HardwareAuthToken(), VerificationToken(),
- [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
- const hidl_vec<KeyParameter>& hidl_out_params,
- const HidlBuf& hidl_output) {
- error = hidl_error;
- out_params->push_back(AuthorizationSet(hidl_out_params));
- output->append(hidl_output.to_string());
- *input_consumed = hidl_input_consumed;
- })
- .isOk());
- return error;
- }
-
- ErrorCode Update(const string& input, string* out, size_t* input_consumed) {
- SCOPED_TRACE("Update");
- AuthorizationSet out_params;
- ErrorCode error = Update(op_handle_, AuthorizationSet() /* in_params */, input, &out_params,
- out, input_consumed);
- EXPECT_TRUE(out_params.empty());
- return error;
- }
-
- ErrorCode Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
- const string& input, const string& signature, AuthorizationSet* out_params,
- string* output) {
- SCOPED_TRACE("Finish");
- ErrorCode error;
- EXPECT_TRUE(
- keymaster_
- ->finish(op_handle, in_params.hidl_data(), HidlBuf(input), HidlBuf(signature),
- HardwareAuthToken(), VerificationToken(),
- [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
- const HidlBuf& hidl_output) {
- error = hidl_error;
- *out_params = hidl_out_params;
- output->append(hidl_output.to_string());
- })
- .isOk());
- op_handle_ = kOpHandleSentinel; // So dtor doesn't Abort().
- return error;
- }
-
- ErrorCode Finish(const string& message, string* output) {
- SCOPED_TRACE("Finish");
- AuthorizationSet out_params;
- string finish_output;
- ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message,
- "" /* signature */, &out_params, output);
- if (error != ErrorCode::OK) {
- return error;
- }
- EXPECT_EQ(0U, out_params.size());
- return error;
- }
-
- ErrorCode Finish(const string& message, const string& signature, string* output) {
- SCOPED_TRACE("Finish");
- AuthorizationSet out_params;
- ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message, signature,
- &out_params, output);
- op_handle_ = kOpHandleSentinel; // So dtor doesn't Abort().
- if (error != ErrorCode::OK) {
- return error;
- }
- EXPECT_EQ(0U, out_params.size());
- return error;
- }
-
- ErrorCode Abort(OperationHandle op_handle) {
- SCOPED_TRACE("Abort");
- auto retval = keymaster_->abort(op_handle);
- EXPECT_TRUE(retval.isOk());
- return retval;
- }
-
- void AbortIfNeeded() {
- SCOPED_TRACE("AbortIfNeeded");
- if (op_handle_ != kOpHandleSentinel) {
- EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
- op_handle_ = kOpHandleSentinel;
- }
- }
-
- ErrorCode AttestKey(const HidlBuf& key_blob, const AuthorizationSet& attest_params,
- hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
- SCOPED_TRACE("AttestKey");
- ErrorCode error;
- auto rc = keymaster_->attestKey(
- key_blob, attest_params.hidl_data(),
- [&](ErrorCode hidl_error, const hidl_vec<hidl_vec<uint8_t>>& hidl_cert_chain) {
- error = hidl_error;
- *cert_chain = hidl_cert_chain;
- });
-
- EXPECT_TRUE(rc.isOk()) << rc.description();
- if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
-
- return error;
- }
-
- ErrorCode AttestKey(const AuthorizationSet& attest_params,
- hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
- SCOPED_TRACE("AttestKey");
- return AttestKey(key_blob_, attest_params, cert_chain);
- }
-
- string ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const string& message,
- const AuthorizationSet& in_params, AuthorizationSet* out_params) {
- SCOPED_TRACE("ProcessMessage");
- AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK,
- Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_));
-
- string unused;
- AuthorizationSet finish_params;
- AuthorizationSet finish_out_params;
- string output;
- EXPECT_EQ(ErrorCode::OK,
- Finish(op_handle_, finish_params, message, unused, &finish_out_params, &output));
- op_handle_ = kOpHandleSentinel;
-
- out_params->push_back(begin_out_params);
- out_params->push_back(finish_out_params);
- return output;
- }
-
- string SignMessage(const HidlBuf& key_blob, const string& message,
- const AuthorizationSet& params) {
- SCOPED_TRACE("SignMessage");
- AuthorizationSet out_params;
- string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params);
- EXPECT_TRUE(out_params.empty());
- return signature;
- }
-
- string SignMessage(const string& message, const AuthorizationSet& params) {
- SCOPED_TRACE("SignMessage");
- return SignMessage(key_blob_, message, params);
- }
-
- string MacMessage(const string& message, Digest digest, size_t mac_length) {
- SCOPED_TRACE("MacMessage");
- return SignMessage(
- key_blob_, message,
- AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
- }
-
- void CheckHmacTestVector(const string& key, const string& message, Digest digest,
- const string& expected_mac) {
- SCOPED_TRACE("CheckHmacTestVector");
- ASSERT_EQ(ErrorCode::OK,
- ImportKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .HmacKey(key.size() * 8)
- .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
- .Digest(digest),
- KeyFormat::RAW, key));
- string signature = MacMessage(message, digest, expected_mac.size() * 8);
- EXPECT_EQ(expected_mac, signature)
- << "Test vector didn't match for key of size " << key.size() << " message of size "
- << message.size() << " and digest " << digest;
- CheckedDeleteKey();
- }
-
- void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
- const string& expected_ciphertext) {
- SCOPED_TRACE("CheckAesCtrTestVector");
- ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .AesEncryptionKey(key.size() * 8)
- .BlockMode(BlockMode::CTR)
- .Authorization(TAG_CALLER_NONCE)
- .Padding(PaddingMode::NONE),
- KeyFormat::RAW, key));
-
- auto params = AuthorizationSetBuilder()
- .Authorization(TAG_NONCE, nonce.data(), nonce.size())
- .BlockMode(BlockMode::CTR)
- .Padding(PaddingMode::NONE);
- AuthorizationSet out_params;
- string ciphertext = EncryptMessage(key_blob_, message, params, &out_params);
- EXPECT_EQ(expected_ciphertext, ciphertext);
- }
-
- void VerifyMessage(const HidlBuf& key_blob, const string& message, const string& signature,
- const AuthorizationSet& params) {
- SCOPED_TRACE("VerifyMessage");
- AuthorizationSet begin_out_params;
- ASSERT_EQ(ErrorCode::OK,
- Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params, &op_handle_));
-
- string unused;
- AuthorizationSet finish_params;
- AuthorizationSet finish_out_params;
- string output;
- EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, signature,
- &finish_out_params, &output));
- op_handle_ = kOpHandleSentinel;
- EXPECT_TRUE(output.empty());
- }
-
- void VerifyMessage(const string& message, const string& signature,
- const AuthorizationSet& params) {
- SCOPED_TRACE("VerifyMessage");
- VerifyMessage(key_blob_, message, signature, params);
- }
-
- string EncryptMessage(const HidlBuf& key_blob, const string& message,
- const AuthorizationSet& in_params, AuthorizationSet* out_params) {
- SCOPED_TRACE("EncryptMessage");
- return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params);
- }
-
- string EncryptMessage(const string& message, const AuthorizationSet& params,
- AuthorizationSet* out_params) {
- SCOPED_TRACE("EncryptMessage");
- return EncryptMessage(key_blob_, message, params, out_params);
- }
-
- string EncryptMessage(const string& message, const AuthorizationSet& params) {
- SCOPED_TRACE("EncryptMessage");
- AuthorizationSet out_params;
- string ciphertext = EncryptMessage(message, params, &out_params);
- EXPECT_TRUE(out_params.empty())
- << "Output params should be empty. Contained: " << out_params;
- return ciphertext;
- }
-
- string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
- const AuthorizationSet& params) {
- SCOPED_TRACE("DecryptMessage");
- AuthorizationSet out_params;
- string plaintext =
- ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params);
- EXPECT_TRUE(out_params.empty());
- return plaintext;
- }
-
- string DecryptMessage(const string& ciphertext, const AuthorizationSet& params) {
- SCOPED_TRACE("DecryptMessage");
- return DecryptMessage(key_blob_, ciphertext, params);
- }
-
- std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob) {
- std::pair<ErrorCode, HidlBuf> retval;
- keymaster_->upgradeKey(key_blob, hidl_vec<KeyParameter>(),
- [&](ErrorCode error, const hidl_vec<uint8_t>& upgraded_blob) {
- retval = std::tie(error, upgraded_blob);
- });
- return retval;
- }
-
- static bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
-
- HidlBuf key_blob_;
- KeyCharacteristics key_characteristics_;
- OperationHandle op_handle_ = kOpHandleSentinel;
-
- private:
- static sp<IKeymasterDevice> keymaster_;
- static uint32_t os_version_;
- static uint32_t os_patch_level_;
-
- static SecurityLevel securityLevel_;
- static hidl_string name_;
- static hidl_string author_;
-};
-
bool verify_attestation_record(const string& challenge, const string& app_id,
AuthorizationSet expected_sw_enforced,
AuthorizationSet expected_tee_enforced,
@@ -946,13 +327,6 @@
return true;
}
-sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
-uint32_t KeymasterHidlTest::os_version_;
-uint32_t KeymasterHidlTest::os_patch_level_;
-SecurityLevel KeymasterHidlTest::securityLevel_;
-hidl_string KeymasterHidlTest::name_;
-hidl_string KeymasterHidlTest::author_;
-
class NewKeyGenerationTest : public KeymasterHidlTest {
protected:
void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) {
@@ -2421,6 +1795,111 @@
VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
}
+auto wrapped_key = hex2str(
+ "30820173020100048201006F5C273914D9E7EAB667FE62456A57DE64BED4A57DB3EFBB77E6907C82CC36B0BD12CB8A"
+ "85F3F8BC08A26C58186DB5C35636063388A04AE5579D3BDC057F9BB0EB6FDDA5E836DBB1F18A4546A64BA06E3D0132"
+ "AAA3306676638C786FAF0722E6E4145E0C91B009C422691F9F42F9F179DA93E16E7793DE5960E77A387433F0B43E49"
+ "3A7CF77ECA25BA724CC02F916D5792CAA76BC0756D3DB5D110D209B8B30285E9653D91FD89E953F351D82ACE1422CC"
+ "A146F8BD0C2F4CC32D1F81D894F4650043DB46109869696319A1A011BB003F2EBD8FA20B4A43F3226C1F182A39AE81"
+ "A35B9B7590A48B6A6874C9CC0EE0CD9528FB908688B4111932DF478CD7A92B50040CD796B02C370F1FA4CC0124F130"
+ "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420CCD54085"
+ "5F833A5E1480BFD2D36FAF3AEEE15DF5BEABE2691BC82DDE2A7AA91004107CB81BDDCD09E8F4DF575726279F3229");
+
+auto wrapped_key_masked = hex2str(
+ "30820173020100048201009059BB6E48F8036ABE1800D9C74F3DB5F20448F035C2C78AFBCC28AF26581061298CAC78"
+ "A8CA5B79721B60B74490555168488ED696C8930D00463C6FC81BF0B6E4E26C93E018D0E3DC8754C6B261E0A7C3A6DA"
+ "1A223EB59ACA8E13348F14B9E944AF3C224906C1ABFE21ADDEE81FC641D45E092C6B0A75A9BA56C05529AE47ECA0D5"
+ "CD3568501CF04D47391FC695EDE19A3022B347D1BDC6C792A08AA014F87DD4BBD44777B14D7D2273191DDCFE4E8512"
+ "EFA677A14E68E5D820C5513331D687C08B6317FA64D404231D05C74CDD9AEB89D253FBE07154B2080CF4ACA5E1EFCB"
+ "53EB193E8A01DD5F9634B65EF9B49899003E245FDA6A3B137FAC1263E55A6E1D040C6D9721D08589581AB49204A330"
+ "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420A61C6E24"
+ "7E25B3E6E69AA78EB03C2D4AC20D1F99A9A024A76F35C8E2CAB9B68D04101FF7A0E793B9EE4AECEBB9AC4C545254");
+
+auto wrapping_key = hex2str(
+ "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d8900ce56"
+ "b0067f7d70e1fc653f3f34d194c1fed50018fb43db937b06e673a837313d56b1c725150a3fef86acbddc41bb759c28"
+ "54eae32d35841efb5c18d82bc90a1cb5c1d55adf245b02911f0b7cda88c421ff0ebafe7c0d23be312d7bd5921ffaea"
+ "1347c157406fef718f682643e4e5d33c6703d61c0cf7ac0bf4645c11f5c1374c3886427411c449796792e0bef75dec"
+ "858a2123c36753e02a95a96d7c454b504de385a642e0dfc3e60ac3a7ee4991d0d48b0172a95f9536f02ba13cecccb9"
+ "2b727db5c27e5b2f5cec09600b286af5cf14c42024c61ddfe71c2a8d7458f185234cb00e01d282f10f8fc6721d2aed"
+ "3f4833cca2bd8fa62821dd55020301000102820100431447b6251908112b1ee76f99f3711a52b6630960046c2de70d"
+ "e188d833f8b8b91e4d785caeeeaf4f0f74414e2cda40641f7fe24f14c67a88959bdb27766df9e710b630a03adc683b"
+ "5d2c43080e52bee71e9eaeb6de297a5fea1072070d181c822bccff087d63c940ba8a45f670feb29fb4484d1c95e6d2"
+ "579ba02aae0a00900c3ebf490e3d2cd7ee8d0e20c536e4dc5a5097272888cddd7e91f228b1c4d7474c55b8fcd618c4"
+ "a957bbddd5ad7407cc312d8d98a5caf7e08f4a0d6b45bb41c652659d5a5ba05b663737a8696281865ba20fbdd7f851"
+ "e6c56e8cbe0ddbbf24dc03b2d2cb4c3d540fb0af52e034a2d06698b128e5f101e3b51a34f8d8b4f8618102818100de"
+ "392e18d682c829266cc3454e1d6166242f32d9a1d10577753e904ea7d08bff841be5bac82a164c5970007047b8c517"
+ "db8f8f84e37bd5988561bdf503d4dc2bdb38f885434ae42c355f725c9a60f91f0788e1f1a97223b524b5357fdf72e2"
+ "f696bab7d78e32bf92ba8e1864eab1229e91346130748a6e3c124f9149d71c743502818100c95387c0f9d35f137b57"
+ "d0d65c397c5e21cc251e47008ed62a542409c8b6b6ac7f8967b3863ca645fcce49582a9aa17349db6c4a95affdae0d"
+ "ae612e1afac99ed39a2d934c880440aed8832f9843163a47f27f392199dc1202f9a0f9bd08308007cb1e4e7f583093"
+ "66a7de25f7c3c9b880677c068e1be936e81288815252a8a102818057ff8ca1895080b2cae486ef0adfd791fb0235c0"
+ "b8b36cd6c136e52e4085f4ea5a063212a4f105a3764743e53281988aba073f6e0027298e1c4378556e0efca0e14ece"
+ "1af76ad0b030f27af6f0ab35fb73a060d8b1a0e142fa2647e93b32e36d8282ae0a4de50ab7afe85500a16f43a64719"
+ "d6e2b9439823719cd08bcd03178102818100ba73b0bb28e3f81e9bd1c568713b101241acc607976c4ddccc90e65b65"
+ "56ca31516058f92b6e09f3b160ff0e374ec40d78ae4d4979fde6ac06a1a400c61dd31254186af30b22c10582a8a43e"
+ "34fe949c5f3b9755bae7baa7b7b7a6bd03b38cef55c86885fc6c1978b9cee7ef33da507c9df6b9277cff1e6aaa5d57"
+ "aca528466102818100c931617c77829dfb1270502be9195c8f2830885f57dba869536811e6864236d0c4736a0008a1"
+ "45af36b8357a7c3d139966d04c4e00934ea1aede3bb6b8ec841dc95e3f579751e2bfdfe27ae778983f959356210723"
+ "287b0affcc9f727044d48c373f1babde0724fa17a4fd4da0902c7c9b9bf27ba61be6ad02dfddda8f4e6822");
+
+string zero_masking_key =
+ hex2str("0000000000000000000000000000000000000000000000000000000000000000");
+string masking_key = hex2str("D796B02C370F1FA4CC0124F14EC8CBEBE987E825246265050F399A51FD477DFC");
+
+class ImportWrappedKeyTest : public KeymasterHidlTest {};
+
+TEST_F(ImportWrappedKeyTest, Success) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA1)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+ ASSERT_EQ(ErrorCode::OK,
+ ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key));
+
+ string message = "Hello World!";
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(message, params);
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+TEST_F(ImportWrappedKeyTest, SuccessMasked) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA1)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+ ASSERT_EQ(ErrorCode::OK,
+ ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key));
+}
+
+TEST_F(ImportWrappedKeyTest, WrongMask) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA1)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+ ASSERT_EQ(
+ ErrorCode::VERIFICATION_FAILED,
+ ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key));
+}
+
+TEST_F(ImportWrappedKeyTest, WrongPurpose) {
+ auto wrapping_key_desc = AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::SHA1)
+ .Padding(PaddingMode::RSA_OAEP);
+
+ ASSERT_EQ(
+ ErrorCode::INCOMPATIBLE_PURPOSE,
+ ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key));
+}
+
typedef KeymasterHidlTest EncryptionOperationsTest;
/*
@@ -3712,6 +3191,535 @@
EXPECT_TRUE(finish_out_params.empty());
}
+/*
+ * EncryptionOperationsTest.TripleDesEcbRoundTripSuccess
+ *
+ * Verifies that 3DES is basically functional.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
+ std::cout << "Hello" << std::endl;
+
+ auto auths = AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE);
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(auths));
+ // Two-block message.
+ string message = "1234567890123456";
+ auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+ string ciphertext1 = EncryptMessage(message, inParams);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(string(message), inParams);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // ECB is deterministic.
+ EXPECT_EQ(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, inParams);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNotAuthorized
+ *
+ * Verifies that CBC keys reject ECB usage.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+
+ auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7Padding
+ *
+ * Tests ECB mode with PKCS#7 padding, various message sizes.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)));
+
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ auto inParams =
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(message, inParams);
+ EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+ string plaintext = DecryptMessage(ciphertext, inParams);
+ EXPECT_EQ(message, plaintext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that keys configured for no padding reject PKCS7 padding
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+ for (size_t i = 0; i < 32; ++i) {
+ auto inParams =
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted padding is detected.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)));
+
+ string message = "a";
+ string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
+ EXPECT_EQ(8U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+ ++ciphertext[ciphertext.size() / 2];
+
+ AuthorizationSetBuilder begin_params;
+ begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
+ begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ size_t input_consumed;
+ EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+struct TripleDesTestVector {
+ const char* name;
+ const KeyPurpose purpose;
+ const BlockMode block_mode;
+ const PaddingMode padding_mode;
+ const char* key;
+ const char* iv;
+ const char* input;
+ const char* output;
+};
+
+// These test vectors are from NIST CAVP, plus a few custom variants to test padding, since all of
+// the NIST vectors are multiples of the block size.
+static const TripleDesTestVector kTripleDesTestVectors[] = {
+ {
+ "TECBMMT2 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "ad192fd064b5579e7a4fb3c8f794f22a", // key
+ "", // IV
+ "13bad542f3652d67", // input
+ "908e543cf2cb254f", // output
+ },
+ {
+ "TECBMMT2 Encrypt 0 PKCS7", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::PKCS7,
+ "ad192fd064b5579e7a4fb3c8f794f22a", // key
+ "", // IV
+ "13bad542f3652d6700", // input
+ "908e543cf2cb254fc40165289a89008c", // output
+ },
+ {
+ "TECBMMT2 Encrypt 0 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::ECB,
+ PaddingMode::PKCS7,
+ "ad192fd064b5579e7a4fb3c8f794f22a", // key
+ "", // IV
+ "908e543cf2cb254fc40165289a89008c", // input
+ "13bad542f3652d6700", // output
+ },
+ {
+ "TECBMMT2 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "259df16e7af804fe83b90e9bf7c7e557", // key
+ "", // IV
+ "a4619c433bbd6787c07c81728f9ac9fa", // input
+ "9e06de155c483c6bcfd834dbc8bd5830", // output
+ },
+ {
+ "TECBMMT2 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "b32ff42092024adf2076b9d3d9f19e6d", // key
+ "", // IV
+ "2f3f2a49bba807a5", // input
+ "2249973fa135fb52", // output
+ },
+ {
+ "TECBMMT2 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "023dfbe6621aa17cc219eae9cdecd923", // key
+ "", // IV
+ "54045dc71d8d565b227ec19f06fef912", // input
+ "9b071622181e6412de6066429401410d", // output
+ },
+ {
+ "TECBMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "a2b5bc67da13dc92cd9d344aa238544a0e1fa79ef76810cd", // key
+ "", // IV
+ "329d86bdf1bc5af4", // input
+ "d946c2756d78633f", // output
+ },
+ {
+ "TECBMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "49e692290d2a5e46bace79b9648a4c5d491004c262dc9d49", // key
+ "", // IV
+ "6b1540781b01ce1997adae102dbf3c5b", // input
+ "4d0dc182d6e481ac4a3dc6ab6976ccae", // output
+ },
+ {
+ "TECBMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "52daec2ac7dc1958377392682f37860b2cc1ea2304bab0e9", // key
+ "", // IV
+ "6daad94ce08acfe7", // input
+ "660e7d32dcc90e79", // output
+ },
+ {
+ "TECBMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+ "7f8fe3d3f4a48394fb682c2919926d6ddfce8932529229ce", // key
+ "", // IV
+ "e9653a0a1f05d31b9acd12d73aa9879d", // input
+ "9b2ae9d998efe62f1b592e7e1df8ff38", // output
+ },
+ {
+ "TCBCMMT2 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "34a41a8c293176c1b30732ecfe38ae8a", // key
+ "f55b4855228bd0b4", // IV
+ "7dd880d2a9ab411c", // input
+ "c91892948b6cadb4", // output
+ },
+ {
+ "TCBCMMT2 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "70a88fa1dfb9942fa77f40157ffef2ad", // key
+ "ece08ce2fdc6ce80", // IV
+ "bc225304d5a3a5c9918fc5006cbc40cc", // input
+ "27f67dc87af7ddb4b68f63fa7c2d454a", // output
+ },
+ {
+ "TCBCMMT2 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "4ff47fda89209bda8c85f7fe80192007", // key
+ "d5bc4891dabe48b9", // IV
+ "7e154b28c353adef", // input
+ "712b961ea9a1d0af", // output
+ },
+ {
+ "TCBCMMT2 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "464092cdbf736d38fb1fe6a12a94ae0e", // key
+ "5423455f00023b01", // IV
+ "3f6050b74ed64416bc23d53b0469ed7a", // input
+ "9cbe7d1b5cdd1864c3095ba810575960", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37", // key
+ "43f791134c5647ba", // IV
+ "dcc153cef81d6f24", // input
+ "92538bd8af18d3ba", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key
+ "c2e999cb6249023c", // IV
+ "c689aee38a301bb316da75db36f110b5", // input
+ "e9afaba5ec75ea1bbe65506655bb4ecb", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 1 PKCS7 variant", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::PKCS7,
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key
+ "c2e999cb6249023c", // IV
+ "c689aee38a301bb316da75db36f110b500", // input
+ "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // output
+ },
+ {
+ "TCBCMMT3 Encrypt 1 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::CBC,
+ PaddingMode::PKCS7,
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key
+ "c2e999cb6249023c", // IV
+ "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // input
+ "c689aee38a301bb316da75db36f110b500", // output
+ },
+ {
+ "TCBCMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "5eb6040d46082c7aa7d06dfd08dfeac8c18364c1548c3ba1", // key
+ "41746c7e442d3681", // IV
+ "c53a7b0ec40600fe", // input
+ "d4f00eb455de1034", // output
+ },
+ {
+ "TCBCMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+ "5b1cce7c0dc1ec49130dfb4af45785ab9179e567f2c7d549", // key
+ "3982bc02c3727d45", // IV
+ "6006f10adef52991fcc777a1238bbb65", // input
+ "edae09288e9e3bc05746d872b48e3b29", // output
+ },
+};
+
+/*
+ * EncryptionOperationsTest.TripleDesTestVector
+ *
+ * Verifies that NIST (plus a few extra) test vectors produce the correct results.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesTestVector) {
+ constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector);
+ for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) {
+ SCOPED_TRACE(test->name);
+ CheckTripleDesTestVector(test->purpose, test->block_mode, test->padding_mode,
+ hex2str(test->key), hex2str(test->iv), hex2str(test->input),
+ hex2str(test->output));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcRoundTripSuccess
+ *
+ * Validates CBC mode functionality.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+ // Two-block message.
+ string message = "1234567890123456";
+ HidlBuf iv1;
+ string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv1);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ HidlBuf iv2;
+ string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv2);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(iv1, iv2);
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv1);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCallerIv
+ *
+ * Validates that 3DES keys can allow caller-specified IVs, and use them correctly.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCallerIv) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE)));
+ string message = "1234567890123456";
+ HidlBuf iv;
+ // Don't specify IV, should get a random one.
+ string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+ EXPECT_EQ(8U, iv.size());
+
+ string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify an IV, should also work.
+ iv = HidlBuf("abcdefgh");
+ string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, iv);
+
+ // Decrypt with correct IV.
+ plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, iv);
+ EXPECT_EQ(message, plaintext);
+
+ // Now try with wrong IV.
+ plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, HidlBuf("aaaaaaaa"));
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCallerNonceProhibited.
+ *
+ * Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "12345678901234567890123456789012";
+ HidlBuf iv;
+ // Don't specify nonce, should get a random one.
+ string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+ EXPECT_EQ(8U, iv.size());
+
+ string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should fail.
+ auto input_params = AuthorizationSetBuilder()
+ .Authorization(TAG_NONCE, HidlBuf("abcdefgh"))
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED,
+ Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNotAuthorized
+ *
+ * Verifies that 3DES ECB-only keys do not allow CBC usage.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+ // Two-block message.
+ string message = "1234567890123456";
+ auto begin_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingWrongInputSize
+ *
+ * Verifies that unpadded CBC operations reject inputs that are not a multiple of block size.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+ // Message is slightly shorter than two blocks.
+ string message = "123456789012345";
+
+ auto begin_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcPkcs7Padding.
+ *
+ * Verifies that PKCS7 padding works correctly in CBC mode.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::PKCS7)));
+
+ // Try various message lengths; all should work.
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ HidlBuf iv;
+ string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+ EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+ string plaintext = DecryptMessage(ciphertext, BlockMode::CBC, PaddingMode::PKCS7, iv);
+ EXPECT_EQ(message, plaintext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+
+ // Try various message lengths; all should fail.
+ for (size_t i = 0; i < 32; ++i) {
+ auto begin_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted PKCS7 padding is rejected during decryption.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::PKCS7)));
+
+ string message = "a";
+ HidlBuf iv;
+ string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+ EXPECT_EQ(8U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+ ++ciphertext[ciphertext.size() / 2];
+
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::PKCS7)
+ .Authorization(TAG_NONCE, iv);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ size_t input_consumed;
+ EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding.
+ *
+ * Verifies that 3DES CBC works with many different input sizes.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(112)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+
+ int increment = 7;
+ string message(240, 'a');
+ AuthorizationSet input_params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+
+ string ciphertext;
+ size_t input_consumed;
+ for (size_t i = 0; i < message.size(); i += increment)
+ EXPECT_EQ(ErrorCode::OK,
+ Update(message.substr(i, increment), &ciphertext, &input_consumed));
+ EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext));
+ EXPECT_EQ(message.size(), ciphertext.size());
+
+ // Move TAG_NONCE into input_params
+ input_params = output_params;
+ input_params.push_back(TAG_BLOCK_MODE, BlockMode::CBC);
+ input_params.push_back(TAG_PADDING, PaddingMode::NONE);
+ output_params.Clear();
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment)
+ EXPECT_EQ(ErrorCode::OK,
+ Update(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+ EXPECT_EQ(ErrorCode::OK, Finish(&plaintext));
+ EXPECT_EQ(ciphertext.size(), plaintext.size());
+ EXPECT_EQ(message, plaintext);
+}
+
typedef KeymasterHidlTest MaxOperationsTest;
/*
diff --git a/soundtrigger/2.0/default/Android.bp b/soundtrigger/2.0/default/Android.bp
new file mode 100644
index 0000000..cc20f91
--- /dev/null
+++ b/soundtrigger/2.0/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "android.hardware.soundtrigger@2.0-core",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "SoundTriggerHalImpl.cpp",
+ ],
+
+ export_include_dirs: ["."],
+
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.audio.common@2.0",
+ ],
+
+ header_libs: [
+ "libaudio_system_headers",
+ "libhardware_headers",
+ ],
+}
diff --git a/soundtrigger/2.0/default/Android.mk b/soundtrigger/2.0/default/Android.mk
index 9262858..835a020 100644
--- a/soundtrigger/2.0/default/Android.mk
+++ b/soundtrigger/2.0/default/Android.mk
@@ -18,23 +18,20 @@
include $(CLEAR_VARS)
LOCAL_MODULE := android.hardware.soundtrigger@2.0-impl
-LOCAL_PROPRIETARY_MODULE := true
+LOCAL_VENDOR_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := \
- SoundTriggerHalImpl.cpp
+ FetchISoundTriggerHw.cpp
LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := \
- libhidlbase \
- libhidltransport \
- liblog \
- libutils \
libhardware \
+ libutils \
android.hardware.soundtrigger@2.0 \
- android.hardware.audio.common@2.0
+ android.hardware.soundtrigger@2.0-core
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_C_INCLUDE_DIRS := $(LOCAL_PATH)
ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
LOCAL_MULTILIB := 32
diff --git a/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp b/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp
new file mode 100644
index 0000000..bd99221
--- /dev/null
+++ b/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SoundTriggerHalImpl.h"
+
+extern "C" ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(
+ const char* /* name */) {
+ return (new ::android::hardware::soundtrigger::V2_0::implementation::SoundTriggerHalImpl())
+ ->getInterface();
+}
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
index f963fb1..612772c 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
@@ -17,9 +17,8 @@
#define LOG_TAG "SoundTriggerHalImpl"
//#define LOG_NDEBUG 0
-#include <android/log.h>
#include "SoundTriggerHalImpl.h"
-
+#include <android/log.h>
namespace android {
namespace hardware {
@@ -28,64 +27,45 @@
namespace implementation {
// static
-void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event *halEvent,
- void *cookie)
-{
+void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event* halEvent,
+ void* cookie) {
if (halEvent == NULL) {
ALOGW("soundModelCallback called with NULL event");
return;
}
sp<SoundModelClient> client =
- wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+ wp<SoundModelClient>(static_cast<SoundModelClient*>(cookie)).promote();
if (client == 0) {
ALOGW("soundModelCallback called on stale client");
return;
}
- if (halEvent->model != client->mHalHandle) {
+ if (halEvent->model != client->getHalHandle()) {
ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
- (int)halEvent->model, (int)client->mHalHandle);
+ (int)halEvent->model, (int)client->getHalHandle());
return;
}
- ISoundTriggerHwCallback::ModelEvent event;
- convertSoundModelEventFromHal(&event, halEvent);
- event.model = client->mId;
-
- client->mCallback->soundModelCallback(event, client->mCookie);
+ client->soundModelCallback(halEvent);
}
// static
-void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event *halEvent,
- void *cookie)
-{
+void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event* halEvent,
+ void* cookie) {
if (halEvent == NULL) {
ALOGW("recognitionCallback call NULL event");
return;
}
sp<SoundModelClient> client =
- wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+ wp<SoundModelClient>(static_cast<SoundModelClient*>(cookie)).promote();
if (client == 0) {
ALOGW("soundModelCallback called on stale client");
return;
}
- ISoundTriggerHwCallback::RecognitionEvent *event = convertRecognitionEventFromHal(halEvent);
- event->model = client->mId;
- if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
- client->mCallback->phraseRecognitionCallback(
- *(reinterpret_cast<ISoundTriggerHwCallback::PhraseRecognitionEvent *>(event)),
- client->mCookie);
- } else {
- client->mCallback->recognitionCallback(*event, client->mCookie);
- }
- delete event;
+ client->recognitionCallback(halEvent);
}
-
-
-// Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
-Return<void> SoundTriggerHalImpl::getProperties(getProperties_cb _hidl_cb)
-{
+Return<void> SoundTriggerHalImpl::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) {
ALOGV("getProperties() mHwDevice %p", mHwDevice);
int ret;
struct sound_trigger_properties halProperties;
@@ -100,8 +80,8 @@
convertPropertiesFromHal(&properties, &halProperties);
- ALOGV("getProperties implementor %s recognitionModes %08x",
- properties.implementor.c_str(), properties.recognitionModes);
+ ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(),
+ properties.recognitionModes);
exit:
_hidl_cb(ret, properties);
@@ -109,14 +89,9 @@
}
int SoundTriggerHalImpl::doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
- const sp<ISoundTriggerHwCallback>& callback,
- ISoundTriggerHwCallback::CallbackCookie cookie,
- uint32_t *modelId)
-{
+ sp<SoundModelClient> client) {
int32_t ret = 0;
- struct sound_trigger_sound_model *halSoundModel;
- *modelId = 0;
- sp<SoundModelClient> client;
+ struct sound_trigger_sound_model* halSoundModel;
ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
@@ -131,19 +106,9 @@
goto exit;
}
- {
- AutoMutex lock(mLock);
- do {
- *modelId = nextUniqueId();
- } while (mClients.valueFor(*modelId) != 0 && *modelId != 0);
- }
- LOG_ALWAYS_FATAL_IF(*modelId == 0,
- "wrap around in sound model IDs, num loaded models %zu", mClients.size());
-
- client = new SoundModelClient(*modelId, callback, cookie);
-
- ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback,
- client.get(), &client->mHalHandle);
+ sound_model_handle_t halHandle;
+ ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback, client.get(),
+ &halHandle);
free(halSoundModel);
@@ -151,9 +116,10 @@
goto exit;
}
+ client->setHalHandle(halHandle);
{
AutoMutex lock(mLock);
- mClients.add(*modelId, client);
+ mClients.add(client->getId(), client);
}
exit:
@@ -163,31 +129,23 @@
Return<void> SoundTriggerHalImpl::loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
const sp<ISoundTriggerHwCallback>& callback,
ISoundTriggerHwCallback::CallbackCookie cookie,
- loadSoundModel_cb _hidl_cb)
-{
- uint32_t modelId = 0;
- int32_t ret = doLoadSoundModel(soundModel, callback, cookie, &modelId);
-
- _hidl_cb(ret, modelId);
+ ISoundTriggerHw::loadSoundModel_cb _hidl_cb) {
+ sp<SoundModelClient> client = new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel(soundModel, client), client->getId());
return Void();
}
Return<void> SoundTriggerHalImpl::loadPhraseSoundModel(
- const ISoundTriggerHw::PhraseSoundModel& soundModel,
- const sp<ISoundTriggerHwCallback>& callback,
- ISoundTriggerHwCallback::CallbackCookie cookie,
- ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb)
-{
- uint32_t modelId = 0;
- int32_t ret = doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel,
- callback, cookie, &modelId);
-
- _hidl_cb(ret, modelId);
+ const ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback, ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) {
+ sp<SoundModelClient> client = new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel, client),
+ client->getId());
return Void();
}
-Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle)
-{
+Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle) {
int32_t ret;
sp<SoundModelClient> client;
@@ -205,7 +163,7 @@
}
}
- ret = mHwDevice->unload_sound_model(mHwDevice, client->mHalHandle);
+ ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle());
mClients.removeItem(modelHandle);
@@ -213,14 +171,11 @@
return ret;
}
-Return<int32_t> SoundTriggerHalImpl::startRecognition(SoundModelHandle modelHandle,
- const ISoundTriggerHw::RecognitionConfig& config,
- const sp<ISoundTriggerHwCallback>& callback __unused,
- ISoundTriggerHwCallback::CallbackCookie cookie __unused)
-{
+Return<int32_t> SoundTriggerHalImpl::startRecognition(
+ SoundModelHandle modelHandle, const ISoundTriggerHw::RecognitionConfig& config) {
int32_t ret;
sp<SoundModelClient> client;
- struct sound_trigger_recognition_config *halConfig;
+ struct sound_trigger_recognition_config* halConfig;
if (mHwDevice == NULL) {
ret = -ENODEV;
@@ -236,15 +191,14 @@
}
}
-
halConfig = convertRecognitionConfigToHal(&config);
if (halConfig == NULL) {
ret = -EINVAL;
goto exit;
}
- ret = mHwDevice->start_recognition(mHwDevice, client->mHalHandle, halConfig,
- recognitionCallback, client.get());
+ ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,
+ recognitionCallback, client.get());
free(halConfig);
@@ -252,8 +206,7 @@
return ret;
}
-Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle)
-{
+Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle) {
int32_t ret;
sp<SoundModelClient> client;
if (mHwDevice == NULL) {
@@ -270,14 +223,13 @@
}
}
- ret = mHwDevice->stop_recognition(mHwDevice, client->mHalHandle);
+ ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle());
exit:
return ret;
}
-Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions()
-{
+Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions() {
int32_t ret;
if (mHwDevice == NULL) {
ret = -ENODEV;
@@ -285,7 +237,7 @@
}
if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
- mHwDevice->stop_all_recognitions) {
+ mHwDevice->stop_all_recognitions) {
ret = mHwDevice->stop_all_recognitions(mHwDevice);
} else {
ret = -ENOSYS;
@@ -295,19 +247,16 @@
}
SoundTriggerHalImpl::SoundTriggerHalImpl()
- : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1)
-{
-}
+ : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {}
-void SoundTriggerHalImpl::onFirstRef()
-{
- const hw_module_t *mod;
+void SoundTriggerHalImpl::onFirstRef() {
+ const hw_module_t* mod;
int rc;
rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
if (rc != 0) {
- ALOGE("couldn't load sound trigger module %s.%s (%s)",
- SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+ ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID,
+ mModuleName, strerror(-rc));
return;
}
rc = sound_trigger_hw_device_open(mod, &mHwDevice);
@@ -318,7 +267,7 @@
return;
}
if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
- mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+ mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
sound_trigger_hw_device_close(mHwDevice);
mHwDevice = NULL;
@@ -328,22 +277,27 @@
ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
}
-SoundTriggerHalImpl::~SoundTriggerHalImpl()
-{
+SoundTriggerHalImpl::~SoundTriggerHalImpl() {
if (mHwDevice != NULL) {
sound_trigger_hw_device_close(mHwDevice);
}
}
-uint32_t SoundTriggerHalImpl::nextUniqueId()
-{
- return (uint32_t) atomic_fetch_add_explicit(&mNextModelId,
- (uint_fast32_t) 1, memory_order_acq_rel);
+uint32_t SoundTriggerHalImpl::nextUniqueModelId() {
+ uint32_t modelId = 0;
+ {
+ AutoMutex lock(mLock);
+ do {
+ modelId =
+ atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1, memory_order_acq_rel);
+ } while (mClients.valueFor(modelId) != 0 && modelId != 0);
+ }
+ LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu",
+ mClients.size());
+ return modelId;
}
-void SoundTriggerHalImpl::convertUuidFromHal(Uuid *uuid,
- const sound_trigger_uuid_t *halUuid)
-{
+void SoundTriggerHalImpl::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) {
uuid->timeLow = halUuid->timeLow;
uuid->timeMid = halUuid->timeMid;
uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
@@ -351,9 +305,7 @@
memcpy(&uuid->node[0], &halUuid->node[0], 6);
}
-void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t *halUuid,
- const Uuid *uuid)
-{
+void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) {
halUuid->timeLow = uuid->timeLow;
halUuid->timeMid = uuid->timeMid;
halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
@@ -362,9 +314,7 @@
}
void SoundTriggerHalImpl::convertPropertiesFromHal(
- ISoundTriggerHw::Properties *properties,
- const struct sound_trigger_properties *halProperties)
-{
+ ISoundTriggerHw::Properties* properties, const struct sound_trigger_properties* halProperties) {
properties->implementor = halProperties->implementor;
properties->description = halProperties->description;
properties->version = halProperties->version;
@@ -378,13 +328,10 @@
properties->concurrentCapture = halProperties->concurrent_capture;
properties->triggerInEvent = halProperties->trigger_in_event;
properties->powerConsumptionMw = halProperties->power_consumption_mw;
-
}
-void SoundTriggerHalImpl::convertTriggerPhraseToHal(
- struct sound_trigger_phrase *halTriggerPhrase,
- const ISoundTriggerHw::Phrase *triggerPhrase)
-{
+void SoundTriggerHalImpl::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+ const ISoundTriggerHw::Phrase* triggerPhrase) {
halTriggerPhrase->id = triggerPhrase->id;
halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
unsigned int i;
@@ -395,39 +342,35 @@
halTriggerPhrase->users[i] = triggerPhrase->users[i];
}
- strlcpy(halTriggerPhrase->locale,
- triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
- strlcpy(halTriggerPhrase->text,
- triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+ strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
+ strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
}
-struct sound_trigger_sound_model *SoundTriggerHalImpl::convertSoundModelToHal(
- const ISoundTriggerHw::SoundModel *soundModel)
-{
- struct sound_trigger_sound_model *halModel = NULL;
+struct sound_trigger_sound_model* SoundTriggerHalImpl::convertSoundModelToHal(
+ const ISoundTriggerHw::SoundModel* soundModel) {
+ struct sound_trigger_sound_model* halModel = NULL;
if (soundModel->type == SoundModelType::KEYPHRASE) {
size_t allocSize =
- sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
- struct sound_trigger_phrase_sound_model *halKeyPhraseModel =
- static_cast<struct sound_trigger_phrase_sound_model *>(malloc(allocSize));
+ sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
+ struct sound_trigger_phrase_sound_model* halKeyPhraseModel =
+ static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize));
LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
- "malloc failed for size %zu in convertSoundModelToHal PHRASE", allocSize);
+ "malloc failed for size %zu in convertSoundModelToHal PHRASE",
+ allocSize);
- const ISoundTriggerHw::PhraseSoundModel *keyPhraseModel =
- reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel *>(soundModel);
+ const ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
+ reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel*>(soundModel);
size_t i;
for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
- convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i],
- &keyPhraseModel->phrases[i]);
+ convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]);
}
halKeyPhraseModel->num_phrases = (unsigned int)i;
- halModel = reinterpret_cast<struct sound_trigger_sound_model *>(halKeyPhraseModel);
+ halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel);
halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
} else {
- size_t allocSize =
- sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
- halModel = static_cast<struct sound_trigger_sound_model *>(malloc(allocSize));
+ size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
+ halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize));
LOG_ALWAYS_FATAL_IF(halModel == NULL,
"malloc failed for size %zu in convertSoundModelToHal GENERIC",
allocSize);
@@ -438,17 +381,15 @@
convertUuidToHal(&halModel->uuid, &soundModel->uuid);
convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
halModel->data_size = soundModel->data.size();
- uint8_t *dst = reinterpret_cast<uint8_t *>(halModel) + halModel->data_offset;
- const uint8_t *src = reinterpret_cast<const uint8_t *>(&soundModel->data[0]);
+ uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset;
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]);
memcpy(dst, src, soundModel->data.size());
return halModel;
}
void SoundTriggerHalImpl::convertPhraseRecognitionExtraToHal(
- struct sound_trigger_phrase_recognition_extra *halExtra,
- const PhraseRecognitionExtra *extra)
-{
+ struct sound_trigger_phrase_recognition_extra* halExtra, const PhraseRecognitionExtra* extra) {
halExtra->id = extra->id;
halExtra->recognition_modes = extra->recognitionModes;
halExtra->confidence_level = extra->confidenceLevel;
@@ -461,16 +402,14 @@
halExtra->num_levels = i;
}
-struct sound_trigger_recognition_config *SoundTriggerHalImpl::convertRecognitionConfigToHal(
- const ISoundTriggerHw::RecognitionConfig *config)
-{
+struct sound_trigger_recognition_config* SoundTriggerHalImpl::convertRecognitionConfigToHal(
+ const ISoundTriggerHw::RecognitionConfig* config) {
size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
- struct sound_trigger_recognition_config *halConfig =
- static_cast<struct sound_trigger_recognition_config *>(malloc(allocSize));
+ struct sound_trigger_recognition_config* halConfig =
+ static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize));
LOG_ALWAYS_FATAL_IF(halConfig == NULL,
- "malloc failed for size %zu in convertRecognitionConfigToHal",
- allocSize);
+ "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize);
halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
halConfig->capture_device = (audio_devices_t)config->captureDevice;
@@ -478,57 +417,43 @@
unsigned int i;
for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
- convertPhraseRecognitionExtraToHal(&halConfig->phrases[i],
- &config->phrases[i]);
+ convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]);
}
halConfig->num_phrases = i;
halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
halConfig->data_size = config->data.size();
- uint8_t *dst = reinterpret_cast<uint8_t *>(halConfig) + halConfig->data_offset;
- const uint8_t *src = reinterpret_cast<const uint8_t *>(&config->data[0]);
+ uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset;
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]);
memcpy(dst, src, config->data.size());
return halConfig;
}
// static
-void SoundTriggerHalImpl::convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
- const struct sound_trigger_model_event *halEvent)
-{
+void SoundTriggerHalImpl::convertSoundModelEventFromHal(
+ ISoundTriggerHwCallback::ModelEvent* event, const struct sound_trigger_model_event* halEvent) {
event->status = (ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
// event->model to be remapped by called
event->data.setToExternal(
- const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
- halEvent->data_size);
+ const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+ halEvent->data_size);
}
// static
-ISoundTriggerHwCallback::RecognitionEvent *SoundTriggerHalImpl::convertRecognitionEventFromHal(
- const struct sound_trigger_recognition_event *halEvent)
-{
- ISoundTriggerHwCallback::RecognitionEvent * event;
-
- if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
- const struct sound_trigger_phrase_recognition_event *halPhraseEvent =
- reinterpret_cast<const struct sound_trigger_phrase_recognition_event *>(halEvent);
- ISoundTriggerHwCallback::PhraseRecognitionEvent *phraseEvent =
- new ISoundTriggerHwCallback::PhraseRecognitionEvent();
-
- PhraseRecognitionExtra *phraseExtras =
- new PhraseRecognitionExtra[halPhraseEvent->num_phrases];
- for (unsigned int i = 0; i < halPhraseEvent->num_phrases; i++) {
- convertPhraseRecognitionExtraFromHal(&phraseExtras[i],
- &halPhraseEvent->phrase_extras[i]);
- }
- phraseEvent->phraseExtras.setToExternal(phraseExtras, halPhraseEvent->num_phrases);
- // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
- phraseEvent->phraseExtras.resize(halPhraseEvent->num_phrases);
- delete[] phraseExtras;
- event = reinterpret_cast<ISoundTriggerHwCallback::RecognitionEvent *>(phraseEvent);
- } else {
- event = new ISoundTriggerHwCallback::RecognitionEvent();
+void SoundTriggerHalImpl::convertPhaseRecognitionEventFromHal(
+ ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+ const struct sound_trigger_phrase_recognition_event* halEvent) {
+ event->phraseExtras.resize(halEvent->num_phrases);
+ for (unsigned int i = 0; i < halEvent->num_phrases; i++) {
+ convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]);
}
+ convertRecognitionEventFromHal(&event->common, &halEvent->common);
+}
+// static
+void SoundTriggerHalImpl::convertRecognitionEventFromHal(
+ ISoundTriggerHwCallback::RecognitionEvent* event,
+ const struct sound_trigger_recognition_event* halEvent) {
event->status = static_cast<ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
event->type = static_cast<SoundModelType>(halEvent->type);
// event->model to be remapped by called
@@ -539,45 +464,53 @@
event->triggerInData = halEvent->trigger_in_data;
event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
event->audioConfig.channelMask =
- (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
+ (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
event->data.setToExternal(
- const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
- halEvent->data_size);
-
- return event;
+ const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+ halEvent->data_size);
}
// static
void SoundTriggerHalImpl::convertPhraseRecognitionExtraFromHal(
- PhraseRecognitionExtra *extra,
- const struct sound_trigger_phrase_recognition_extra *halExtra)
-{
+ PhraseRecognitionExtra* extra, const struct sound_trigger_phrase_recognition_extra* halExtra) {
extra->id = halExtra->id;
extra->recognitionModes = halExtra->recognition_modes;
extra->confidenceLevel = halExtra->confidence_level;
- ConfidenceLevel *levels =
- new ConfidenceLevel[halExtra->num_levels];
- for (unsigned int i = 0; i < halExtra->num_levels; i++) {
- levels[i].userId = halExtra->levels[i].user_id;
- levels[i].levelPercent = halExtra->levels[i].level;
- }
- extra->levels.setToExternal(levels, halExtra->num_levels);
- // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
extra->levels.resize(halExtra->num_levels);
- delete[] levels;
+ for (unsigned int i = 0; i < halExtra->num_levels; i++) {
+ extra->levels[i].userId = halExtra->levels[i].user_id;
+ extra->levels[i].levelPercent = halExtra->levels[i].level;
+ }
}
-ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char* /* name */)
-{
- return new SoundTriggerHalImpl();
+void SoundTriggerHalImpl::SoundModelClient_2_0::recognitionCallback(
+ struct sound_trigger_recognition_event* halEvent) {
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+ convertPhaseRecognitionEventFromHal(
+ &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+ event.common.model = mId;
+ mCallback->phraseRecognitionCallback(event, mCookie);
+ } else {
+ ISoundTriggerHwCallback::RecognitionEvent event;
+ convertRecognitionEventFromHal(&event, halEvent);
+ event.model = mId;
+ mCallback->recognitionCallback(event, mCookie);
+ }
}
-} // namespace implementation
+
+void SoundTriggerHalImpl::SoundModelClient_2_0::soundModelCallback(
+ struct sound_trigger_model_event* halEvent) {
+ ISoundTriggerHwCallback::ModelEvent event;
+ convertSoundModelEventFromHal(&event, halEvent);
+ event.model = mId;
+ mCallback->soundModelCallback(event, mCookie);
+}
+
+} // namespace implementation
} // namespace V2_0
} // namespace soundtrigger
} // namespace hardware
} // namespace android
-
-
-
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
index 4769590..5a9f0e1 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -19,12 +19,12 @@
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <hardware/sound_trigger.h>
#include <hidl/Status.h>
#include <stdatomic.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
#include <system/sound_trigger.h>
-#include <hardware/sound_trigger.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
namespace android {
namespace hardware {
@@ -35,96 +35,144 @@
using ::android::hardware::audio::common::V2_0::Uuid;
using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+class SoundTriggerHalImpl : public RefBase {
+ public:
+ SoundTriggerHalImpl();
+ ISoundTriggerHw* getInterface() { return new TrampolineSoundTriggerHw_2_0(this); }
-class SoundTriggerHalImpl : public ISoundTriggerHw {
-public:
- SoundTriggerHalImpl();
+ protected:
+ class SoundModelClient : public RefBase {
+ public:
+ SoundModelClient(uint32_t id, ISoundTriggerHwCallback::CallbackCookie cookie)
+ : mId(id), mCookie(cookie) {}
+ virtual ~SoundModelClient() {}
+
+ uint32_t getId() const { return mId; }
+ sound_model_handle_t getHalHandle() const { return mHalHandle; }
+ void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; }
+
+ virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0;
+ virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0;
+
+ protected:
+ const uint32_t mId;
+ sound_model_handle_t mHalHandle;
+ ISoundTriggerHwCallback::CallbackCookie mCookie;
+ };
+
+ static void convertPhaseRecognitionEventFromHal(
+ ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+ const struct sound_trigger_phrase_recognition_event* halEvent);
+ static void convertRecognitionEventFromHal(
+ ISoundTriggerHwCallback::RecognitionEvent* event,
+ const struct sound_trigger_recognition_event* halEvent);
+ static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent* event,
+ const struct sound_trigger_model_event* halEvent);
+
+ virtual ~SoundTriggerHalImpl();
+
+ Return<void> getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb);
+ Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadSoundModel_cb _hidl_cb);
+ Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb);
+ Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle);
+ Return<int32_t> startRecognition(SoundModelHandle modelHandle,
+ const ISoundTriggerHw::RecognitionConfig& config);
+ Return<int32_t> stopRecognition(SoundModelHandle modelHandle);
+ Return<int32_t> stopAllRecognitions();
+
+ uint32_t nextUniqueModelId();
+ int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+ sp<SoundModelClient> client);
+
+ // RefBase
+ void onFirstRef() override;
+
+ private:
+ struct TrampolineSoundTriggerHw_2_0 : public ISoundTriggerHw {
+ explicit TrampolineSoundTriggerHw_2_0(sp<SoundTriggerHalImpl> impl) : mImpl(impl) {}
// Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
- Return<void> getProperties(getProperties_cb _hidl_cb) override;
+ Return<void> getProperties(getProperties_cb _hidl_cb) override {
+ return mImpl->getProperties(_hidl_cb);
+ }
Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
const sp<ISoundTriggerHwCallback>& callback,
ISoundTriggerHwCallback::CallbackCookie cookie,
- loadSoundModel_cb _hidl_cb) override;
+ loadSoundModel_cb _hidl_cb) override {
+ return mImpl->loadSoundModel(soundModel, callback, cookie, _hidl_cb);
+ }
Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel,
- const sp<ISoundTriggerHwCallback>& callback,
- ISoundTriggerHwCallback::CallbackCookie cookie,
- loadPhraseSoundModel_cb _hidl_cb) override;
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ loadPhraseSoundModel_cb _hidl_cb) override {
+ return mImpl->loadPhraseSoundModel(soundModel, callback, cookie, _hidl_cb);
+ }
+ Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle) override {
+ return mImpl->unloadSoundModel(modelHandle);
+ }
+ Return<int32_t> startRecognition(
+ SoundModelHandle modelHandle, const ISoundTriggerHw::RecognitionConfig& config,
+ const sp<ISoundTriggerHwCallback>& /*callback*/,
+ ISoundTriggerHwCallback::CallbackCookie /*cookie*/) override {
+ return mImpl->startRecognition(modelHandle, config);
+ }
+ Return<int32_t> stopRecognition(SoundModelHandle modelHandle) override {
+ return mImpl->stopRecognition(modelHandle);
+ }
+ Return<int32_t> stopAllRecognitions() override { return mImpl->stopAllRecognitions(); }
- Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle) override;
- Return<int32_t> startRecognition(SoundModelHandle modelHandle,
- const ISoundTriggerHw::RecognitionConfig& config,
- const sp<ISoundTriggerHwCallback>& callback,
- ISoundTriggerHwCallback::CallbackCookie cookie) override;
- Return<int32_t> stopRecognition(SoundModelHandle modelHandle) override;
- Return<int32_t> stopAllRecognitions() override;
+ private:
+ sp<SoundTriggerHalImpl> mImpl;
+ };
- // RefBase
- virtual void onFirstRef();
+ class SoundModelClient_2_0 : public SoundModelClient {
+ public:
+ SoundModelClient_2_0(uint32_t id, ISoundTriggerHwCallback::CallbackCookie cookie,
+ sp<ISoundTriggerHwCallback> callback)
+ : SoundModelClient(id, cookie), mCallback(callback) {}
- static void soundModelCallback(struct sound_trigger_model_event *halEvent,
- void *cookie);
- static void recognitionCallback(struct sound_trigger_recognition_event *halEvent,
- void *cookie);
+ void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+ void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
-private:
+ private:
+ sp<ISoundTriggerHwCallback> mCallback;
+ };
- class SoundModelClient : public RefBase {
- public:
- SoundModelClient(uint32_t id, sp<ISoundTriggerHwCallback> callback,
- ISoundTriggerHwCallback::CallbackCookie cookie)
- : mId(id), mCallback(callback), mCookie(cookie) {}
- virtual ~SoundModelClient() {}
+ void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid);
+ void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid);
+ void convertPropertiesFromHal(ISoundTriggerHw::Properties* properties,
+ const struct sound_trigger_properties* halProperties);
+ void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+ const ISoundTriggerHw::Phrase* triggerPhrase);
+ // returned HAL sound model must be freed by caller
+ struct sound_trigger_sound_model* convertSoundModelToHal(
+ const ISoundTriggerHw::SoundModel* soundModel);
+ void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra,
+ const PhraseRecognitionExtra* extra);
+ // returned recognition config must be freed by caller
+ struct sound_trigger_recognition_config* convertRecognitionConfigToHal(
+ const ISoundTriggerHw::RecognitionConfig* config);
- uint32_t mId;
- sound_model_handle_t mHalHandle;
- sp<ISoundTriggerHwCallback> mCallback;
- ISoundTriggerHwCallback::CallbackCookie mCookie;
- };
+ static void convertPhraseRecognitionExtraFromHal(
+ PhraseRecognitionExtra* extra,
+ const struct sound_trigger_phrase_recognition_extra* halExtra);
- uint32_t nextUniqueId();
- void convertUuidFromHal(Uuid *uuid,
- const sound_trigger_uuid_t *halUuid);
- void convertUuidToHal(sound_trigger_uuid_t *halUuid,
- const Uuid *uuid);
- void convertPropertiesFromHal(ISoundTriggerHw::Properties *properties,
- const struct sound_trigger_properties *halProperties);
- void convertTriggerPhraseToHal(struct sound_trigger_phrase *halTriggerPhrase,
- const ISoundTriggerHw::Phrase *triggerPhrase);
- // returned HAL sound model must be freed by caller
- struct sound_trigger_sound_model *convertSoundModelToHal(
- const ISoundTriggerHw::SoundModel *soundModel);
- void convertPhraseRecognitionExtraToHal(
- struct sound_trigger_phrase_recognition_extra *halExtra,
- const PhraseRecognitionExtra *extra);
- // returned recognition config must be freed by caller
- struct sound_trigger_recognition_config *convertRecognitionConfigToHal(
- const ISoundTriggerHw::RecognitionConfig *config);
+ static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie);
+ static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie);
-
- static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
- const struct sound_trigger_model_event *halEvent);
- static ISoundTriggerHwCallback::RecognitionEvent *convertRecognitionEventFromHal(
- const struct sound_trigger_recognition_event *halEvent);
- static void convertPhraseRecognitionExtraFromHal(PhraseRecognitionExtra *extra,
- const struct sound_trigger_phrase_recognition_extra *halExtra);
-
- int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
- const sp<ISoundTriggerHwCallback>& callback,
- ISoundTriggerHwCallback::CallbackCookie cookie,
- uint32_t *modelId);
-
- virtual ~SoundTriggerHalImpl();
-
- const char * mModuleName;
- struct sound_trigger_hw_device* mHwDevice;
- volatile atomic_uint_fast32_t mNextModelId;
- DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients;
- Mutex mLock;
+ const char* mModuleName;
+ struct sound_trigger_hw_device* mHwDevice;
+ volatile atomic_uint_fast32_t mNextModelId;
+ DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients;
+ Mutex mLock;
};
-extern "C" ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name);
-
} // namespace implementation
} // namespace V2_0
} // namespace soundtrigger
@@ -132,4 +180,3 @@
} // namespace android
#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H
-
diff --git a/soundtrigger/2.1/Android.bp b/soundtrigger/2.1/Android.bp
new file mode 100644
index 0000000..ed1ec3d
--- /dev/null
+++ b/soundtrigger/2.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.soundtrigger@2.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "ISoundTriggerHw.hal",
+ "ISoundTriggerHwCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@2.0",
+ "android.hardware.soundtrigger@2.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
+
diff --git a/soundtrigger/2.1/ISoundTriggerHw.hal b/soundtrigger/2.1/ISoundTriggerHw.hal
new file mode 100644
index 0000000..2f2e73a
--- /dev/null
+++ b/soundtrigger/2.1/ISoundTriggerHw.hal
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger@2.1;
+
+import @2.0::ISoundTriggerHw;
+import @2.0::ISoundTriggerHwCallback.CallbackCookie;
+import @2.0::SoundModelHandle;
+
+import ISoundTriggerHwCallback;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords.
+ */
+interface ISoundTriggerHw extends @2.0::ISoundTriggerHw {
+
+ /**
+ * Base sound model descriptor. This struct is the header of a larger block
+ * passed to loadSoundModel_2_1() and contains the binary data of the
+ * sound model.
+ */
+ struct SoundModel {
+ /** Sound model header. Any data contained in the 'header.data' field
+ * is ignored */
+ @2.0::ISoundTriggerHw.SoundModel header;
+ /** Opaque data transparent to Android framework */
+ memory data;
+ };
+
+ /**
+ * Specialized sound model for key phrase detection.
+ * Proprietary representation of key phrases in binary data must match
+ * information indicated by phrases field.
+ */
+ struct PhraseSoundModel {
+ /** Common part of sound model descriptor */
+ SoundModel common;
+ /** List of descriptors for key phrases supported by this sound model */
+ vec<Phrase> phrases;
+ };
+
+ /**
+ * Configuration for sound trigger capture session passed to
+ * startRecognition_2_1() method.
+ */
+ struct RecognitionConfig {
+ /** Configuration header. Any data contained in the 'header.data' field
+ * is ignored */
+ @2.0::ISoundTriggerHw.RecognitionConfig header;
+ /** Opaque capture configuration data transparent to the framework */
+ memory data;
+ };
+
+ /**
+ * Load a sound model. Once loaded, recognition of this model can be
+ * started and stopped. Only one active recognition per model at a time.
+ * The SoundTrigger service must handle concurrent recognition requests by
+ * different users/applications on the same model.
+ * The implementation returns a unique handle used by other functions
+ * (unloadSoundModel(), startRecognition*(), etc...
+ *
+ * Must have the exact same semantics as loadSoundModel from
+ * ISoundTriggerHw@2.0 except that the SoundModel uses shared memory
+ * instead of data.
+ *
+ * @param soundModel A SoundModel structure describing the sound model
+ * to load.
+ * @param callback The callback interface on which the soundmodelCallback*()
+ * method must be called upon completion.
+ * @param cookie The value of the cookie argument passed to the completion
+ * callback. This unique context information is assigned and
+ * used only by the framework.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid sound model (e.g 0 data size),
+ * -ENOSYS in case of invalid operation (e.g max number of models
+ * exceeded),
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ * @return modelHandle A unique handle assigned by the HAL for use by the
+ * framework when controlling activity for this sound model.
+ */
+ @callflow(next={"startRecognition_2_1", "setSoundModelParameters", "unloadSoundModel"})
+ loadSoundModel_2_1(SoundModel soundModel,
+ ISoundTriggerHwCallback callback,
+ CallbackCookie cookie)
+ generates (int32_t retval, SoundModelHandle modelHandle);
+
+ /**
+ * Load a key phrase sound model. Once loaded, recognition of this model can
+ * be started and stopped. Only one active recognition per model at a time.
+ * The SoundTrigger service must handle concurrent recognition requests by
+ * different users/applications on the same model.
+ * The implementation returns a unique handle used by other functions
+ * (unloadSoundModel(), startRecognition*(), etc...
+ *
+ * Must have the exact same semantics as loadPhraseSoundModel from
+ * ISoundTriggerHw@2.0 except that the PhraseSoundModel uses shared memory
+ * instead of data.
+ *
+ * @param soundModel A PhraseSoundModel structure describing the sound model
+ * to load.
+ * @param callback The callback interface on which the soundmodelCallback*()
+ * method must be called upon completion.
+ * @param cookie The value of the cookie argument passed to the completion
+ * callback. This unique context information is assigned and
+ * used only by the framework.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid sound model (e.g 0 data size),
+ * -ENOSYS in case of invalid operation (e.g max number of models
+ * exceeded),
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ * @return modelHandle A unique handle assigned by the HAL for use by the
+ * framework when controlling activity for this sound model.
+ */
+ @callflow(next={"startRecognition_2_1", "setSoundModelParameters", "unloadSoundModel"})
+ loadPhraseSoundModel_2_1(PhraseSoundModel soundModel,
+ ISoundTriggerHwCallback callback,
+ CallbackCookie cookie)
+ generates (int32_t retval, SoundModelHandle modelHandle);
+
+ /**
+ * Start recognition on a given model. Only one recognition active
+ * at a time per model. Once recognition succeeds of fails, the callback
+ * is called.
+ *
+ * Must have the exact same semantics as startRecognition from
+ * ISoundTriggerHw@2.0 except that the RecognitionConfig uses shared memory
+ * instead of data.
+ *
+ * @param modelHandle the handle of the sound model to use for recognition
+ * @param config A RecognitionConfig structure containing attributes of the
+ * recognition to perform
+ * @param callback The callback interface on which the recognitionCallback()
+ * method must be called upon recognition.
+ * @param cookie The value of the cookie argument passed to the recognition
+ * callback. This unique context information is assigned and
+ * used only by the framework.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid recognition attributes,
+ * -ENOSYS in case of invalid model handle,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ */
+ @callflow(next={"stopRecognition", "stopAllRecognitions"})
+ startRecognition_2_1(SoundModelHandle modelHandle,
+ RecognitionConfig config,
+ ISoundTriggerHwCallback callback,
+ CallbackCookie cookie)
+ generates (int32_t retval);
+
+
+ struct ParameterValue {
+ string key;
+ string value;
+ };
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param keys parameter keys.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid keys,
+ * -ENOSYS in case if this operation is not supported,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ * @return parameters parameter key value pairs.
+ */
+ getParameters(vec<string> keys)
+ generates (int32_t retval, vec<ParameterValue> parameters);
+
+ /**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param parameters parameter key value pairs.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid keys,
+ * -ENOSYS in case if this operation is not supported,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ */
+ setParameters(vec<ParameterValue> parameters) generates (int32_t retval);
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param modelHandle the handle of the sound model to get parameters about.
+ * @param keys parameter keys.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid keys,
+ * -ENOSYS in case if this operation is not supported,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ * @return parameters parameter key value pairs.
+ */
+ getSoundModelParameters(SoundModelHandle modelHandle, vec<string> keys)
+ generates (int32_t retval, vec<ParameterValue> parameters);
+
+ /**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param modelHandle the handle of the sound model to set parameters for.
+ * @param parameters parameter key value pairs.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid keys,
+ * -ENOSYS in case if this operation is not supported,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ */
+ setSoundModelParameters(
+ SoundModelHandle modelHandle, vec<ParameterValue> parameters)
+ generates (int32_t retval);
+};
diff --git a/soundtrigger/2.1/ISoundTriggerHwCallback.hal b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
new file mode 100644
index 0000000..42e851b
--- /dev/null
+++ b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger@2.1;
+
+import @2.0::ISoundTriggerHwCallback;
+import @2.0::PhraseRecognitionExtra;
+
+/**
+ * SoundTrigger HAL Callback interface. Obtained during SoundTrigger setup.
+ */
+@hidl_callback
+interface ISoundTriggerHwCallback extends @2.0::ISoundTriggerHwCallback {
+
+ /**
+ * Generic recognition event sent via recognition callback.
+ */
+ struct RecognitionEvent {
+ /** Event header. Any data contained in the 'header.data' field
+ * is ignored */
+ @2.0::ISoundTriggerHwCallback.RecognitionEvent header;
+ /** Opaque event data */
+ memory data;
+ };
+
+ /**
+ * Specialized recognition event for key phrase recognitions.
+ */
+ struct PhraseRecognitionEvent {
+ /** Common part of the recognition event */
+ RecognitionEvent common;
+ /** List of descriptors for each recognized key phrase */
+ vec<PhraseRecognitionExtra> phraseExtras;
+ };
+
+ /**
+ * Event sent via load sound model callback.
+ */
+ struct ModelEvent {
+ /** Event header. Any data contained in the 'header.data' field
+ * is ignored */
+ @2.0::ISoundTriggerHwCallback.ModelEvent header;
+ /** Opaque event data, passed transparently by the framework */
+ memory data;
+ };
+
+ /**
+ * Callback method called by the HAL when the sound recognition triggers.
+ *
+ * @param event A RecognitionEvent structure containing detailed results
+ * of the recognition triggered
+ * @param cookie The cookie passed by the framework when recognition was
+ * started (see ISoundtriggerHw.startRecognition*())
+ */
+ recognitionCallback_2_1(RecognitionEvent event, CallbackCookie cookie);
+
+ /**
+ * Callback method called by the HAL when the sound recognition triggers
+ * for a key phrase sound model.
+ *
+ * @param event A RecognitionEvent structure containing detailed results
+ * of the recognition triggered
+ * @param cookie The cookie passed by the framework when recognition was
+ * started (see ISoundtriggerHw.startRecognition*())
+ */
+ phraseRecognitionCallback_2_1(PhraseRecognitionEvent event,
+ CallbackCookie cookie);
+
+ /**
+ * Callback method called by the HAL when the sound model loading completes.
+ *
+ * @param event A ModelEvent structure containing detailed results of the
+ * model loading operation
+ * @param cookie The cookie passed by the framework when loading was
+ * initiated (see ISoundtriggerHw.loadSoundModel*())
+ */
+ soundModelCallback_2_1(ModelEvent event, CallbackCookie cookie);
+};
diff --git a/soundtrigger/2.1/default/Android.mk b/soundtrigger/2.1/default/Android.mk
new file mode 100644
index 0000000..5851d63
--- /dev/null
+++ b/soundtrigger/2.1/default/Android.mk
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.soundtrigger@2.1-impl
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ SoundTriggerHw.cpp
+
+LOCAL_CFLAGS := -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+ libhardware \
+ libhidlbase \
+ libhidlmemory \
+ libhidltransport \
+ liblog \
+ libutils \
+ android.hardware.soundtrigger@2.1 \
+ android.hardware.soundtrigger@2.0 \
+ android.hardware.soundtrigger@2.0-core \
+ android.hidl.allocator@1.0 \
+ android.hidl.memory@1.0
+
+LOCAL_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/soundtrigger/2.1/default/SoundTriggerHw.cpp b/soundtrigger/2.1/default/SoundTriggerHw.cpp
new file mode 100644
index 0000000..246d2bc
--- /dev/null
+++ b/soundtrigger/2.1/default/SoundTriggerHw.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHw"
+
+#include "SoundTriggerHw.h"
+
+#include <utility>
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/log.h>
+#include <hidlmemory/mapping.h>
+
+using android::hardware::hidl_memory;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_1 {
+namespace implementation {
+
+namespace {
+
+// Backs up by the vector with the contents of shared memory.
+// It is assumed that the passed hidl_vector is empty, so it's
+// not cleared if the memory is a null object.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
+ sp<IMemory> memory;
+ if (m.size() == 0) {
+ return std::make_pair(true, memory);
+ }
+ memory = mapMemory(m);
+ if (memory != nullptr) {
+ memory->read();
+ vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
+ memory->getSize());
+ return std::make_pair(true, memory);
+ }
+ ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
+ return std::make_pair(false, memory);
+}
+
+// Moves the data from the vector into allocated shared memory,
+// emptying the vector.
+// It is assumed that the passed hidl_memory is a null object, so it's
+// not reset if the vector is empty.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
+ sp<IMemory> memory;
+ if (v->size() == 0) {
+ return std::make_pair(true, memory);
+ }
+ sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+ if (ashmem == 0) {
+ ALOGE("Failed to retrieve ashmem allocator service");
+ return std::make_pair(false, memory);
+ }
+ bool success = false;
+ Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
+ success = s;
+ if (success) *mem = m;
+ });
+ if (r.isOk() && success) {
+ memory = hardware::mapMemory(*mem);
+ if (memory != 0) {
+ memory->update();
+ memcpy(memory->getPointer(), v->data(), v->size());
+ memory->commit();
+ v->resize(0);
+ return std::make_pair(true, memory);
+ } else {
+ ALOGE("Failed to map allocated ashmem");
+ }
+ } else {
+ ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
+ }
+ return std::make_pair(false, memory);
+}
+
+} // namespace
+
+Return<void> SoundTriggerHw::loadSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) {
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header);
+ auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data);
+ if (result.first) {
+ sp<SoundModelClient> client =
+ new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId());
+ return Void();
+ }
+ _hidl_cb(-ENOMEM, 0);
+ return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) {
+ V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0;
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ soundModel_2_0.common = soundModel.common.header;
+ // Avoid copying phrases data.
+ soundModel_2_0.phrases.setToExternal(
+ const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()),
+ soundModel.phrases.size());
+ auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data);
+ if (result.first) {
+ sp<SoundModelClient> client =
+ new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client),
+ client->getId());
+ return Void();
+ }
+ _hidl_cb(-ENOMEM, 0);
+ return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_1(
+ int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config) {
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header);
+ auto result = memoryAsVector(config.data, &config_2_0.data);
+ return result.first ? startRecognition(modelHandle, config_2_0) : Return<int32_t>(-ENOMEM);
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback(
+ struct sound_trigger_recognition_event* halEvent) {
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
+ convertPhaseRecognitionEventFromHal(
+ &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+ event_2_0.common.model = mId;
+ V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+ event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(),
+ event_2_0.phraseExtras.size());
+ auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data);
+ if (result.first) {
+ // The data vector is now empty, thus copying is cheap.
+ event.common.header = event_2_0.common;
+ mCallback->phraseRecognitionCallback_2_1(event, mCookie);
+ }
+ } else {
+ V2_1::ISoundTriggerHwCallback::RecognitionEvent event;
+ convertRecognitionEventFromHal(&event.header, halEvent);
+ event.header.model = mId;
+ auto result = moveVectorToMemory(&event.header.data, &event.data);
+ if (result.first) {
+ mCallback->recognitionCallback_2_1(event, mCookie);
+ }
+ }
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback(
+ struct sound_trigger_model_event* halEvent) {
+ V2_1::ISoundTriggerHwCallback::ModelEvent event;
+ convertSoundModelEventFromHal(&event.header, halEvent);
+ event.header.model = mId;
+ auto result = moveVectorToMemory(&event.header.data, &event.data);
+ if (result.first) {
+ mCallback->soundModelCallback_2_1(event, mCookie);
+ }
+}
+
+ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
+ return (new SoundTriggerHw())->getInterface();
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
diff --git a/soundtrigger/2.1/default/SoundTriggerHw.h b/soundtrigger/2.1/default/SoundTriggerHw.h
new file mode 100644
index 0000000..855d1a6
--- /dev/null
+++ b/soundtrigger/2.1/default/SoundTriggerHw.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
+
+#include <SoundTriggerHalImpl.h>
+#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct SoundTriggerHw : public V2_0::implementation::SoundTriggerHalImpl {
+ SoundTriggerHw() = default;
+ ISoundTriggerHw* getInterface() { return new TrampolineSoundTriggerHw_2_1(this); }
+
+ protected:
+ virtual ~SoundTriggerHw() = default;
+
+ Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie,
+ V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb);
+ Return<void> loadPhraseSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb);
+ Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+ const V2_1::ISoundTriggerHw::RecognitionConfig& config);
+
+ private:
+ struct TrampolineSoundTriggerHw_2_1 : public ISoundTriggerHw {
+ explicit TrampolineSoundTriggerHw_2_1(sp<SoundTriggerHw> impl) : mImpl(impl) {}
+
+ // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
+ Return<void> getProperties(getProperties_cb _hidl_cb) override {
+ return mImpl->getProperties(_hidl_cb);
+ }
+ Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ int32_t cookie, loadSoundModel_cb _hidl_cb) override {
+ return mImpl->loadSoundModel(soundModel, callback, cookie, _hidl_cb);
+ }
+ Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ int32_t cookie,
+ loadPhraseSoundModel_cb _hidl_cb) override {
+ return mImpl->loadPhraseSoundModel(soundModel, callback, cookie, _hidl_cb);
+ }
+ Return<int32_t> unloadSoundModel(V2_0::SoundModelHandle modelHandle) override {
+ return mImpl->unloadSoundModel(modelHandle);
+ }
+ Return<int32_t> startRecognition(int32_t modelHandle,
+ const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_0::ISoundTriggerHwCallback>& /*callback*/,
+ int32_t /*cookie*/) override {
+ return mImpl->startRecognition(modelHandle, config);
+ }
+ Return<int32_t> stopRecognition(V2_0::SoundModelHandle modelHandle) override {
+ return mImpl->stopRecognition(modelHandle);
+ }
+ Return<int32_t> stopAllRecognitions() override { return mImpl->stopAllRecognitions(); }
+
+ // Methods from V2_1::ISoundTriggerHw follow.
+ Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override {
+ return mImpl->loadSoundModel_2_1(soundModel, callback, cookie, _hidl_cb);
+ }
+ Return<void> loadPhraseSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ loadPhraseSoundModel_2_1_cb _hidl_cb) override {
+ return mImpl->loadPhraseSoundModel_2_1(soundModel, callback, cookie, _hidl_cb);
+ }
+ Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+ const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_1::ISoundTriggerHwCallback>& /*callback*/,
+ int32_t /*cookie*/) override {
+ return mImpl->startRecognition_2_1(modelHandle, config);
+ }
+ Return<void> getParameters(const hidl_vec<hidl_string>& /*keys*/,
+ getParameters_cb _hidl_cb) override {
+ _hidl_cb(-ENOSYS, hidl_vec<ParameterValue>());
+ return Void();
+ }
+ Return<int32_t> setParameters(
+ const hidl_vec<V2_1::ISoundTriggerHw::ParameterValue>& /*parameters*/) override {
+ return -ENOSYS;
+ }
+ Return<void> getSoundModelParameters(int32_t /*modelHandle*/,
+ const hidl_vec<hidl_string>& /*keys*/,
+ getSoundModelParameters_cb _hidl_cb) override {
+ _hidl_cb(-ENOSYS, hidl_vec<ParameterValue>());
+ return Void();
+ }
+ Return<int32_t> setSoundModelParameters(
+ int32_t /*modelHandle*/,
+ const hidl_vec<V2_1::ISoundTriggerHw::ParameterValue>& /*parameters*/) override {
+ return -ENOSYS;
+ }
+
+ private:
+ sp<SoundTriggerHw> mImpl;
+ };
+
+ class SoundModelClient_2_1 : public SoundModelClient {
+ public:
+ SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie,
+ sp<V2_1::ISoundTriggerHwCallback> callback)
+ : SoundModelClient(id, cookie), mCallback(callback) {}
+
+ void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+ void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+ private:
+ sp<V2_1::ISoundTriggerHwCallback> mCallback;
+ };
+};
+
+extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name);
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
diff --git a/soundtrigger/2.1/vts/functional/Android.bp b/soundtrigger/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..925a17c
--- /dev/null
+++ b/soundtrigger/2.1/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalSoundtriggerV2_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalSoundtriggerV2_1TargetTest.cpp"],
+ static_libs: [
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.1",
+ "libhidlmemory"
+ ],
+}
diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
new file mode 100644
index 0000000..9876cdd
--- /dev/null
+++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHidlHalTest"
+#include <stdlib.h>
+#include <time.h>
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+#include <log/log.h>
+
+#include <android/hardware/audio/common/2.0/types.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/types.h>
+#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <hidlmemory/mapping.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#define SHORT_TIMEOUT_PERIOD (1)
+
+using ::android::sp;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
+using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
+using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
+using ::android::hardware::soundtrigger::V2_0::SoundModelType;
+using V2_0_ISoundTriggerHw = ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using V2_0_ISoundTriggerHwCallback =
+ ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw;
+using ParameterValue = ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw::ParameterValue;
+using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+/**
+ * Test code uses this class to wait for notification from callback.
+ */
+class Monitor {
+ public:
+ Monitor() : mCount(0) {}
+
+ /**
+ * Adds 1 to the internal counter and unblocks one of the waiting threads.
+ */
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMtx);
+ mCount++;
+ mCv.notify_one();
+ }
+
+ /**
+ * Blocks until the internal counter becomes greater than 0.
+ *
+ * If notified, this method decreases the counter by 1 and returns true.
+ * If timeout, returns false.
+ */
+ bool wait(int timeoutSeconds) {
+ auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSeconds);
+ std::unique_lock<std::mutex> lock(mMtx);
+ if (!mCv.wait_until(lock, deadline, [& count = mCount] { return count > 0; })) {
+ return false;
+ }
+ mCount--;
+ return true;
+ }
+
+ private:
+ std::mutex mMtx;
+ std::condition_variable mCv;
+ int mCount;
+};
+
+// The main test class for Sound Trigger HIDL HAL.
+class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>();
+ ASSERT_NE(nullptr, mSoundTriggerHal.get());
+ mCallback = new SoundTriggerHwCallback(*this);
+ ASSERT_NE(nullptr, mCallback.get());
+ }
+
+ static void SetUpTestCase() { srand(1234); }
+
+ class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
+ private:
+ SoundTriggerHidlTest& mParent;
+
+ public:
+ SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
+
+ Return<void> recognitionCallback(const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event
+ __unused,
+ int32_t cookie __unused) override {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ };
+
+ Return<void> phraseRecognitionCallback(
+ const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+ int32_t cookie __unused) override {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ };
+
+ Return<void> soundModelCallback(const V2_0_ISoundTriggerHwCallback::ModelEvent& event,
+ int32_t cookie __unused) override {
+ ALOGI("%s", __FUNCTION__);
+ mParent.lastModelEvent_2_0 = event;
+ mParent.monitor.notify();
+ return Void();
+ }
+
+ Return<void> recognitionCallback_2_1(const ISoundTriggerHwCallback::RecognitionEvent& event
+ __unused,
+ int32_t cookie __unused) override {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ Return<void> phraseRecognitionCallback_2_1(
+ const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+ int32_t cookie __unused) override {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ Return<void> soundModelCallback_2_1(const ISoundTriggerHwCallback::ModelEvent& event,
+ int32_t cookie __unused) {
+ ALOGI("%s", __FUNCTION__);
+ mParent.lastModelEvent = event;
+ mParent.monitor.notify();
+ return Void();
+ }
+ };
+
+ virtual void TearDown() override {}
+
+ Monitor monitor;
+ // updated by soundModelCallback()
+ V2_0_ISoundTriggerHwCallback::ModelEvent lastModelEvent_2_0;
+ // updated by soundModelCallback_2_1()
+ ISoundTriggerHwCallback::ModelEvent lastModelEvent;
+
+ protected:
+ sp<ISoundTriggerHw> mSoundTriggerHal;
+ sp<SoundTriggerHwCallback> mCallback;
+};
+
+/**
+ * Test ISoundTriggerHw::getProperties() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the method returns 0 (no error)
+ * - the implementation supports at least one sound model and one key phrase
+ * - the implementation supports at least VOICE_TRIGGER recognition mode
+ */
+TEST_F(SoundTriggerHidlTest, GetProperties) {
+ ISoundTriggerHw::Properties halProperties;
+ Return<void> hidlReturn;
+ int ret = -ENODEV;
+
+ hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) {
+ ret = rc;
+ halProperties = res;
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(0, ret);
+ EXPECT_GT(halProperties.maxSoundModels, 0u);
+ EXPECT_GT(halProperties.maxKeyPhrases, 0u);
+ EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
+}
+
+/**
+ * Test ISoundTriggerHw::loadPhraseSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when passed a malformed sound model
+ *
+ * There is no way to verify that implementation actually can load a sound model because each
+ * sound model is vendor specific.
+ */
+TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+ Return<void> hidlReturn;
+ int ret = -ENODEV;
+ V2_0_ISoundTriggerHw::PhraseSoundModel model;
+ SoundModelHandle handle;
+
+ model.common.type = SoundModelType::UNKNOWN;
+
+ hidlReturn =
+ mSoundTriggerHal->loadPhraseSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadPhraseSoundModel_2_1() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when passed a malformed sound model
+ *
+ * There is no way to verify that implementation actually can load a sound model because each
+ * sound model is vendor specific.
+ */
+TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
+ Return<void> hidlReturn;
+ int ret = -ENODEV;
+ ISoundTriggerHw::PhraseSoundModel model;
+ SoundModelHandle handle;
+
+ model.common.header.type = SoundModelType::UNKNOWN;
+
+ hidlReturn = mSoundTriggerHal->loadPhraseSoundModel_2_1(model, mCallback, 0,
+ [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation returns an error when passed an empty sound model
+ */
+TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
+ int ret = -ENODEV;
+ V2_0_ISoundTriggerHw::SoundModel model;
+ SoundModelHandle handle = 0;
+
+ model.type = SoundModelType::GENERIC;
+
+ Return<void> loadReturn =
+ mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(loadReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+ int ret = -ENODEV;
+ V2_0_ISoundTriggerHw::SoundModel model;
+ SoundModelHandle handle = 0;
+
+ model.type = SoundModelType::GENERIC;
+ model.data.resize(100);
+ for (auto& d : model.data) {
+ d = rand();
+ }
+
+ Return<void> loadReturn =
+ mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(loadReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel_2_1() method
+ *
+ * Verifies that:
+ * - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
+ int ret = -ENODEV;
+ ISoundTriggerHw::SoundModel model;
+ SoundModelHandle handle = 0;
+
+ model.header.type = SoundModelType::GENERIC;
+
+ Return<void> loadReturn =
+ mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(loadReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel_2_1() method
+ *
+ * Verifies that:
+ * - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
+ int ret = -ENODEV;
+ ISoundTriggerHw::SoundModel model;
+ SoundModelHandle handle = 0;
+
+ model.header.type = SoundModelType::GENERIC;
+ sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+ ASSERT_NE(nullptr, ashmem.get());
+ hidl_memory hmemory;
+ int size = 100;
+ Return<void> allocReturn = ashmem->allocate(size, [&](bool success, const hidl_memory& m) {
+ ASSERT_TRUE(success);
+ hmemory = m;
+ });
+ sp<IMemory> memory = ::android::hardware::mapMemory(hmemory);
+ ASSERT_NE(nullptr, memory.get());
+ memory->update();
+ for (uint8_t *p = static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())); size >= 0;
+ p++, size--) {
+ *p = rand();
+ }
+
+ Return<void> loadReturn =
+ mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(loadReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::unloadSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when called without a valid loaded sound model
+ *
+ */
+TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+ Return<int32_t> hidlReturn(0);
+ SoundModelHandle halHandle = 0;
+
+ hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle);
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::startRecognition() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when called without a valid loaded sound model
+ *
+ * There is no way to verify that implementation actually starts recognition because no model can
+ * be loaded.
+ */
+TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+ Return<int32_t> hidlReturn(0);
+ SoundModelHandle handle = 0;
+ PhraseRecognitionExtra phrase;
+ V2_0_ISoundTriggerHw::RecognitionConfig config;
+
+ config.captureHandle = 0;
+ config.captureDevice = AudioDevice::IN_BUILTIN_MIC;
+ phrase.id = 0;
+ phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
+ phrase.confidenceLevel = 0;
+
+ config.phrases.setToExternal(&phrase, 1);
+
+ hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0);
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::startRecognition_2_1() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when called without a valid loaded sound model
+ *
+ * There is no way to verify that implementation actually starts recognition because no model can
+ * be loaded.
+ */
+TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
+ Return<int32_t> hidlReturn(0);
+ SoundModelHandle handle = 0;
+ PhraseRecognitionExtra phrase;
+ ISoundTriggerHw::RecognitionConfig config;
+
+ config.header.captureHandle = 0;
+ config.header.captureDevice = AudioDevice::IN_BUILTIN_MIC;
+ phrase.id = 0;
+ phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
+ phrase.confidenceLevel = 0;
+
+ config.header.phrases.setToExternal(&phrase, 1);
+
+ hidlReturn = mSoundTriggerHal->startRecognition_2_1(handle, config, mCallback, 0);
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopRecognition() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when called without an active recognition running
+ *
+ */
+TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+ Return<int32_t> hidlReturn(0);
+ SoundModelHandle handle = 0;
+
+ hidlReturn = mSoundTriggerHal->stopRecognition(handle);
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopAllRecognitions() method
+ *
+ * Verifies that:
+ * - the implementation implements this optional method or indicates it is not supported by
+ * returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+ Return<int32_t> hidlReturn(0);
+
+ hidlReturn = mSoundTriggerHal->stopAllRecognitions();
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
+}
+
+/**
+ * Test ISoundTriggerHw::getParameters() and setParameters() methods
+ *
+ * Verifies that:
+ * - the implementation implements these optional methods or indicates it is not supported by
+ * returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, getAndSetParameters) {
+ hidl_vec<hidl_string> keys;
+ hidl_vec<ParameterValue> values;
+
+ int32_t ret = -ENODEV;
+ Return<void> hidlReturn =
+ mSoundTriggerHal->getParameters(keys, [&](int32_t retval, auto params) {
+ ret = retval;
+ values = params;
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_TRUE(ret == 0 || ret == -ENOSYS);
+ if (ret == 0) {
+ Return<int32_t> hidlReturn = mSoundTriggerHal->setParameters(values);
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(0, hidlReturn);
+ }
+}
+
+/**
+ * Test ISoundTriggerHw::setParameters() method
+ *
+ * Verifies that:
+ * - the implementation accepts empty parameters to be set or indicates it is not supported by
+ * returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, setParameters) {
+ hidl_vec<ParameterValue> values;
+ Return<int32_t> hidlReturn = mSoundTriggerHal->setParameters(values);
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
+}
+
+/**
+ * Test ISoundTriggerHw::getSoundModelParameters() and setSoundModelParameters() methods
+ *
+ * Verifies that:
+ * - the implementation implements these optional methods or indicates it is not supported by
+ * returning -ENOSYS;
+ * - if the methods are supported, the implementation returns an error when called without
+ * an active recognition running.
+ *
+ */
+TEST_F(SoundTriggerHidlTest, getAndSetSoundModelParameters) {
+ SoundModelHandle handle = 0;
+ hidl_vec<hidl_string> keys;
+ hidl_vec<ParameterValue> values;
+
+ {
+ int32_t ret = 0;
+ Return<void> hidlReturn = mSoundTriggerHal->getSoundModelParameters(
+ handle, keys, [&](int32_t retval, auto params) {
+ ret = retval;
+ values = params;
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_EQ(0u, values.size());
+ }
+
+ values.resize(0);
+ {
+ Return<int32_t> hidlReturn = mSoundTriggerHal->setSoundModelParameters(handle, values);
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+ }
+}
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index b9fb0bd..4b8d68a 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -1411,7 +1411,8 @@
vec<uint8_t> extendedServiceSpecificInfo;
/**
* The match filter from the discovery packet (publish or subscribe) which caused service
- * discovery. Matches the peer's |NanDiscoveryCommonConfig.txMatchFilter|.
+ * discovery. Matches the |NanDiscoveryCommonConfig.txMatchFilter| of the peer's Unsolicited
+ * publish message or of the local device's Active subscribe message.
* Max length: |NanCapabilities.maxMatchFilterLen|.
* NAN Spec: Service Descriptor Attribute (SDA) / Matching Filter
*/
diff --git a/wifi/1.2/Android.bp b/wifi/1.2/Android.bp
index 49752a1..100b36b 100644
--- a/wifi/1.2/Android.bp
+++ b/wifi/1.2/Android.bp
@@ -7,14 +7,23 @@
enabled: true,
},
srcs: [
+ "types.hal",
"IWifi.hal",
"IWifiChip.hal",
+ "IWifiNanIface.hal",
+ "IWifiNanIfaceEventCallback.hal",
],
interfaces: [
"android.hardware.wifi@1.0",
"android.hardware.wifi@1.1",
"android.hidl.base@1.0",
],
+ types: [
+ "NanConfigRequestSupplemental",
+ "NanDataPathChannelInfo",
+ "NanDataPathConfirmInd",
+ "NanDataPathScheduleUpdateInd",
+ ],
gen_java: true,
}
diff --git a/wifi/1.2/IWifiNanIface.hal b/wifi/1.2/IWifiNanIface.hal
new file mode 100644
index 0000000..0260162
--- /dev/null
+++ b/wifi/1.2/IWifiNanIface.hal
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::CommandIdShort;
+import @1.0::IWifiNanIface;
+import @1.0::NanConfigRequest;
+import @1.0::NanEnableRequest;
+import @1.0::WifiStatus;
+import IWifiNanIfaceEventCallback;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.0::IWifiNanIface {
+ /**
+ * Requests notifications of significant events on this iface. Multiple calls
+ * to this must register multiple callbacks each of which must receive all
+ * events.
+ *
+ * Note: supersedes the @1.0::IWifiNanIface.registerEventCallback() method which is deprecated
+ * as of HAL version 1.2.
+ *
+ * @param callback An instance of the |IWifiNanIfaceEventCallback| HIDL interface
+ * object.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ registerEventCallback_1_2(IWifiNanIfaceEventCallback callback)
+ generates (WifiStatus status);
+
+ /**
+ * Enable NAN: configures and activates NAN clustering (does not start
+ * a discovery session or set up data-interfaces or data-paths). Use the
+ * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+ * NAN interface.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+ *
+ * Note: supersedes the @1.0::IWifiNanIface.enableRequest() method which is deprecated as of
+ * HAL version 1.2.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param msg1 Instance of |NanEnableRequest|.
+ * @param msg2 Instance of |NanConfigRequestSupplemental|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ enableRequest_1_2(CommandIdShort cmdId, NanEnableRequest msg1,
+ NanConfigRequestSupplemental msg2)
+ generates (WifiStatus status);
+
+ /**
+ * Configure NAN: configures an existing NAN functionality (i.e. assumes
+ * |IWifiNanIface.enableRequest| already submitted and succeeded).
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+ *
+ * Note: supersedes the @1.0::IWifiNanIface.configRequest() method which is deprecated as of
+ * HAL version 1.2.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param msg1 Instance of |NanConfigRequest|.
+ * @param msg1 Instance of |NanConfigRequestSupplemental|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ configRequest_1_2(CommandIdShort cmdId, NanConfigRequest msg1,
+ NanConfigRequestSupplemental msg2)
+ generates (WifiStatus status);
+};
diff --git a/wifi/1.2/IWifiNanIfaceEventCallback.hal b/wifi/1.2/IWifiNanIfaceEventCallback.hal
new file mode 100644
index 0000000..efd5479
--- /dev/null
+++ b/wifi/1.2/IWifiNanIfaceEventCallback.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::IWifiNanIfaceEventCallback;
+
+/**
+ * NAN Response and Asynchronous Event Callbacks.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIfaceEventCallback extends @1.0::IWifiNanIfaceEventCallback {
+ /**
+ * Asynchronous callback indicating a data-path (NDP) setup has been completed: received by
+ * both Initiator and Responder.
+ *
+ * Note: supersedes the @1.0::IWifiNanIfaceEventCallback.eventDataPathConfirm() method which is
+ * deprecated as of HAL version 1.2.
+ *
+ * @param event: NanDataPathConfirmInd containing event details.
+ */
+ oneway eventDataPathConfirm_1_2(NanDataPathConfirmInd event);
+
+ /**
+ * Asynchronous callback indicating a data-path (NDP) schedule has been updated (e.g. channels
+ * have been changed).
+ *
+ * @param event: NanDataPathScheduleUpdateInd containing event details.
+ */
+ oneway eventDataPathScheduleUpdate(NanDataPathScheduleUpdateInd event);
+};
\ No newline at end of file
diff --git a/wifi/1.2/default/hidl_struct_util.cpp b/wifi/1.2/default/hidl_struct_util.cpp
index 5d48109..f87828c 100644
--- a/wifi/1.2/default/hidl_struct_util.cpp
+++ b/wifi/1.2/default/hidl_struct_util.cpp
@@ -1118,6 +1118,35 @@
return true;
}
+bool convertHidlNanEnableRequest_1_2ToLegacy(
+ const NanEnableRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanEnableRequest_1_2ToLegacy: null legacy_request";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_discovery_beacon_int = 1;
+ legacy_request->discovery_beacon_interval =
+ hidl_request2.discoveryBeaconIntervalMs;
+ legacy_request->config_nss = 1;
+ legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->config_dw_early_termination = 1;
+ legacy_request->enable_dw_termination =
+ hidl_request2.enableDiscoveryWindowEarlyTermination;
+ legacy_request->config_enable_ranging = 1;
+ legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+ return true;
+}
+
bool convertHidlNanPublishRequestToLegacy(
const NanPublishRequest& hidl_request,
legacy_hal::NanPublishRequest* legacy_request) {
@@ -1600,6 +1629,35 @@
return true;
}
+bool convertHidlNanConfigRequest_1_2ToLegacy(
+ const NanConfigRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request "
+ "is null";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_discovery_beacon_int = 1;
+ legacy_request->discovery_beacon_interval =
+ hidl_request2.discoveryBeaconIntervalMs;
+ legacy_request->config_nss = 1;
+ legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->config_dw_early_termination = 1;
+ legacy_request->enable_dw_termination =
+ hidl_request2.enableDiscoveryWindowEarlyTermination;
+ legacy_request->config_enable_ranging = 1;
+ legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+ return true;
+}
+
bool convertHidlNanDataPathInitiatorRequestToLegacy(
const NanInitiateDataPathRequest& hidl_request,
legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
@@ -1902,6 +1960,22 @@
return true;
}
+bool convertLegacyNdpChannelInfoToHidl(
+ const legacy_hal::NanChannelInfo& legacy_struct,
+ NanDataPathChannelInfo* hidl_struct) {
+ if (!hidl_struct) {
+ LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
+ return false;
+ }
+ *hidl_struct = {};
+
+ hidl_struct->channelFreq = legacy_struct.channel;
+ hidl_struct->channelBandwidth = legacy_struct.bandwidth;
+ hidl_struct->numSpatialStreams = legacy_struct.nss;
+
+ return true;
+}
+
bool convertLegacyNanDataPathConfirmIndToHidl(
const legacy_hal::NanDataPathConfirmInd& legacy_ind,
NanDataPathConfirmInd* hidl_ind) {
@@ -1912,18 +1986,60 @@
}
*hidl_ind = {};
- hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
- hidl_ind->dataPathSetupSuccess =
+ hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
+ hidl_ind->V1_0.dataPathSetupSuccess =
legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
- hidl_ind->peerNdiMacAddr =
+ hidl_ind->V1_0.peerNdiMacAddr =
hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
- hidl_ind->appInfo =
+ hidl_ind->V1_0.appInfo =
std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
legacy_ind.app_info.ndp_app_info +
legacy_ind.app_info.ndp_app_info_len);
- hidl_ind->status.status =
+ hidl_ind->V1_0.status.status =
convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
- hidl_ind->status.description = ""; // TODO: b/34059183
+ hidl_ind->V1_0.status.description = ""; // TODO: b/34059183
+
+ std::vector<NanDataPathChannelInfo> channelInfo;
+ for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+ NanDataPathChannelInfo hidl_struct;
+ if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+ &hidl_struct)) {
+ return false;
+ }
+ channelInfo.push_back(hidl_struct);
+ }
+ hidl_ind->channelInfo = channelInfo;
+
+ return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+ NanDataPathScheduleUpdateInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
+ "hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->peerDiscoveryAddress =
+ hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
+ std::vector<NanDataPathChannelInfo> channelInfo;
+ for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+ NanDataPathChannelInfo hidl_struct;
+ if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+ &hidl_struct)) {
+ return false;
+ }
+ channelInfo.push_back(hidl_struct);
+ }
+ hidl_ind->channelInfo = channelInfo;
+ std::vector<uint32_t> ndpInstanceIds;
+ for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+ ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+ }
+ hidl_ind->ndpInstanceIds = ndpInstanceIds;
return true;
}
diff --git a/wifi/1.2/default/hidl_struct_util.h b/wifi/1.2/default/hidl_struct_util.h
index 6766b0f..1208afd 100644
--- a/wifi/1.2/default/hidl_struct_util.h
+++ b/wifi/1.2/default/hidl_struct_util.h
@@ -22,6 +22,7 @@
#include <android/hardware/wifi/1.0/IWifiChip.h>
#include <android/hardware/wifi/1.0/types.h>
#include <android/hardware/wifi/1.1/IWifiChip.h>
+#include <android/hardware/wifi/1.2/types.h>
#include "wifi_legacy_hal.h"
@@ -106,6 +107,14 @@
bool convertHidlNanConfigRequestToLegacy(
const NanConfigRequest& hidl_request,
legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_2ToLegacy(
+ const NanEnableRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_2ToLegacy(
+ const NanConfigRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request);
bool convertHidlNanPublishRequestToLegacy(
const NanPublishRequest& hidl_request,
legacy_hal::NanPublishRequest* legacy_request);
@@ -138,6 +147,9 @@
bool convertLegacyNanDataPathConfirmIndToHidl(
const legacy_hal::NanDataPathConfirmInd& legacy_ind,
NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+ NanDataPathScheduleUpdateInd* hidl_ind);
// RTT controller conversion methods.
bool convertHidlVectorOfRttConfigToLegacy(
diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
index f73869b..1b082d0 100644
--- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
@@ -117,8 +117,10 @@
});
} else if (type == IfaceType::NAN) {
chip_->createNanIface(
- [&iface_name](const WifiStatus& status,
- const sp<IWifiNanIface>& iface) {
+ [&iface_name](
+ const WifiStatus& status,
+ const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
+ iface) {
if (WifiStatusCode::SUCCESS == status.code) {
ASSERT_NE(iface.get(), nullptr);
iface->getName([&iface_name](const WifiStatus& status,
diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.2/default/wifi_nan_iface.cpp
index 12e4d7b..535e3d3 100644
--- a/wifi/1.2/default/wifi_nan_iface.cpp
+++ b/wifi/1.2/default/wifi_nan_iface.cpp
@@ -428,7 +428,7 @@
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventDataPathConfirm(hidl_struct).isOk()) {
+ if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
@@ -467,10 +467,28 @@
LOG(ERROR) << "on_event_range_report - should not be called";
};
- callback_handlers.on_event_schedule_update =
- [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& /* msg */) {
- LOG(ERROR) << "on_event_schedule_update - should not be called";
- };
+ callback_handlers
+ .on_event_schedule_update = [weak_ptr_this](
+ const legacy_hal::
+ NanDataPathScheduleUpdateInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanDataPathScheduleUpdateInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
@@ -511,7 +529,7 @@
}
Return<void> WifiNanIface::registerEventCallback(
- const sp<IWifiNanIfaceEventCallback>& callback,
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
registerEventCallback_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::registerEventCallbackInternal,
@@ -628,6 +646,32 @@
hidl_status_cb, cmd_id, ndpInstanceId);
}
+Return<void> WifiNanIface::registerEventCallback_1_2(
+ const sp<IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_2_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallback_1_2Internal,
+ hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_2(
+ uint16_t cmd_id, const NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ enableRequest_1_2_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequest_1_2Internal,
+ hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_2(
+ uint16_t cmd_id, const NanConfigRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ configRequest_1_2_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequest_1_2Internal,
+ hidl_status_cb, cmd_id, msg1, msg2);
+}
+
std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
}
@@ -637,11 +681,8 @@
}
WifiStatus WifiNanIface::registerEventCallbackInternal(
- const sp<IWifiNanIfaceEventCallback>& callback) {
- if (!event_cb_handler_.addCallback(callback)) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
+ const sp<V1_0::IWifiNanIfaceEventCallback>& /*callback*/) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
@@ -650,28 +691,14 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-WifiStatus WifiNanIface::enableRequestInternal(uint16_t cmd_id,
- const NanEnableRequest& msg) {
- legacy_hal::NanEnableRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanEnableRequestToLegacy(msg,
- &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
+WifiStatus WifiNanIface::enableRequestInternal(
+ uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
-WifiStatus WifiNanIface::configRequestInternal(uint16_t cmd_id,
- const NanConfigRequest& msg) {
- legacy_hal::NanConfigRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanConfigRequestToLegacy(msg,
- &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
+WifiStatus WifiNanIface::configRequestInternal(
+ uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
@@ -780,6 +807,40 @@
return createWifiStatusFromLegacyError(legacy_status);
}
+WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
+ const sp<IWifiNanIfaceEventCallback>& callback) {
+ if (!event_cb_handler_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_2Internal(
+ uint16_t cmd_id, const NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2) {
+ legacy_hal::NanEnableRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy(
+ msg1, msg2, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::configRequest_1_2Internal(
+ uint16_t cmd_id, const NanConfigRequest& msg1,
+ const NanConfigRequestSupplemental& msg2) {
+ legacy_hal::NanConfigRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy(
+ msg1, msg2, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
} // namespace implementation
} // namespace V1_2
} // namespace wifi
diff --git a/wifi/1.2/default/wifi_nan_iface.h b/wifi/1.2/default/wifi_nan_iface.h
index 6fa7b0c..a2dcf3a 100644
--- a/wifi/1.2/default/wifi_nan_iface.h
+++ b/wifi/1.2/default/wifi_nan_iface.h
@@ -18,8 +18,8 @@
#define WIFI_NAN_IFACE_H_
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiNanIface.h>
#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.2/IWifiNanIface.h>
#include "hidl_callback_util.h"
#include "wifi_legacy_hal.h"
@@ -34,7 +34,7 @@
/**
* HIDL interface object used to control a NAN Iface instance.
*/
-class WifiNanIface : public V1_0::IWifiNanIface {
+class WifiNanIface : public V1_2::IWifiNanIface {
public:
WifiNanIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -47,7 +47,7 @@
Return<void> getName(getName_cb hidl_status_cb) override;
Return<void> getType(getType_cb hidl_status_cb) override;
Return<void> registerEventCallback(
- const sp<IWifiNanIfaceEventCallback>& callback,
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
registerEventCallback_cb hidl_status_cb) override;
Return<void> getCapabilitiesRequest(
uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
@@ -88,12 +88,24 @@
uint16_t cmd_id, uint32_t ndpInstanceId,
terminateDataPathRequest_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_2(
+ const sp<IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_2_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_2(
+ uint16_t cmd_id, const NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ enableRequest_1_2_cb hidl_status_cb) override;
+ Return<void> configRequest_1_2(
+ uint16_t cmd_id, const NanConfigRequest& msg1,
+ const NanConfigRequestSupplemental& msg2,
+ configRequest_1_2_cb hidl_status_cb) override;
+
private:
// Corresponding worker functions for the HIDL methods.
std::pair<WifiStatus, std::string> getNameInternal();
std::pair<WifiStatus, IfaceType> getTypeInternal();
WifiStatus registerEventCallbackInternal(
- const sp<IWifiNanIfaceEventCallback>& callback);
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
WifiStatus enableRequestInternal(uint16_t cmd_id,
const NanEnableRequest& msg);
@@ -119,6 +131,15 @@
WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
uint32_t ndpInstanceId);
+ WifiStatus registerEventCallback_1_2Internal(
+ const sp<IWifiNanIfaceEventCallback>& callback);
+ WifiStatus enableRequest_1_2Internal(
+ uint16_t cmd_id, const NanEnableRequest& msg1,
+ const NanConfigRequestSupplemental& msg2);
+ WifiStatus configRequest_1_2Internal(
+ uint16_t cmd_id, const NanConfigRequest& msg,
+ const NanConfigRequestSupplemental& msg2);
+
std::set<sp<IWifiNanIfaceEventCallback>> getEventCallbacks();
std::string ifname_;
diff --git a/wifi/1.2/types.hal b/wifi/1.2/types.hal
new file mode 100644
index 0000000..1636ae8
--- /dev/null
+++ b/wifi/1.2/types.hal
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::MacAddress;
+import @1.0::NanDataPathConfirmInd;
+import @1.0::WifiChannelInMhz;
+
+/**
+ * NAN configuration request parameters added in the 1.2 HAL. These are supplemental to previous
+ * versions.
+ */
+struct NanConfigRequestSupplemental {
+ /**
+ * Specify the Discovery Beacon interval in ms. Specification only applicable if the device
+ * transmits Discovery Beacons (based on the Wi-Fi Aware protocol selection criteria). The value
+ * can be increased to reduce power consumption (on devices which would transmit Discovery
+ * Beacons), however - cluster synchronization time will likely increase.
+ * Values are:
+ * - A value of 0 indicates that the HAL sets the interval to a default (implementation specific)
+ * - A positive value
+ */
+ uint32_t discoveryBeaconIntervalMs;
+ /**
+ * The number of spatial streams to be used for transmitting NAN management frames (does NOT apply
+ * to data-path packets). A small value may reduce power consumption for small discovery packets.
+ * Values are:
+ * - A value of 0 indicates that the HAL sets the number to a default (implementation specific)
+ * - A positive value
+ */
+ uint32_t numberOfSpatialStreamsInDiscovery;
+ /**
+ * Controls whether the device may terminate listening on a Discovery Window (DW) earlier than the
+ * DW termination (16ms) if no information is received. Enabling the feature will result in
+ * lower power consumption, but may result in some missed messages and hence increased latency.
+ */
+ bool enableDiscoveryWindowEarlyTermination;
+ /**
+ * Controls whether NAN RTT (ranging) is permitted. Global flag on any NAN RTT operations are
+ * allowed. Controls ranging in the context of discovery as well as direct RTT.
+ */
+ bool enableRanging;
+};
+
+/**
+ * NAN data path channel information provided to the framework.
+ */
+struct NanDataPathChannelInfo {
+ /**
+ * Channel frequency in MHz.
+ */
+ WifiChannelInMhz channelFreq;
+ /**
+ * Channel bandwidth in MHz.
+ */
+ uint32_t channelBandwidth;
+ /**
+ * Number of spatial streams used in the channel.
+ */
+ uint32_t numSpatialStreams;
+};
+
+/**
+ * NAN Data path confirmation Indication structure.
+ * Event indication is received on both initiator and responder side when negotiation for a
+ * data-path finish: on success or failure.
+ */
+struct NanDataPathConfirmInd {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::NanDataPathConfirmInd V1_0;
+ /**
+ * The channel(s) on which the NDP is scheduled to operate.
+ * Updates to the operational channels are provided using the |eventDataPathScheduleUpdate|
+ * event.
+ */
+ vec<NanDataPathChannelInfo> channelInfo;
+};
+
+/**
+ * NAN data path channel information update indication structure.
+ * Event indication is received by all NDP owners whenever the channels on which the NDP operates
+ * are updated.
+ * Note: multiple NDPs may share the same schedule, the indication specifies all NDPs to which it
+ * applies.
+ */
+struct NanDataPathScheduleUpdateInd {
+ /**
+ * The discovery address (NMI) of the peer to which the NDP is connected.
+ */
+ MacAddress peerDiscoveryAddress;
+ /**
+ * The updated channel(s) information.
+ */
+ vec<NanDataPathChannelInfo> channelInfo;
+ /**
+ * The list of NDPs to which this update applies.
+ */
+ vec<uint32_t> ndpInstanceIds;
+};
diff --git a/wifi/hostapd/1.0/Android.bp b/wifi/hostapd/1.0/Android.bp
new file mode 100644
index 0000000..a17e153
--- /dev/null
+++ b/wifi/hostapd/1.0/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.hostapd@1.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IHostapd.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "HostapdStatus",
+ "HostapdStatusCode",
+ ],
+ gen_java: true,
+}
+
diff --git a/wifi/hostapd/1.0/IHostapd.hal b/wifi/hostapd/1.0/IHostapd.hal
new file mode 100644
index 0000000..4dc7bf8
--- /dev/null
+++ b/wifi/hostapd/1.0/IHostapd.hal
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.0;
+
+import android.hardware.wifi.supplicant@1.0::Ssid;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd {
+ /**
+ * Size limits for some of the params used in this interface.
+ */
+ enum ParamSizeLimits : uint32_t {
+ /** Max length of SSID param. */
+ SSID_MAX_LEN_IN_BYTES = 32,
+
+ /** Min length of PSK passphrase param. */
+ WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8,
+
+ /** Max length of PSK passphrase param. */
+ WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63,
+ };
+
+ /** Possble Security types. */
+ enum EncryptionType : uint32_t {
+ NONE,
+ WPA,
+ WPA2
+ };
+
+ /**
+ * Band to use for the SoftAp operations.
+ * When using ACS, special value |BAND_ANY| can be
+ * used to indicate that any supported band can be used. This special
+ * case is currently supported only with drivers with which
+ * offloaded ACS is used.
+ */
+ enum Band : uint32_t {
+ BAND_2_4_GHZ,
+ BAND_5_GHZ,
+ BAND_ANY
+ };
+
+ /**
+ * Parameters to control the HW mode for the interface.
+ */
+ struct HwModeParams {
+ /**
+ * Whether IEEE 802.11n (HT) is enabled or not.
+ * Note: hwMode=G (2.4 GHz) and hwMode=A (5 GHz) is used to specify
+ * the band.
+ */
+ bool enable80211N;
+ /**
+ * Whether IEEE 802.11ac (VHT) is enabled or not.
+ * Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
+ */
+ bool enable80211AC;
+ };
+
+ /**
+ * Parameters to control the channel selection for the interface.
+ */
+ struct ChannelParams {
+ /**
+ * Whether to enable ACS (Automatic Channel Selection) or not.
+ * The channel can be selected automatically at run time by setting
+ * this flag, which must enable the ACS survey based algorithm.
+ */
+ bool enableAcs;
+ /**
+ * This option can be used to exclude all DFS channels from the ACS
+ * channel list in cases where the driver supports DFS channels.
+ **/
+ bool acsShouldExcludeDfs;
+ /**
+ * Channel number (IEEE 802.11) to use for the interface.
+ * If ACS is enabled, this field is ignored.
+ */
+ uint32_t channel;
+ /**
+ * Band to use for the SoftAp operations.
+ */
+ Band band;
+ };
+
+ /**
+ * Parameters to use for setting up the access point interface.
+ */
+ struct IfaceParams {
+ /** Name of the interface */
+ string ifaceName;
+ /** Hw mode params for the interface */
+ HwModeParams hwModeParams;
+ /** Chanel params for the interface */
+ ChannelParams channelParams;
+ };
+
+ /**
+ * Parameters to use for setting up the access point network.
+ */
+ struct NetworkParams {
+ /** SSID to set for the network */
+ Ssid ssid;
+ /** Whether the network needs to be hidden or not. */
+ bool isHidden;
+ /** Key management mask for the network. */
+ EncryptionType encryptionType;
+ /** Passphrase for WPA_PSK network. */
+ string pskPassphrase;
+ };
+
+ /**
+ * Adds a new access point for hostapd to control.
+ *
+ * This should trigger the setup of an access point with the specified
+ * interface and network params.
+ *
+ * @param ifaceParams AccessPoint Params for the access point.
+ * @param nwParams Network Params for the access point.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|,
+ * |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+ */
+ addAccessPoint(IfaceParams ifaceParams, NetworkParams nwParams)
+ generates(HostapdStatus status);
+
+ /**
+ * Removes an existing access point from hostapd.
+ *
+ * This should bring down the access point previously setup on the
+ * interface.
+ *
+ * @param ifaceName Name of the interface.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|,
+ * |HostapdStatusCode.FAILURE_IFACE_UNKNOWN|
+ */
+ removeAccessPoint(string ifaceName) generates(HostapdStatus status);
+};
diff --git a/wifi/hostapd/1.0/types.hal b/wifi/hostapd/1.0/types.hal
new file mode 100644
index 0000000..31bbc34
--- /dev/null
+++ b/wifi/hostapd/1.0/types.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.0;
+/**
+ * Enum values indicating the status of any hostapd operation.
+ */
+enum HostapdStatusCode : uint32_t {
+ /** No errors. */
+ SUCCESS,
+ /** Unknown failure occured. */
+ FAILURE_UNKNOWN,
+ /** One or more of the incoming args is invalid. */
+ FAILURE_ARGS_INVALID,
+ /** Iface with the provided name does not exist. */
+ FAILURE_IFACE_UNKNOWN,
+ /** Iface with the provided name already exists. */
+ FAILURE_IFACE_EXISTS
+};
+
+/**
+ * Generic structure to return the status of any hostapd operation.
+ */
+struct HostapdStatus {
+ HostapdStatusCode code;
+ /**
+ * A vendor-specific error message to provide more information beyond the
+ * status code.
+ * This must be used for debugging purposes only.
+ */
+ string debugMessage;
+};