Merge "Expanding AudioUsage to include new system usages"
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 2dbcbba..bf85da2 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -255,6 +255,13 @@
.initialValue = {.stringValue = "Toy Vehicle"}},
{.config =
{
+ .prop = toInt(VehicleProperty::INFO_EXTERIOR_DIMENSIONS),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.floatValues = {1776, 4950, 2008, 2140, 2984, 1665, 1667, 11800}}},
+ {.config =
+ {
.prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
@@ -293,7 +300,24 @@
.maxSampleRate = 10.0f,
},
.initialValue = {.floatValues = {0.0f}}},
-
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::PERF_STEERING_ANGLE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::PERF_REAR_STEERING_ANGLE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}}},
{
.config =
{
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 24fcf76..6145ea2 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -298,6 +298,28 @@
| VehicleArea:SEAT),
/**
+ * Exterior dimensions of vehicle.
+ *
+ * int32Values[0] = height
+ * int32Values[1] = length
+ * int32Values[2] = width
+ * int32Values[3] = width including mirrors
+ * int32Values[4] = wheel base
+ * int32Values[5] = track width front
+ * int32Values[6] = track width rear
+ * int32Values[7] = curb to curb turning radius
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:MILLIMETER
+ */
+ INFO_EXTERIOR_DIMENSIONS = (
+ 0x010B
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /**
* Current odometer value of the vehicle
*
* @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -340,7 +362,7 @@
| VehicleArea:GLOBAL),
/**
- * Steering angle of the vehicle
+ * Front bicycle model steering angle for vehicle
*
* Angle is in degrees. Left is negative.
*
@@ -355,6 +377,21 @@
| VehicleArea:GLOBAL),
/**
+ * Rear bicycle model steering angle for vehicle
+ *
+ * Angle is in degrees. Left is negative.
+ *
+ * @change_mode VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:DEGREES
+ */
+ PERF_REAR_STEERING_ANGLE = (
+ 0x0210
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /**
* Temperature of engine coolant
*
* @change_mode VehiclePropertyChangeMode:CONTINUOUS
diff --git a/current.txt b/current.txt
index bc64c70..938c54e 100644
--- a/current.txt
+++ b/current.txt
@@ -645,35 +645,35 @@
bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardware.identity@1.0::IIdentityCredential
96ce8aad80f4c476f25261f790d357c117e79e18474c7dadd850dac704bbe65e android.hardware.identity@1.0::IIdentityCredentialStore
6e1e28a96c90ba78d47257faea3f3bb4e6360affbbfa5822f0dc31211f9266ff android.hardware.identity@1.0::IWritableIdentityCredential
-c228aaa27f66c48e147159a4f4996c5273191fece1b08de31bd171c61334855e android.hardware.keymaster@4.1::IKeymasterDevice
+27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
-7a04ea5595ed418ca3e91c28b8bd7353dd988be9be7b0c8c9e64fb4b77bd4523 android.hardware.keymaster@4.1::types
+ac429fca0da4ce91218768ec31b64ded88251f8a26d8c4f27c06abdc5b1926d9 android.hardware.keymaster@4.1::types
df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
4b5c8546533db9412fec6d32c0ef42b22e5e68dbf390c775ec3c22bb2d501102 android.hardware.neuralnetworks@1.3::IBuffer
-234cc547d63d2f24a447aee0a9a76cab68b31c080adadc5a960598b827a69fa2 android.hardware.neuralnetworks@1.3::IDevice
+5a6b75f13f0e010a4268defa4f627b862ab2899fb04f9d985194a25bd8f9fe0d android.hardware.neuralnetworks@1.3::IDevice
058b48f0e2e725bb2b3fa2b7917b0f0a696383d03a4c57afe26f0eadb6a7af28 android.hardware.neuralnetworks@1.3::IPreparedModel
94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-2576ba54711218ce0d7f207baa533fca9af3c630756938ede6e73fe197b7ea38 android.hardware.neuralnetworks@1.3::types
+12c51f9d04a52324510419aeee3e37bb3607e6900556cdde79774d80ed989855 android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
-c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
-168480869108d9c21bd09eb6ac550a2149b7f794ad05a16ae99e1628c75a5eb2 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-8835e9799cddf7c239f60beff467cbdf164331f70a8b6c06ed78982d7810d835 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+8aed0a8e03e7a67bfdfb78ad7529a9ae95bea36e6060473b204c89d772522126 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types
##
# BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present
##
-73b5418353fe52721267d64592d4d4c1b77fbd1ef4261d964865de88e62ee0be android.hardware.radio@1.5::types
+696f9000adf181682a49510baf93127e2ca62cfc84173b36afd164c797bc5771 android.hardware.radio@1.5::types
996f98ffe508a2f6f1755c1511b50067f7883f7c445dea9f3e931385f020b7ab android.hardware.radio@1.5::IRadio
20d52e66fd548f89bcb98cda42749a591ce8f439a2a7148617adac0c967ad937 android.hardware.radio@1.5::IRadioIndication
1512f6e1198e1aa0ebcbdb1694d0ed500a3e7791d6f305327866112331d82b66 android.hardware.radio@1.5::IRadioResponse
-55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
-b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
+5971a891d7d8843e9fb9f44583a9a0a265ec42fd5e4e1c95c9803454d21fabf7 android.hardware.radio.config@1.3::types
+a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig
742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
-7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
+0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse
##
# END Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present
##
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index 64ed4f3..499d3b9 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -626,9 +626,15 @@
}
protected:
+ template <typename T>
+ bool beginCommand(T* outCommand, uint16_t* outLength) {
+ return beginCommandBase(reinterpret_cast<IComposerClient::Command*>(outCommand),
+ outLength);
+ }
+
bool isEmpty() const { return (mDataRead >= mDataSize); }
- bool beginCommand(IComposerClient::Command* outCommand, uint16_t* outLength) {
+ bool beginCommandBase(IComposerClient::Command* outCommand, uint16_t* outLength) {
if (mCommandEnd) {
LOG_FATAL("endCommand was not called for last command");
}
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
index b173e2e..ab67eb1 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
@@ -146,6 +146,25 @@
return std::make_unique<CommandWriterBase>(writerInitialSize);
}
+ virtual Error executeValidateDisplayInternal() {
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks);
+ mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+ if (err == Error::NONE) {
+ mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
+ mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+ } else {
+ mWriter->setError(getCommandLoc(), err);
+ }
+ return err;
+ }
+
bool executeSelectDisplay(uint16_t length) {
if (length != CommandWriterBase::kSelectDisplayLength) {
return false;
@@ -255,23 +274,7 @@
if (length != CommandWriterBase::kValidateDisplayLength) {
return false;
}
-
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
- uint32_t displayRequestMask = 0x0;
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
- &displayRequestMask, &requestedLayers, &requestMasks);
- mResources->setDisplayMustValidateState(mCurrentDisplay, false);
- if (err == Error::NONE) {
- mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
- mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
- } else {
- mWriter->setError(getCommandLoc(), err);
- }
-
+ executeValidateDisplayInternal();
return true;
}
@@ -297,21 +300,9 @@
}
// Present has failed. We need to fallback to validate
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
- uint32_t displayRequestMask = 0x0;
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
- &displayRequestMask, &requestedLayers, &requestMasks);
- mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+ auto err = executeValidateDisplayInternal();
if (err == Error::NONE) {
mWriter->setPresentOrValidateResult(0);
- mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
- mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
- } else {
- mWriter->setError(getCommandLoc(), err);
}
return true;
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index 1b8170b..7e0c33c 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -16,6 +16,9 @@
package android.hardware.graphics.composer@2.4;
+import android.hardware.graphics.common@1.2::PixelFormat;
+import android.hardware.graphics.common@1.2::Dataspace;
+import android.hardware.graphics.composer@2.1::IComposerClient.Command;
import IComposerCallback;
import @2.1::Config;
import @2.1::Display;
@@ -56,6 +59,20 @@
AUTO_LOW_LATENCY_MODE = 5,
};
+ enum Command : @2.3::IComposerClient.Command {
+ /**
+ * SET_CLIENT_TARGET_PROPERTY has this pseudo prototype
+ *
+ * This command has the following binary layout in bytes:
+ *
+ * 0 - 3: clientTargetProperty.pixelFormat
+ * 4 - 7: clientTargetProperty.dataspace
+ *
+ * setClientTargetProperty(ClientTargetProperty clientTargetProperty);
+ */
+ SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+ };
+
/**
* Supersedes {@link @2.1::IComposerClient.DisplayType}.
*/
@@ -99,6 +116,11 @@
bool seamlessRequired;
};
+ struct ClientTargetProperty {
+ PixelFormat pixelFormat;
+ Dataspace dataspace;
+ };
+
/**
* Provides a IComposerCallback object for the device to call.
*
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
index cb391be..e84779e 100644
--- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -41,14 +41,25 @@
// units of uint32_t's.
class CommandWriterBase : public V2_3::CommandWriterBase {
public:
+ static constexpr uint16_t kSetClientTargetPropertyLength = 2;
+
CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {}
+
+ void setClientTargetProperty(
+ const IComposerClient::ClientTargetProperty& clientTargetProperty) {
+ beginCommand(IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY,
+ kSetClientTargetPropertyLength);
+ writeSigned(static_cast<int32_t>(clientTargetProperty.pixelFormat));
+ writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
+ endCommand();
+ }
};
// This class helps parse a command queue. Note that all sizes/lengths are in
// units of uint32_t's.
class CommandReaderBase : public V2_3::CommandReaderBase {
public:
- CommandReaderBase() : V2_3::CommandReaderBase(){};
+ CommandReaderBase() : V2_3::CommandReaderBase() {}
};
} // namespace V2_4
diff --git a/graphics/composer/2.4/utils/hal/Android.bp b/graphics/composer/2.4/utils/hal/Android.bp
index 3ee4e19..f4cdea4 100644
--- a/graphics/composer/2.4/utils/hal/Android.bp
+++ b/graphics/composer/2.4/utils/hal/Android.bp
@@ -26,11 +26,11 @@
],
header_libs: [
"android.hardware.graphics.composer@2.3-hal",
- "android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
],
export_header_lib_headers: [
"android.hardware.graphics.composer@2.3-hal",
- "android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
],
export_include_dirs: ["include"],
}
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
index d48a9e7..c864ce6 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -22,6 +22,7 @@
#include <android/hardware/graphics/composer/2.4/IComposerCallback.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-hal/2.4/ComposerCommandEngine.h>
#include <composer-hal/2.4/ComposerHal.h>
#include <composer-resources/2.1/ComposerResources.h>
@@ -168,12 +169,18 @@
return client->init() ? std::move(client) : nullptr;
}
+ protected:
+ std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
+ return std::make_unique<ComposerCommandEngine>(
+ mHal, static_cast<V2_2::hal::ComposerResources*>(mResources.get()));
+ }
+
private:
using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1::mHal;
- std::unique_ptr<HalEventCallback> mHalEventCallback_2_4;
using BaseType2_1::mResources;
+ std::unique_ptr<HalEventCallback> mHalEventCallback_2_4;
};
} // namespace detail
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
new file mode 100644
index 0000000..e0153ce
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.3/ComposerCommandEngine.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine {
+ public:
+ ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources)
+ : BaseType2_3(hal, resources), mHal(hal) {}
+
+ protected:
+ std::unique_ptr<V2_1::CommandWriterBase> createCommandWriter(
+ size_t writerInitialSize) override {
+ return std::make_unique<CommandWriterBase>(writerInitialSize);
+ }
+
+ private:
+ using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+ using BaseType2_3 = V2_3::hal::ComposerCommandEngine;
+ using BaseType2_1::mWriter;
+
+ V2_1::Error executeValidateDisplayInternal() override {
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+ IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
+ Dataspace::UNKNOWN};
+
+ auto err = mHal->validateDisplay_2_4(mCurrentDisplay, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks,
+ &clientTargetProperty);
+ mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+ if (err == Error::NONE) {
+ mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
+ mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+ getWriter()->setClientTargetProperty(clientTargetProperty);
+ } else {
+ mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(err));
+ }
+ return static_cast<V2_1::Error>(err);
+ }
+
+ CommandWriterBase* getWriter() { return static_cast<CommandWriterBase*>(mWriter.get()); }
+
+ ComposerHal* mHal;
+};
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
index bbc5405..277055c 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -73,6 +73,12 @@
Display display,
std::vector<IComposerClient::ContentType>* outSupportedContentTypes) = 0;
virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0;
+ virtual Error validateDisplay_2_4(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
index 07d8607..616852a 100644
--- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -43,6 +43,7 @@
using common::V1_2::PixelFormat;
using V2_1::Config;
using V2_1::Display;
+using V2_1::Layer;
using V2_4::Error;
// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
@@ -218,6 +219,32 @@
return Error::NONE;
}
+ Error validateDisplay_2_4(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty) override {
+ auto err = static_cast<Error>(BaseType2_1::validateDisplay(
+ display, outChangedLayers, outCompositionTypes, outDisplayRequestMask,
+ outRequestedLayers, outRequestMasks));
+ if (err != Error::NONE) {
+ return err;
+ }
+
+ if (mDispatch.getClientTargetProperty) {
+ hwc_client_target_property_t clientTargetProperty;
+ err = static_cast<Error>(
+ mDispatch.getClientTargetProperty(mDevice, display, &clientTargetProperty));
+ outClientTargetProperty->pixelFormat =
+ static_cast<PixelFormat>(clientTargetProperty.pixelFormat);
+ outClientTargetProperty->dataspace =
+ static_cast<Dataspace>(clientTargetProperty.dataspace);
+ }
+
+ return err;
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_3::initDispatch()) {
@@ -238,6 +265,8 @@
this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES,
&mDispatch.getSupportedContentTypes);
this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY,
+ &mDispatch.getClientTargetProperty);
return true;
}
@@ -289,6 +318,7 @@
HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode;
HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
HWC2_PFN_SET_CONTENT_TYPE setContentType;
+ HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty;
} mDispatch = {};
hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 2f40282..9c5fbab 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -27,11 +27,10 @@
"authorization_set.cpp",
"key_param_output.cpp",
"keymaster_utils.cpp",
- "Keymaster.cpp",
- "Keymaster3.cpp",
- "Keymaster4.cpp",
],
- export_include_dirs: ["include"],
+ export_include_dirs: [
+ "include",
+ ],
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
@@ -39,6 +38,5 @@
"libcrypto",
"libhardware",
"libhidlbase",
- "libutils",
- ]
+ ],
}
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
deleted file mode 100644
index cc3d656..0000000
--- a/keymaster/4.0/support/Keymaster4.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-**
-** 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, const hidl_string& keymasterName,
- const hidl_string& authorName) {
- version_ = {keymasterName, authorName, 4 /* major version */, securityLevel,
- true /* supportsEc */};
- haveVersion_ = true;
- });
-
- CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
-}
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
diff --git a/keymaster/4.0/support/OWNERS b/keymaster/4.0/support/OWNERS
index 335660d..a9efe66 100644
--- a/keymaster/4.0/support/OWNERS
+++ b/keymaster/4.0/support/OWNERS
@@ -1,2 +1,3 @@
jdanis@google.com
swillden@google.com
+jbires@google.com
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
index 000d46e..27e00c1 100644
--- a/keymaster/4.0/support/attestation_record.cpp
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -321,19 +321,20 @@
LOG(ERROR) << AT << "Failed record parsing";
return ErrorCode::UNKNOWN_ERROR;
}
- if (!record->tee_enforced) {
- LOG(ERROR) << AT << "Failed hardware characteristic parsing";
+
+ KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+ root_of_trust = record->tee_enforced->root_of_trust;
+ } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+ root_of_trust = record->software_enforced->root_of_trust;
+ } else {
+ LOG(ERROR) << AT << " Failed root of trust parsing";
return ErrorCode::INVALID_ARGUMENT;
}
- if (!record->tee_enforced->root_of_trust) {
- LOG(ERROR) << AT << "Failed root of trust parsing";
+ if (!root_of_trust->verified_boot_key) {
+ LOG(ERROR) << AT << " Failed verified boot key parsing";
return ErrorCode::INVALID_ARGUMENT;
}
- if (!record->tee_enforced->root_of_trust->verified_boot_key) {
- LOG(ERROR) << AT << "Failed verified boot key parsing";
- return ErrorCode::INVALID_ARGUMENT;
- }
- KM_ROOT_OF_TRUST* root_of_trust = record->tee_enforced->root_of_trust;
auto& vb_key = root_of_trust->verified_boot_key;
verified_boot_key->resize(vb_key->length);
@@ -342,19 +343,19 @@
*verified_boot_state = static_cast<keymaster_verified_boot_t>(
ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
if (!verified_boot_state) {
- LOG(ERROR) << AT << "Failed verified boot state parsing";
+ LOG(ERROR) << AT << " Failed verified boot state parsing";
return ErrorCode::INVALID_ARGUMENT;
}
*device_locked = root_of_trust->device_locked;
if (!device_locked) {
- LOG(ERROR) << AT << "Failed device locked parsing";
+ LOG(ERROR) << AT << " Failed device locked parsing";
return ErrorCode::INVALID_ARGUMENT;
}
auto& vb_hash = root_of_trust->verified_boot_hash;
if (!vb_hash) {
- LOG(ERROR) << AT << "Failed verified boot hash parsing";
+ LOG(ERROR) << AT << " Failed verified boot hash parsing";
return ErrorCode::INVALID_ARGUMENT;
}
verified_boot_hash->resize(vb_hash->length);
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index d6b50f5..a024ff9 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -25,7 +25,7 @@
namespace keymaster {
namespace V4_0 {
-inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return a.tag < b.tag;
int retval;
switch (typeFromTag(a.tag)) {
@@ -58,7 +58,7 @@
return false;
}
-inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return false;
switch (typeFromTag(a.tag)) {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
deleted file mode 100644
index dfd03ef..0000000
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- **
- ** 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, const hidl_string& instanceName)
- : Keymaster(IKeymaster4Device::descriptor, instanceName),
- haveVersion_(false),
- dev_(km4_dev) {}
-
- const VersionResult& halVersion() const override {
- const_cast<Keymaster4*>(this)->getVersionIfNeeded();
- return version_;
- }
-
- 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,
- const hidl_vec<KeyParameter>& unwrappingParams,
- uint64_t passwordSid, uint64_t biometricSid,
- importWrappedKey_cb _hidl_cb) {
- return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, unwrappingParams,
- passwordSid, biometricSid, _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_;
- VersionResult version_;
- 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/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index cb29c64..bc7f311 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -355,95 +355,61 @@
return accessTagValue(ttag, param);
}
+inline bool operator<(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) return a.tag < b.tag;
+ int retval;
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return false;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.f.integer < b.f.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ return a.f.longInteger < b.f.longInteger;
+ case TagType::DATE:
+ return a.f.dateTime < b.f.dateTime;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ // Handle the empty cases.
+ if (a.blob.size() == 0) return b.blob.size() != 0;
+ if (b.blob.size() == 0) return false;
+
+ retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+ // if one is the prefix of the other the longer wins
+ if (retval == 0) return a.blob.size() < b.blob.size();
+ // Otherwise a is less if a is less.
+ else
+ return retval < 0;
+ }
+ return false;
+}
+
inline bool operator==(const KeyParameter& a, const KeyParameter& b) {
- if (a.tag != b.tag) {
- return false;
- }
+ 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::UNLOCKED_DEVICE_REQUIRED:
- case Tag::ROLLBACK_RESISTANCE:
- case Tag::RESET_SINCE_ID_ROTATION:
- case Tag::TRUSTED_CONFIRMATION_REQUIRED:
- case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
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::USER_ID:
- case Tag::AUTH_TIMEOUT:
- case Tag::VENDOR_PATCHLEVEL:
- case Tag::BOOT_PATCHLEVEL:
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
return a.f.integer == b.f.integer;
-
- /* Long integer tags */
- case Tag::RSA_PUBLIC_EXPONENT:
- case Tag::USER_SECURE_ID:
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
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:
+ case TagType::DATE:
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::CONFIRMATION_TOKEN:
- 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;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ if (a.blob.size() != b.blob.size()) return false;
+ return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
}
-
return false;
}
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 5e5ae8d..61645f8 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -52,6 +52,9 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+
} // namespace support
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
index cc71dd1..b3869f4 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
@@ -18,6 +18,8 @@
#define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
#include <android/hardware/keymaster/4.0/types.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
template <typename T, void (*F)(T*)>
struct UniquePtrDeleter {
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index e35fdd3..850a776 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+#include <regex.h>
+
+#include <android-base/properties.h>
#include <hardware/hw_auth_token.h>
#include <keymasterV4_0/keymaster_utils.h>
-namespace android {
-namespace hardware {
+namespace android::hardware {
inline static bool operator<(const hidl_vec<uint8_t>& a, const hidl_vec<uint8_t>& b) {
auto result = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
@@ -32,8 +34,7 @@
return memcmp(a.data(), b.data(), SIZE) == -1;
}
-namespace keymaster {
-namespace V4_0 {
+namespace keymaster::V4_0 {
bool operator<(const HmacSharingParameters& a, const HmacSharingParameters& b) {
return std::tie(a.seed, a.nonce) < std::tie(b.seed, b.nonce);
@@ -58,9 +59,9 @@
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),
+ 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;
@@ -86,9 +87,9 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
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),
+ 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");
if (buffer.size() != sizeof(hw_auth_token_t)) return {};
@@ -100,7 +101,7 @@
pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
token.authenticatorType = static_cast<HardwareAuthenticatorType>(
- ntohl(static_cast<uint32_t>(token.authenticatorType)));
+ ntohl(static_cast<uint32_t>(token.authenticatorType)));
pos = copy_bytes_from_iterator(&token.timestamp, pos);
token.timestamp = ntohq(token.timestamp);
token.mac.resize(kHmacSize);
@@ -109,8 +110,93 @@
return token;
}
+namespace {
+
+constexpr char kPlatformVersionProp[] = "ro.build.version.release";
+constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
+constexpr size_t kMajorVersionMatch = 1;
+constexpr size_t kMinorVersionMatch = 3;
+constexpr size_t kSubminorVersionMatch = 5;
+constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
+
+constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
+constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+
+uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
+ if (match.rm_so == -1) return 0;
+
+ size_t len = match.rm_eo - match.rm_so;
+ std::string s(expression + match.rm_so, len);
+ return std::stoul(s);
+}
+
+std::string wait_and_get_property(const char* prop) {
+ std::string prop_value;
+ while (!android::base::WaitForPropertyCreation(prop))
+ ;
+ prop_value = android::base::GetProperty(prop, "" /* default */);
+ return prop_value;
+}
+
+} // anonymous namespace
+
+uint32_t getOsVersion(const char* version_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformVersionMatchCount];
+ int not_match =
+ regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
+ uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
+ uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
+
+ return (major * 100 + minor) * 100 + subminor;
+}
+
+uint32_t getOsVersion() {
+ std::string version = wait_and_get_property(kPlatformVersionProp);
+ return getOsVersion(version.c_str());
+}
+
+uint32_t getOsPatchlevel(const char* patchlevel_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformPatchlevelMatchCount];
+ int not_match =
+ regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+ uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+ if (month < 1 || month > 12) {
+ return 0;
+ }
+ return year * 100 + month;
+}
+
+uint32_t getOsPatchlevel() {
+ std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
+ return getOsPatchlevel(patchlevel.c_str());
+}
+
} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
+} // namespace keymaster::V4_0
+} // namespace android::hardware
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 5649f20..db50080 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -19,7 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"HmacKeySharingTest.cpp",
- "KeymasterHidlTest.cpp",
"VerificationTokenTest.cpp",
"keymaster_hidl_hal_test.cpp",
],
@@ -27,7 +26,25 @@
"android.hardware.keymaster@4.0",
"libcrypto_static",
"libkeymaster4support",
- "libsoftkeymasterdevice",
+ "libkeymaster4vtstest",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
+
+cc_test_library {
+ name: "libkeymaster4vtstest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "KeymasterHidlTest.cpp",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+ static_libs: [
+ "android.hardware.keymaster@4.0",
+ "libkeymaster4support",
+ ],
}
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index c228ef7..f57a668 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -28,6 +28,16 @@
*/
class HmacKeySharingTest : public KeymasterHidlTest {
protected:
+ const std::vector<sp<IKeymasterDevice>>& allKeymasters() {
+ if (all_keymasters_.empty()) {
+ auto names = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ for (const auto& name : names) {
+ all_keymasters_.push_back(IKeymasterDevice::getService(name));
+ }
+ }
+ return all_keymasters_;
+ }
+
struct GetParamsResult {
ErrorCode error;
HmacSharingParameters params;
@@ -99,8 +109,13 @@
EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
}
}
+
+ private:
+ static std::vector<sp<IKeymasterDevice>> all_keymasters_;
};
+std::vector<sp<IKeymasterDevice>> HmacKeySharingTest::all_keymasters_;
+
TEST_P(HmacKeySharingTest, GetParameters) {
auto result1 = getHmacSharingParameters(keymaster());
EXPECT_EQ(ErrorCode::OK, result1.error);
@@ -115,26 +130,26 @@
}
TEST_P(HmacKeySharingTest, ComputeSharedHmac) {
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
auto nonces = copyNonces(params);
- EXPECT_EQ(all_keymasters().size(), nonces.size());
+ EXPECT_EQ(allKeymasters().size(), nonces.size());
std::sort(nonces.begin(), nonces.end());
std::unique(nonces.begin(), nonces.end());
- EXPECT_EQ(all_keymasters().size(), nonces.size());
+ EXPECT_EQ(allKeymasters().size(), nonces.size());
- auto responses = computeSharedHmac(all_keymasters(), params);
+ auto responses = computeSharedHmac(allKeymasters(), 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.";
+ params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
ASSERT_EQ(32U, responses[0].sharing_check.size());
verifyResponses(responses[0].sharing_check, responses);
@@ -160,15 +175,16 @@
// 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 fixup_hmac = finally([&]() {
+ computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+ });
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().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);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
HidlBuf correct_response = responses[0].sharing_check;
@@ -181,7 +197,7 @@
uint8_t bit_to_tweak = rand() % 8;
params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
for (size_t i = 0; i < responses.size(); ++i) {
if (i == param_to_tweak) {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -199,15 +215,16 @@
// 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 fixup_hmac = finally([&]() {
+ computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+ });
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().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);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
HidlBuf correct_response = responses[0].sharing_check;
@@ -223,7 +240,7 @@
}
to_tweak[0]++;
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
for (size_t i = 0; i < responses.size(); ++i) {
if (i == param_to_tweak) {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -236,10 +253,7 @@
}
}
-INSTANTIATE_TEST_SUITE_P(
- PerInstance, HmacKeySharingTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
- android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(HmacKeySharingTest);
} // namespace test
} // namespace V4_0
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 7241984..d0ad433 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -23,6 +23,7 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <keymasterV4_0/key_param_output.h>
+#include <keymasterV4_0/keymaster_utils.h>
namespace android {
namespace hardware {
@@ -41,39 +42,26 @@
namespace test {
-void KeymasterHidlTest::InitializeKeymaster() {
- service_name_ = GetParam();
- keymaster_ = IKeymasterDevice::getService(service_name_);
- ASSERT_NE(keymaster_, nullptr);
+using namespace std::literals::chrono_literals;
+void KeymasterHidlTest::InitializeKeymaster(sp<IKeymasterDevice> keymaster) {
+ ASSERT_NE(keymaster, nullptr);
+ keymaster_ = keymaster;
ASSERT_TRUE(keymaster_
- ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
- const hidl_string& author) {
- securityLevel_ = securityLevel;
- name_ = name;
- author_ = author;
- })
- .isOk());
+ ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+ const hidl_string& author) {
+ securityLevel_ = securityLevel;
+ name_ = name;
+ author_ = author;
+ })
+ .isOk());
+
+ os_version_ = support::getOsVersion();
+ os_patch_level_ = support::getOsPatchlevel();
}
void KeymasterHidlTest::SetUp() {
- InitializeKeymaster();
-
- 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 = IKeymasterDevice::getService(name);
- ASSERT_NE(keymaster, nullptr);
- all_keymasters_.push_back(keymaster);
- }
- });
+ InitializeKeymaster(IKeymasterDevice::getService(GetParam()));
}
ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
@@ -138,7 +126,7 @@
string masking_key,
const AuthorizationSet& unwrapping_params) {
ErrorCode error;
- ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
+ EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key));
EXPECT_TRUE(keymaster_
->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
unwrapping_params.hidl_data(), 0 /* passwordSid */,
@@ -207,7 +195,9 @@
HidlBuf empty_buf = {};
EXPECT_EQ(ErrorCode::OK,
GetCharacteristics(key_blob, client_id, app_data, key_characteristics));
- EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+ if (SecLevel() != SecurityLevel::SOFTWARE) {
+ EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+ }
EXPECT_GT(key_characteristics->softwareEnforced.size(), 0);
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
@@ -647,23 +637,25 @@
switch (algorithm) {
case Algorithm::RSA:
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
return {2048, 3072, 4096};
case SecurityLevel::STRONGBOX:
return {2048};
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
break;
case Algorithm::EC:
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
return {224, 256, 384, 521};
case SecurityLevel::STRONGBOX:
return {256};
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
break;
@@ -678,25 +670,27 @@
return retval;
}
default:
- CHECK(false) << "Invalid Algorithm: " << algorithm;
+ ADD_FAILURE() << "Invalid Algorithm: " << algorithm;
return {};
}
- CHECK(false) << "Should be impossible to get here";
+ ADD_FAILURE() << "Should be impossible to get here";
return {};
}
+
std::vector<uint32_t> KeymasterHidlTest::InvalidKeySizes(Algorithm algorithm) {
- if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
- CHECK(SecLevel() == SecurityLevel::STRONGBOX);
- switch (algorithm) {
- case Algorithm::RSA:
- return {3072, 4096};
- case Algorithm::EC:
- return {224, 384, 521};
- case Algorithm::AES:
- return {192};
- default:
- return {};
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ switch (algorithm) {
+ case Algorithm::RSA:
+ return {3072, 4096};
+ case Algorithm::EC:
+ return {224, 384, 521};
+ case Algorithm::AES:
+ return {192};
+ default:
+ return {};
+ }
}
+ return {};
}
std::vector<EcCurve> KeymasterHidlTest::ValidCurves() {
@@ -715,6 +709,7 @@
std::vector<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) {
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
if (withNone) {
if (withMD5)
@@ -740,10 +735,10 @@
return {Digest::SHA_2_256};
break;
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
- CHECK(false) << "Should be impossible to get here";
+ ADD_FAILURE() << "Should be impossible to get here";
return {};
}
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 4bd8b26..f495516 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -21,7 +21,6 @@
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
-#include <keymaster/keymaster_configuration.h>
#include <keymasterV4_0/authorization_set.h>
@@ -35,16 +34,18 @@
namespace test {
using ::android::sp;
-using ::std::string;
using hidl::base::V1_0::DebugInfo;
+using ::std::string;
class HidlBuf : public hidl_vec<uint8_t> {
- typedef hidl_vec<uint8_t> super;
+ using super = hidl_vec<uint8_t>;
- public:
+ public:
HidlBuf() {}
HidlBuf(const super& other) : super(other) {}
- HidlBuf(super&& other) : super(std::move(other)) {}
+ HidlBuf(super&& other) : super(std::move(other)) { other = {}; }
+ HidlBuf(const HidlBuf& other) : super(other) {}
+ HidlBuf(HidlBuf&& other) : super(std::move(other)) { other = HidlBuf(); }
explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
HidlBuf& operator=(const super& other) {
@@ -54,6 +55,18 @@
HidlBuf& operator=(super&& other) {
super::operator=(std::move(other));
+ other = {};
+ return *this;
+ }
+
+ HidlBuf& operator=(const HidlBuf& other) {
+ super::operator=(other);
+ return *this;
+ }
+
+ HidlBuf& operator=(HidlBuf&& other) {
+ super::operator=(std::move(other));
+ other.super::operator=({});
return *this;
}
@@ -70,20 +83,16 @@
class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
public:
- void SetUp();
+ void SetUp() override;
void TearDown() override {
if (key_blob_.size()) {
CheckedDeleteKey();
}
AbortIfNeeded();
- keymaster_.clear();
- all_keymasters_.clear();
}
- void InitializeKeymaster();
-
+ void InitializeKeymaster(sp<IKeymasterDevice> keymaster);
IKeymasterDevice& keymaster() { return *keymaster_; }
- const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
uint32_t os_version() { return os_version_; }
uint32_t os_patch_level() { return os_patch_level_; }
@@ -209,18 +218,26 @@
KeyCharacteristics key_characteristics_;
OperationHandle op_handle_ = kOpHandleSentinel;
- private:
- sp<IKeymasterDevice> keymaster_;
- std::vector<sp<IKeymasterDevice>> all_keymasters_;
- uint32_t os_version_;
- uint32_t os_patch_level_;
+ static std::vector<std::string> build_params() {
+ auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ return params;
+ }
- SecurityLevel securityLevel_;
- hidl_string name_;
- hidl_string author_;
- string service_name_;
+ private:
+ sp<IKeymasterDevice> keymaster_;
+ uint32_t os_version_;
+ uint32_t os_patch_level_;
+
+ SecurityLevel securityLevel_;
+ hidl_string name_;
+ hidl_string author_;
};
+#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
+ testing::ValuesIn(KeymasterHidlTest::build_params()), \
+ android::hardware::PrintInstanceNameToString)
+
} // namespace test
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
index 693f4ae..bab1439 100644
--- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -185,10 +185,7 @@
memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
}
-INSTANTIATE_TEST_SUITE_P(
- PerInstance, VerificationTokenTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
- android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationTokenTest);
} // namespace test
} // namespace V4_0
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 66132ad..6cbe4da 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -352,11 +352,11 @@
EXPECT_EQ(ErrorCode::OK, error);
if (error != ErrorCode::OK) return false;
- EXPECT_TRUE(att_attestation_version == 3);
+ EXPECT_GE(att_attestation_version, 3U);
expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
- EXPECT_EQ(att_keymaster_version, 4U);
+ EXPECT_GE(att_keymaster_version, 4U);
EXPECT_EQ(security_level, att_keymaster_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
@@ -397,10 +397,16 @@
// true. A provided boolean tag that can be pulled back out of the certificate indicates correct
// encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
// will handle mismatches of tags.
- EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ if (security_level == SecurityLevel::SOFTWARE) {
+ EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ } else {
+ EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ }
// Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
// the authorization list during key generation) isn't being attested to in the certificate.
+ EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
@@ -461,10 +467,10 @@
verified_boot_key.size()));
} else if (!strcmp(property_value, "red")) {
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_FAILED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
} else {
- EXPECT_TRUE(false);
+ EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
}
att_sw_enforced.Sort();
@@ -840,6 +846,8 @@
.Authorization(TAG_MIN_MAC_LENGTH, 128)));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(NewKeyGenerationTest);
+
typedef KeymasterHidlTest SigningOperationsTest;
/*
@@ -1509,6 +1517,8 @@
}
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(SigningOperationsTest);
+
typedef KeymasterHidlTest VerificationOperationsTest;
/*
@@ -1749,6 +1759,8 @@
CheckedDeleteKey(&verification_key);
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationOperationsTest);
+
typedef KeymasterHidlTest ExportKeyTest;
/*
@@ -1828,6 +1840,8 @@
EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ExportKeyTest);
+
class ImportKeyTest : public KeymasterHidlTest {
public:
template <TagType tag_type, Tag tag, typename ValueT>
@@ -2093,6 +2107,8 @@
VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportKeyTest);
+
auto wrapped_key = hex2str(
"3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b"
"455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b"
@@ -2214,6 +2230,8 @@
.Padding(PaddingMode::RSA_OAEP)));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportWrappedKeyTest);
+
typedef KeymasterHidlTest EncryptionOperationsTest;
/*
@@ -4111,6 +4129,8 @@
EXPECT_EQ(message, plaintext);
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(EncryptionOperationsTest);
+
typedef KeymasterHidlTest MaxOperationsTest;
/*
@@ -4166,6 +4186,8 @@
EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(MaxOperationsTest);
+
typedef KeymasterHidlTest AddEntropyTest;
/*
@@ -4196,6 +4218,8 @@
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(AddEntropyTest);
+
typedef KeymasterHidlTest AttestationTest;
/*
@@ -4373,6 +4397,8 @@
&cert_chain));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(AttestationTest);
+
typedef KeymasterHidlTest KeyDeletionTest;
/**
@@ -4478,6 +4504,8 @@
}
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(KeyDeletionTest);
+
using UpgradeKeyTest = KeymasterHidlTest;
/*
@@ -4497,6 +4525,8 @@
EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(UpgradeKeyTest);
+
using ClearOperationsTest = KeymasterHidlTest;
/*
@@ -4533,51 +4563,14 @@
AbortIfNeeded();
}
-/*
- * ClearSlotsTest.ServiceDeath
- *
- * Verifies that the service is restarted after death and the ongoing
- * operations are cleared.
- */
-TEST_P(ClearOperationsTest, ServiceDeath) {
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaEncryptionKey(2048, 65537)
- .Padding(PaddingMode::NONE)));
-
- auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
- int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16;
- OperationHandle op_handles[max_operations];
- AuthorizationSet out_params;
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
- }
- EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
-
- DebugInfo debug_info;
- GetDebugInfo(&debug_info);
- kill(debug_info.pid, SIGKILL);
- // wait 1 second for keymaster to restart
- sleep(1);
- InitializeKeymaster();
-
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
- }
- EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Abort(op_handles[i]));
- }
-}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ClearOperationsTest);
typedef KeymasterHidlTest TransportLimitTest;
/*
- * TransportLimitTest.LargeFinishInput
+ * TransportLimitTest.FinishInput
*
- * Verifies that passing large input data to finish either succeeds or fails as expected.
+ * Verifies that passing input data to finish succeeds as expected.
*/
TEST_P(TransportLimitTest, LargeFinishInput) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4586,7 +4579,7 @@
.BlockMode(BlockMode::ECB)
.Padding(PaddingMode::NONE)));
- for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) {
+ for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
auto cipher_params =
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
@@ -4597,71 +4590,22 @@
string encrypted_message;
auto rc = Finish(plain_message, &encrypted_message);
- if (rc == ErrorCode::OK) {
- EXPECT_EQ(plain_message.size(), encrypted_message.size())
- << "Encrypt finish returned OK, but did not consume all of the given input";
- } else {
- EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
- << "Encrypt finish failed in an unexpected way when given a large input";
- continue;
- }
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), encrypted_message.size())
+ << "Encrypt finish returned OK, but did not consume all of the given input";
cipher_params.push_back(out_params);
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
string decrypted_message;
rc = Finish(encrypted_message, &decrypted_message);
-
- if (rc == ErrorCode::OK) {
- EXPECT_EQ(plain_message.size(), decrypted_message.size())
- << "Decrypt finish returned OK, did not consume all of the given input";
- } else {
- EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
- << "Encrypt finish failed in an unexpected way when given a large input";
- }
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), decrypted_message.size())
+ << "Decrypt finish returned OK, did not consume all of the given input";
}
-
- CheckedDeleteKey();
}
-static const auto kKeymasterDeviceChoices =
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor));
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ImportWrappedKeyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, TransportLimitTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest);
} // namespace test
} // namespace V4_0
diff --git a/keymaster/4.1/IKeymasterDevice.hal b/keymaster/4.1/IKeymasterDevice.hal
index 64d2c9f..1456abe 100644
--- a/keymaster/4.1/IKeymasterDevice.hal
+++ b/keymaster/4.1/IKeymasterDevice.hal
@@ -22,6 +22,8 @@
import @4.0::KeyParameter;
import @4.0::KeyPurpose;
import @4.0::OperationHandle;
+import @4.0::VerificationToken;
+
import IOperation;
/**
@@ -31,6 +33,11 @@
* - Device-unique attestaion;
* - Early boot only keys;
* - Better cleanup of operations when clients die without completing or aborting them.
+ *
+ * @4.1::IKeymasterDevice::attestKey() must produce attestations with keymasterVersion 41. An
+ * oversight in the original numbering left no room for minor versions, so starting with 4.1 the
+ * versions will be numbered as major_version * 10 + minor version. The addition of new attestable
+ * tags changes the attestation format again, slightly, so the attestationVersion must be 4.
*/
interface IKeymasterDevice extends @4.0::IKeymasterDevice {
/**
@@ -42,10 +49,28 @@
* set to true the sufficiently-recent authentication token must indicate that the user
* authenticated with a password, not a biometric.
*
+ * Note that the IKeymasterDevice UNLOCKED_DEVICE_REQUIRED semantics are slightly different from
+ * the UNLOCKED_DEVICE_REQUIRED semantics enforced by keystore. Keystore handles device locking
+ * on a per-user basis. Because auth tokens do not contain an Android user ID, it's not
+ * possible to replicate the keystore enformcement logic in IKeymasterDevice. So from the
+ * IKeymasterDevice perspective, any user unlock unlocks all UNLOCKED_DEVICE_REQUIRED keys.
+ * Keystore will continue enforcing the per-user device locking.
+ *
* @param passwordOnly specifies whether the device must be unlocked with a password, rather
* than a biometric, before UNLOCKED_DEVICE_REQUIRED keys can be used.
+ *
+ * @param verificationToken is used by StrongBox implementations of IKeymasterDevice. It
+ * provides the StrongBox IKeymasterDevice with a fresh, MACed timestamp which it can use as the
+ * device-lock time, for future comparison against auth tokens when operations using
+ * UNLOCKED_DEVICE_REQUIRED keys are attempted. Unless the auth token timestamp is newer than
+ * the timestamp in the verificationToken, the device is still considered to be locked.
+ * Crucially, if a StrongBox IKeymasterDevice receives a deviceLocked() call with a verification
+ * token timestamp that is less than the timestamp in the last deviceLocked() call, it must
+ * ignore the new timestamp. TEE IKeymasterDevice implementations will receive an empty
+ * verificationToken (zero values and empty vectors) and should use their own clock as the
+ * device-lock time.
*/
- deviceLocked(bool passwordOnly) generates (ErrorCode error);
+ deviceLocked(bool passwordOnly, VerificationToken verificationToken) generates (ErrorCode error);
/**
* Called by client to notify the IKeymasterDevice that the device has left the early boot
diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp
index b06878b..27297b9 100644
--- a/keymaster/4.1/default/Android.bp
+++ b/keymaster/4.1/default/Android.bp
@@ -31,6 +31,7 @@
"libhidlbase",
"libkeymaster4",
"libkeymaster41",
+ "libkeymaster4_1support",
"liblog",
"libutils",
],
diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp
index 34b6108..bdd0ca8 100644
--- a/keymaster/4.1/support/Android.bp
+++ b/keymaster/4.1/support/Android.bp
@@ -22,11 +22,25 @@
"-Wextra",
"-Werror",
],
+ srcs: [
+ "attestation_record.cpp",
+ "Keymaster.cpp",
+ "Keymaster3.cpp",
+ "Keymaster4.cpp",
+ ],
export_include_dirs: ["include"],
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
"android.hardware.keymaster@4.1",
+ "libbase",
+ "libcrypto",
+ "libhidlbase",
"libkeymaster4support",
- ]
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.keymaster@4.1",
+ "libkeymaster4support",
+ ],
}
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.1/support/Keymaster.cpp
similarity index 85%
rename from keymaster/4.0/support/Keymaster.cpp
rename to keymaster/4.1/support/Keymaster.cpp
index f20f951..ea6604e 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.1/support/Keymaster.cpp
@@ -14,19 +14,18 @@
** limitations under the License.
*/
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <iomanip>
#include <android-base/logging.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <keymasterV4_0/Keymaster3.h>
-#include <keymasterV4_0/Keymaster4.h>
#include <keymasterV4_0/key_param_output.h>
#include <keymasterV4_0/keymaster_utils.h>
+#include <keymasterV4_1/Keymaster3.h>
+#include <keymasterV4_1/Keymaster4.h>
-namespace android {
-namespace hardware {
+namespace android::hardware {
template <class T>
std::ostream& operator<<(std::ostream& os, const hidl_vec<T>& vec) {
@@ -57,6 +56,7 @@
}
namespace keymaster {
+
namespace V4_0 {
std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) {
@@ -66,7 +66,9 @@
return os;
}
-namespace support {
+} // namespace V4_0
+
+namespace V4_1::support {
using ::android::sp;
using ::android::hidl::manager::V1_2::IServiceManager;
@@ -140,14 +142,14 @@
}
static hidl_vec<HmacSharingParameters> getHmacParameters(
- const Keymaster::KeymasterSet& keymasters) {
+ const Keymaster::KeymasterSet& keymasters) {
std::vector<HmacSharingParameters> params_vec;
params_vec.reserve(keymasters.size());
for (auto& keymaster : keymasters) {
if (keymaster->halVersion().majorVersion < 4) continue;
auto rc = keymaster->getHmacSharingParameters([&](auto error, auto& params) {
- CHECK(error == ErrorCode::OK)
- << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
+ CHECK(error == V4_0::ErrorCode::OK)
+ << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
params_vec.push_back(params);
});
CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
@@ -169,18 +171,18 @@
if (keymaster->halVersion().majorVersion < 4) continue;
LOG(DEBUG) << "Computing HMAC for " << *keymaster;
auto rc = keymaster->computeSharedHmac(
- params, [&](ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
- CHECK(error == ErrorCode::OK)
- << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
- if (firstKeymaster) {
- sharingCheck = curSharingCheck;
- firstKeymaster = false;
- }
- if (curSharingCheck != sharingCheck)
- LOG(WARNING) << "HMAC computation failed for " << *keymaster //
- << " Expected: " << sharingCheck //
- << " got: " << curSharingCheck;
- });
+ params, [&](V4_0::ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
+ CHECK(error == V4_0::ErrorCode::OK) << "Failed to get HMAC parameters from "
+ << *keymaster << " error " << error;
+ if (firstKeymaster) {
+ sharingCheck = curSharingCheck;
+ firstKeymaster = false;
+ }
+ if (curSharingCheck != sharingCheck)
+ LOG(WARNING) << "HMAC computation failed for " << *keymaster //
+ << " Expected: " << sharingCheck //
+ << " got: " << curSharingCheck;
+ });
CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
<< " error: " << rc.description();
}
@@ -190,8 +192,6 @@
computeHmac(keymasters, getHmacParameters(keymasters));
}
-} // namespace support
-} // namespace V4_0
+} // namespace V4_1::support
} // namespace keymaster
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.1/support/Keymaster3.cpp
similarity index 81%
rename from keymaster/4.0/support/Keymaster3.cpp
rename to keymaster/4.1/support/Keymaster3.cpp
index b2cdbd9..b665689 100644
--- a/keymaster/4.0/support/Keymaster3.cpp
+++ b/keymaster/4.1/support/Keymaster3.cpp
@@ -15,23 +15,19 @@
** limitations under the License.
*/
-#include <keymasterV4_0/Keymaster3.h>
+#include <keymasterV4_1/Keymaster3.h>
#include <android-base/logging.h>
#include <keymasterV4_0/keymaster_utils.h>
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+namespace android::hardware::keymaster::V4_1::support {
using android::hardware::details::StatusOf;
namespace {
-ErrorCode convert(V3_0::ErrorCode error) {
- return static_cast<ErrorCode>(error);
+V4_0::ErrorCode convert(V3_0::ErrorCode error) {
+ return static_cast<V4_0::ErrorCode>(error);
}
V3_0::KeyPurpose convert(KeyPurpose purpose) {
@@ -53,7 +49,7 @@
KeyParameter convert(const V3_0::KeyParameter& param) {
KeyParameter converted;
- converted.tag = static_cast<Tag>(param.tag);
+ converted.tag = static_cast<V4_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;
@@ -89,7 +85,7 @@
converted[i] = convert(params[i]);
}
converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
- converted[params.size()].blob = authToken2HidlVec(authToken);
+ converted[params.size()].blob = V4_0::support::authToken2HidlVec(authToken);
return converted;
}
@@ -107,16 +103,19 @@
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) {
- version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */,
- isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
- supportsEllipticCurve};
- supportsSymmetricCryptography_ = supportsSymmetricCryptography;
- supportsAttestation_ = supportsAttestation;
- supportsAllDigests_ = supportsAllDigests;
- });
+ [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
+ bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
+ const hidl_string& keymasterAuthorName) {
+ version_ = {keymasterName,
+ keymasterAuthorName,
+ 0 /* major version, filled below */,
+ 0 /* minor version */,
+ isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+ supportsEllipticCurve};
+ supportsSymmetricCryptography_ = supportsSymmetricCryptography;
+ supportsAttestation_ = supportsAttestation;
+ supportsAllDigests_ = supportsAllDigests;
+ });
CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
@@ -139,10 +138,10 @@
return Void();
}
-Return<ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
+Return<V4_0::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 StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
}
return convert(rc);
}
@@ -215,21 +214,21 @@
return rc;
}
-Return<ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+Return<V4_0::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);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
-Return<ErrorCode> Keymaster3::deleteAllKeys() {
+Return<V4_0::ErrorCode> Keymaster3::deleteAllKeys() {
auto rc = km3_dev_->deleteAllKeys();
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
-Return<ErrorCode> Keymaster3::destroyAttestationIds() {
+Return<V4_0::ErrorCode> Keymaster3::destroyAttestationIds() {
auto rc = km3_dev_->destroyAttestationIds();
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
@@ -242,7 +241,7 @@
};
auto rc =
- km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
+ km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
rc.isOk(); // move ctor prereq
return rc;
}
@@ -256,8 +255,8 @@
_hidl_cb(convert(error), inputConsumed, convert(outParams), output);
};
- auto rc =
- km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb);
+ auto rc = km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+ cb);
rc.isOk(); // move ctor prereq
return rc;
}
@@ -278,14 +277,10 @@
return rc;
}
-Return<ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
+Return<V4_0::ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
auto rc = km3_dev_->abort(operationHandle);
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/Keymaster4.cpp b/keymaster/4.1/support/Keymaster4.cpp
new file mode 100644
index 0000000..33f4bb1
--- /dev/null
+++ b/keymaster/4.1/support/Keymaster4.cpp
@@ -0,0 +1,41 @@
+/*
+** 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_1/Keymaster4.h>
+
+#include <android-base/logging.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+void Keymaster4::getVersionIfNeeded() {
+ if (haveVersion_) return;
+
+ auto rc = km4_0_dev_->getHardwareInfo([&](SecurityLevel securityLevel,
+ const hidl_string& keymasterName,
+ const hidl_string& authorName) {
+ version_ = {keymasterName,
+ authorName,
+ 4 /* major version */,
+ static_cast<uint8_t>((km4_1_dev_) ? 1 : 0) /* minor version */,
+ securityLevel,
+ true /* supportsEc */};
+ haveVersion_ = true;
+ });
+
+ CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/OWNERS b/keymaster/4.1/support/OWNERS
new file mode 100644
index 0000000..a9efe66
--- /dev/null
+++ b/keymaster/4.1/support/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+swillden@google.com
+jbires@google.com
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
new file mode 100644
index 0000000..9eab1db
--- /dev/null
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_1/attestation_record.h>
+
+#include <android-base/logging.h>
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+#define AT __FILE__ ":" << __LINE__
+
+/*
+ * NOTE: The contents of this file are *extremely* similar to the contents of the V4_0 copy of the
+ * same support file. Unfortunately, small changes in the scheme mean that the schema types have to
+ * be distinct, which drives almost everything else to be different as well. In the next version we
+ * plan to abandon not just this openssl mechanism for parsing ASN.1, but ASN.1 entirely, so
+ * eventually all of this duplication can be removed.
+ */
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+struct stack_st_ASN1_TYPE_Delete {
+ void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+ void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+ void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+ ASN1_OCTET_STRING* verified_boot_key;
+ ASN1_BOOLEAN* device_locked;
+ ASN1_ENUMERATED* verified_boot_state;
+ ASN1_OCTET_STRING* verified_boot_hash;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+ ASN1_INTEGER_SET* purpose;
+ ASN1_INTEGER* algorithm;
+ ASN1_INTEGER* key_size;
+ ASN1_INTEGER_SET* digest;
+ ASN1_INTEGER_SET* padding;
+ ASN1_INTEGER* ec_curve;
+ ASN1_INTEGER* rsa_public_exponent;
+ ASN1_INTEGER* active_date_time;
+ ASN1_INTEGER* origination_expire_date_time;
+ ASN1_INTEGER* usage_expire_date_time;
+ ASN1_NULL* no_auth_required;
+ ASN1_INTEGER* user_auth_type;
+ ASN1_INTEGER* auth_timeout;
+ ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* all_applications;
+ ASN1_OCTET_STRING* application_id;
+ ASN1_INTEGER* creation_date_time;
+ ASN1_INTEGER* origin;
+ ASN1_NULL* rollback_resistance;
+ KM_ROOT_OF_TRUST* root_of_trust;
+ ASN1_INTEGER* os_version;
+ ASN1_INTEGER* os_patchlevel;
+ ASN1_OCTET_STRING* attestation_application_id;
+ ASN1_NULL* trusted_user_presence_required;
+ ASN1_NULL* trusted_confirmation_required;
+ ASN1_NULL* unlocked_device_required;
+ ASN1_INTEGER* vendor_patchlevel;
+ ASN1_INTEGER* boot_patchlevel;
+ ASN1_NULL* early_boot_only;
+ ASN1_NULL* device_unique_attestation;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+ TAG_ROLLBACK_RESISTANCE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+ TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+ TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+ TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+ TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+ TAG_CREATION_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
+ TAG_VENDOR_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
+ TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+ ASN1_INTEGER* attestation_version;
+ ASN1_ENUMERATED* attestation_security_level;
+ ASN1_INTEGER* keymaster_version;
+ ASN1_ENUMERATED* keymaster_security_level;
+ ASN1_OCTET_STRING* attestation_challenge;
+ KM_AUTH_LIST* software_enforced;
+ KM_AUTH_LIST* tee_enforced;
+ ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <V4_0::Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+ auth_list->push_back(
+ ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+ }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+ BIGNUM* value = BN_new();
+ BIGNUM_Ptr one(BN_new());
+ BN_one(one.get());
+ BN_lshift(value, one.get(), 32);
+ return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+ static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+ "This implementation only supports 32 and 64-bit BN_ULONG");
+ if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+ BIGNUM_Ptr uint_max(construct_uint_max());
+ BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+ BN_CTX_Ptr ctx(BN_CTX_new());
+ BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+ return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+ } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+ return BN_get_word(num);
+ } else {
+ return 0;
+ }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_null) return;
+ auth_list->push_back(ttag);
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_string) return;
+ hidl_vec<uint8_t> buf;
+ buf.setToExternal(asn1_string->data, asn1_string->length);
+ auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+ if (!record) return ErrorCode::OK;
+
+ copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+ copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+ copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+ copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+ copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+ copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+ copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+ copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+ copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+ copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+ copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+ copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+ copyAuthTag(record->padding, TAG_PADDING, auth_list);
+ copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+ copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+ copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+ copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+ copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+ copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+ copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
+ copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
+ auth_list);
+ copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
+ auth_list);
+ copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
+ copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+ copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+
+ return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert) {
+ const uint8_t* p = cert.data();
+ X509_Ptr x509(d2i_X509(nullptr, &p, cert.size()));
+
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ if (!oid.get()) {
+ LOG(ERROR) << "Error parsing OID";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ int location = X509_get_ext_by_OBJ(x509.get(), oid.get(), -1 /* search from beginning */);
+ if (location == -1) {
+ LOG(ERROR) << "Attestation extension not found in certificate";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(x509.get(), location);
+ if (!attest_rec_ext) {
+ LOG(ERROR) << "Found extension but couldn't retrieve it. Probably BoringSSL bug.";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ if (!attest_rec_ext) {
+ LOG(ERROR) << "Attestation extension contained no data";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ p = attest_rec->data;
+ KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
+ if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
+
+ AttestationRecord result;
+
+ result.attestation_version = ASN1_INTEGER_get(record->attestation_version);
+ result.attestation_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+ result.keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+ result.keymaster_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+ auto& chall = record->attestation_challenge;
+ result.attestation_challenge.resize(chall->length);
+ memcpy(result.attestation_challenge.data(), chall->data, chall->length);
+ auto& uid = record->unique_id;
+ result.unique_id.resize(uid->length);
+ memcpy(result.unique_id.data(), uid->data, uid->length);
+
+ ErrorCode error = extract_auth_list(record->software_enforced, &result.software_enforced);
+ if (error != ErrorCode::OK) return {error, {}};
+
+ error = extract_auth_list(record->tee_enforced, &result.hardware_enforced);
+ if (error != ErrorCode::OK) return {error, {}};
+
+ KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+ root_of_trust = record->tee_enforced->root_of_trust;
+ } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+ root_of_trust = record->software_enforced->root_of_trust;
+ } else {
+ LOG(ERROR) << AT << " Failed root of trust parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+ if (!root_of_trust->verified_boot_key) {
+ LOG(ERROR) << AT << " Failed verified boot key parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+
+ RootOfTrust& rot = result.root_of_trust;
+ auto& vb_key = root_of_trust->verified_boot_key;
+ rot.verified_boot_key.resize(vb_key->length);
+ memcpy(rot.verified_boot_key.data(), vb_key->data, vb_key->length);
+
+ rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
+ ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
+ rot.device_locked = root_of_trust->device_locked;
+
+ auto& vb_hash = root_of_trust->verified_boot_hash;
+ if (!vb_hash) {
+ LOG(ERROR) << AT << " Failed verified boot hash parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+ rot.verified_boot_hash.resize(vb_hash->length);
+ memcpy(rot.verified_boot_hash.data(), vb_hash->data, vb_hash->length);
+
+ return {ErrorCode::OK, result};
+}
+
+} // namespace V4_1
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
similarity index 73%
rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
index ad83f17..1f49e18 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
@@ -15,28 +15,28 @@
** 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>
+#pragma once
#include <memory>
#include <vector>
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::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.
+ * Keymaster abstracts the underlying V4_1::IKeymasterDevice. There are two implementations,
+ * Keymaster3 which wraps a V3_0::IKeymasterDevice and Keymaster4, which wraps either a
+ * V4_0::IKeymasterDevice or a V4_1::IKeymasterDevice. There is a V3_0::IKeymasterDevice
+ * implementation that is used to wrap pre-HIDL keymaster implementations, and Keymaster3 will wrap
+ * that.
*
* 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.
+ * while still having to use only the latest interface. Plus it's a handy place to keep some
+ * convenience methods.
*/
class Keymaster : public IKeymasterDevice {
public:
@@ -50,12 +50,14 @@
hidl_string keymasterName;
hidl_string authorName;
uint8_t majorVersion;
+ uint8_t minorVersion;
SecurityLevel securityLevel;
bool supportsEc;
bool operator>(const VersionResult& other) const {
- auto lhs = std::tie(securityLevel, majorVersion, supportsEc);
- auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc);
+ auto lhs = std::tie(securityLevel, majorVersion, minorVersion, supportsEc);
+ auto rhs = std::tie(other.securityLevel, other.majorVersion, other.minorVersion,
+ other.supportsEc);
return lhs > rhs;
}
};
@@ -69,6 +71,9 @@
* There are no side effects otherwise.
*/
void logIfKeymasterVendorError(ErrorCode ec) const;
+ void logIfKeymasterVendorError(V4_0::ErrorCode ec) const {
+ logIfKeymasterVendorError(static_cast<ErrorCode>(ec));
+ }
/**
* Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
@@ -93,10 +98,4 @@
std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster);
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
similarity index 72%
rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
index c40be7c..c201e8c 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
@@ -1,5 +1,4 @@
/*
- **
** Copyright 2017, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,18 +14,14 @@
** limitations under the License.
*/
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+#pragma once
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
#include "Keymaster.h"
+#include "Operation.h"
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+namespace android::hardware::keymaster::V4_1::support {
using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
@@ -38,8 +33,10 @@
using ::android::hardware::details::return_status;
class Keymaster3 : public Keymaster {
- public:
+ public:
+ // This definition is used for device enumeration.
using WrappedIKeymasterDevice = IKeymaster3Device;
+
Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
: Keymaster(IKeymaster3Device::descriptor, instanceName),
km3_dev_(km3_dev),
@@ -53,24 +50,24 @@
Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
return Void();
}
Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
computeSharedHmac_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
return Void();
}
Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
const HardwareAuthToken&,
verifyAuthorization_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
return Void();
}
- Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+ Return<V4_0::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,
@@ -86,7 +83,7 @@
const hidl_vec<KeyParameter>& /* unwrappingParams */,
uint64_t /* passwordSid */, uint64_t /* biometricSid */,
importWrappedKey_cb _hidl_cb) {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}, {});
return Void();
}
@@ -99,9 +96,9 @@
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<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+ Return<V4_0::ErrorCode> deleteAllKeys() override;
+ Return<V4_0::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;
@@ -112,9 +109,31 @@
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;
+ Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override;
- private:
+ /**********************************
+ * V4_1::IKeymasterDevice methods *
+ *********************************/
+
+ Return<ErrorCode> deviceLocked(bool /* passwordOnly */,
+ const VerificationToken& /* verificationToken */) override {
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<ErrorCode> earlyBootEnded() override { return ErrorCode::UNIMPLEMENTED; }
+
+ Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ beginOp_cb _hidl_cb) override {
+ return begin(purpose, keyBlob, inParams, authToken,
+ [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+ new Operation(operationHandle));
+ });
+ }
+
+ private:
void getVersionIfNeeded();
sp<IKeymaster3Device> km3_dev_;
@@ -126,10 +145,4 @@
bool supportsAllDigests_;
};
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
new file mode 100644
index 0000000..6d74d98
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
@@ -0,0 +1,197 @@
+/*
+ ** Copyright 2020, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#pragma once
+
+#include "Keymaster.h"
+#include "Operation.h"
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using android::sp;
+
+/**
+ * This class can wrap either a V4_0 or V4_1 IKeymasterDevice.
+ */
+class Keymaster4 : public Keymaster {
+ public:
+ // This definition is used for device enumeration; enumerating 4.0 devices will also
+ // enumerate 4.1. devices.
+ using WrappedIKeymasterDevice = V4_0::IKeymasterDevice;
+
+ Keymaster4(sp<V4_1::IKeymasterDevice> km4_1_dev, const hidl_string& instanceName)
+ : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+ haveVersion_(false),
+ km4_0_dev_(km4_1_dev),
+ km4_1_dev_(km4_1_dev) {}
+
+ Keymaster4(sp<V4_0::IKeymasterDevice> km4_0_dev, const hidl_string& instanceName)
+ : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+ haveVersion_(false),
+ km4_0_dev_(km4_0_dev),
+ km4_1_dev_() {}
+
+ const VersionResult& halVersion() const override {
+ const_cast<Keymaster4*>(this)->getVersionIfNeeded();
+ return version_;
+ }
+
+ /**********************************
+ * V4_0::IKeymasterDevice methods *
+ *********************************/
+
+ Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
+ return km4_0_dev_->getHardwareInfo(_hidl_cb);
+ }
+
+ Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+ return km4_0_dev_->getHmacSharingParameters(_hidl_cb);
+ }
+
+ Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+ computeSharedHmac_cb _hidl_cb) override {
+ return km4_0_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 km4_0_dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
+ return km4_0_dev_->addRngEntropy(data);
+ }
+
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override {
+ return km4_0_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 km4_0_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 km4_0_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,
+ const hidl_vec<KeyParameter>& unwrappingParams,
+ uint64_t passwordSid, uint64_t biometricSid,
+ importWrappedKey_cb _hidl_cb) {
+ return km4_0_dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey,
+ unwrappingParams, passwordSid, biometricSid, _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 km4_0_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 km4_0_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 km4_0_dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
+ return km4_0_dev_->deleteKey(keyBlob);
+ }
+
+ Return<V4_0::ErrorCode> deleteAllKeys() override { return km4_0_dev_->deleteAllKeys(); }
+
+ Return<V4_0::ErrorCode> destroyAttestationIds() override {
+ return km4_0_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 km4_0_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 km4_0_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 km4_0_dev_->finish(operationHandle, inParams, input, signature, authToken,
+ verificationToken, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override {
+ return km4_0_dev_->abort(operationHandle);
+ }
+
+ /**********************************
+ * V4_1::IKeymasterDevice methods *
+ *********************************/
+
+ Return<ErrorCode> deviceLocked(bool passwordOnly,
+ const VerificationToken& verificationToken) override {
+ if (km4_1_dev_) return km4_1_dev_->deviceLocked(passwordOnly, verificationToken);
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<ErrorCode> earlyBootEnded() override {
+ if (km4_1_dev_) return km4_1_dev_->earlyBootEnded();
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ beginOp_cb _hidl_cb) override {
+ if (km4_1_dev_) return km4_1_dev_->beginOp(purpose, keyBlob, inParams, authToken, _hidl_cb);
+
+ return km4_0_dev_->begin(
+ purpose, keyBlob, inParams, authToken,
+ [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+ new Operation(operationHandle));
+ });
+ }
+
+ private:
+ void getVersionIfNeeded();
+
+ bool haveVersion_;
+ VersionResult version_;
+ sp<V4_0::IKeymasterDevice> km4_0_dev_;
+ sp<V4_1::IKeymasterDevice> km4_1_dev_;
+}; // namespace android::hardware::keymaster::V4_1::support
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Operation.h b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
new file mode 100644
index 0000000..902d49a
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
@@ -0,0 +1,38 @@
+/*
+ ** Copyright 2020, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IOperation.h>
+
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+class Operation : public IOperation {
+ public:
+ Operation(OperationHandle handle) : handle_(handle) {}
+
+ Return<void> getOperationChallenge(getOperationChallenge_cb _hidl_cb) override {
+ _hidl_cb(V4_1::ErrorCode::OK, handle_);
+ return Void();
+ }
+
+ private:
+ OperationHandle handle_;
+};
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
new file mode 100644
index 0000000..b543bdd
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_0/attestation_record.h>
+#include <keymasterV4_0/openssl_utils.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+using V4_0::kAttestionRecordOid;
+using V4_0::keymaster_verified_boot_t;
+
+struct RootOfTrust {
+ SecurityLevel security_level;
+ hidl_vec<uint8_t> verified_boot_key;
+ hidl_vec<uint8_t> verified_boot_hash;
+ keymaster_verified_boot_t verified_boot_state;
+ bool device_locked;
+};
+
+struct AttestationRecord {
+ RootOfTrust root_of_trust;
+ uint32_t attestation_version;
+ SecurityLevel attestation_security_level;
+ uint32_t keymaster_version;
+ SecurityLevel keymaster_security_level;
+ hidl_vec<uint8_t> attestation_challenge;
+ AuthorizationSet software_enforced;
+ AuthorizationSet hardware_enforced;
+ hidl_vec<uint8_t> unique_id;
+};
+
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert);
+
+} // namespace V4_1
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
index afc0eaf..01605b7 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
-#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+#pragma once
#include <keymasterV4_0/authorization_set.h>
@@ -28,5 +27,3 @@
using V4_0::KeyParameter;
} // namespace android::hardware::keymaster::V4_1
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 6ffe8e1..c5ce950 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -23,16 +23,26 @@
namespace android::hardware::keymaster::V4_1 {
+using V4_0::Algorithm;
using V4_0::BlockMode;
using V4_0::Digest;
using V4_0::EcCurve;
-using V4_0::ErrorCode;
+using V4_0::HardwareAuthenticatorType;
using V4_0::HardwareAuthToken;
+using V4_0::HmacSharingParameters;
+using V4_0::KeyBlobUsageRequirements;
+using V4_0::KeyCharacteristics;
+using V4_0::KeyFormat;
+using V4_0::KeyOrigin;
using V4_0::KeyParameter;
+using V4_0::KeyPurpose;
+using V4_0::OperationHandle;
using V4_0::PaddingMode;
+using V4_0::SecurityLevel;
using V4_0::TagType;
using V4_0::VerificationToken;
+using V4_0::NullOr;
using V4_0::TypedTag;
using V4_0::TAG_ACTIVE_DATETIME;
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
new file mode 100644
index 0000000..2e28002
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using V4_0::support::blob2hidlVec;
+using V4_0::support::hidlVec2AuthToken;
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/types.hal b/keymaster/4.1/types.hal
index bdf1731..9e8b30e 100644
--- a/keymaster/4.1/types.hal
+++ b/keymaster/4.1/types.hal
@@ -26,17 +26,34 @@
* IKeymasterDevice::earlyBootEnded() is called.
*/
EARLY_BOOT_ONLY = TagType:BOOL | 305,
+
/**
* DEVICE_UNIQUE_ATTESTATION is an argument to IKeymasterDevice::attestKey(). It indicates that
- * attestation using a device-unique key is requested, rather than a batch key. Only
- * SecurityLevel::STRONGBOX IKeymasterDevices may support device-unique attestations.
- * SecurityLevel::TRUSTED_ENVIRONMENT IKeymasterDevices must return ErrorCode::INVALID_ARGUMENT
- * if they receive DEVICE_UNIQUE_ATTESTATION. SecurityLevel::STRONGBOX IKeymasterDevices need
- * not support DEVICE_UNIQUE_ATTESTATION, and return ErrorCode::CANNOT_ATTEST_IDS if they do not
- * support it.
+ * attestation using a device-unique key is requested, rather than a batch key. When a
+ * device-unique key is used, only the attestation certificate is returned; no additional
+ * chained certificates are provided. It's up to the caller to recognize the device-unique
+ * signing key. Only SecurityLevel::STRONGBOX IKeymasterDevices may support device-unique
+ * attestations. SecurityLevel::TRUSTED_ENVIRONMENT IKeymasterDevices must return
+ * ErrorCode::INVALID_ARGUMENT if they receive DEVICE_UNIQUE_ATTESTATION.
+ * SecurityLevel::STRONGBOX IKeymasterDevices need not support DEVICE_UNIQUE_ATTESTATION, and
+ * return ErrorCode::CANNOT_ATTEST_IDS if they do not support it.
*
* IKeymasterDevice implementations that support device-unique attestation MUST add the
* DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
*/
DEVICE_UNIQUE_ATTESTATION = TagType:BOOL | 720,
+
+ /**
+ * IDENTITY_CREDENTIAL_KEY is never used by IKeymasterDevice, is not a valid argument to key
+ * generation or any operation, is never returned by any method and is never used in a key
+ * attestation. It is used in attestations produced by the IIdentityCredential HAL when that
+ * HAL attests to Credential Keys. IIdentityCredential produces Keymaster-style attestations.
+ */
+ IDENTITY_CREDENTIAL_KEY = TagType:BOOL | 721,
+};
+
+enum ErrorCode : @4.0::ErrorCode {
+ EARLY_BOOT_ENDED = -73,
+ ATTESTATION_KEYS_NOT_PROVISIONED = -74,
+ ATTESTATION_IDS_NOT_PROVISIONED = -75,
};
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
index f5a0c9c..c2d7fa3 100644
--- a/keymaster/4.1/vts/functional/Android.bp
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -19,12 +19,24 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"EarlyBootKeyTest.cpp",
+ "DeviceUniqueAttestationTest.cpp",
+ "Keymaster4_1HidlTest.cpp",
+ "UnlockedDeviceRequiredTest.cpp",
],
static_libs: [
"android.hardware.keymaster@4.0",
"android.hardware.keymaster@4.1",
- "libkeymaster4support",
+ "libcrypto_static",
"libkeymaster4_1support",
+ "libkeymaster4support",
+ "libkeymaster4vtstest",
],
- test_suites: ["vts-core"],
+ cflags: [
+ "-Wall",
+ "-O0",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
new file mode 100644
index 0000000..7ea3275
--- /dev/null
+++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster4_1HidlTest.h"
+
+#include <cutils/properties.h>
+
+#include <openssl/x509.h>
+
+#include <keymasterV4_1/attestation_record.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_0 {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+ return std::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+} // namespace android::hardware::keymaster::V4_0
+
+namespace android::hardware::keymaster::V4_1 {
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+ return os << toString(tag);
+}
+
+namespace test {
+
+using std::string;
+using std::tuple;
+
+namespace {
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+string bin2hex(const hidl_vec<uint8_t>& data) {
+ string retval;
+ retval.reserve(data.size() * 2 + 1);
+ for (uint8_t byte : data) {
+ retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+ retval.push_back(nibble2hex[0x0F & byte]);
+ }
+ return retval;
+}
+
+struct AuthorizationSetDifferences {
+ string aName;
+ string bName;
+ AuthorizationSet aWhackB;
+ AuthorizationSet bWhackA;
+};
+
+std::ostream& operator<<(std::ostream& o, const AuthorizationSetDifferences& diffs) {
+ if (!diffs.aWhackB.empty()) {
+ o << "Set " << diffs.aName << " contains the following that " << diffs.bName << " does not"
+ << diffs.aWhackB;
+ if (!diffs.bWhackA.empty()) o << std::endl;
+ }
+
+ if (!diffs.bWhackA.empty()) {
+ o << "Set " << diffs.bName << " contains the following that " << diffs.aName << " does not"
+ << diffs.bWhackA;
+ }
+ return o;
+}
+
+// Computes and returns a \ b and b \ a ('\' is the set-difference operator, a \ b means all the
+// elements that are in a but not b, i.e. take a and whack all the elements in b) to the provided
+// stream. The sets must be sorted.
+//
+// This provides a simple and clear view of how the two sets differ, generally much
+// easier than scrutinizing printouts of the two sets.
+AuthorizationSetDifferences difference(string aName, const AuthorizationSet& a, string bName,
+ const AuthorizationSet& b) {
+ AuthorizationSetDifferences diffs = {std::move(aName), std::move(bName), {}, {}};
+ std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(diffs.aWhackB));
+ std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::back_inserter(diffs.bWhackA));
+ return diffs;
+}
+
+#define DIFFERENCE(a, b) difference(#a, a, #b, b)
+
+void check_root_of_trust(const RootOfTrust& root_of_trust) {
+ char vb_meta_device_state[PROPERTY_VALUE_MAX];
+ if (property_get("ro.boot.vbmeta.device_state", vb_meta_device_state, "") == 0) return;
+
+ char vb_meta_digest[PROPERTY_VALUE_MAX];
+ EXPECT_GT(property_get("ro.boot.vbmeta.digest", vb_meta_digest, ""), 0);
+ EXPECT_EQ(vb_meta_digest, bin2hex(root_of_trust.verified_boot_hash));
+
+ // Verified boot key should be all 0's if the boot state is not verified or self signed
+ HidlBuf empty_boot_key(string(32, '\0'));
+
+ char vb_meta_bootstate[PROPERTY_VALUE_MAX];
+ auto& verified_boot_key = root_of_trust.verified_boot_key;
+ auto& verified_boot_state = root_of_trust.verified_boot_state;
+ EXPECT_GT(property_get("ro.boot.verifiedbootstate", vb_meta_bootstate, ""), 0);
+ if (!strcmp(vb_meta_bootstate, "green")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_VERIFIED);
+ EXPECT_NE(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "yellow")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_SELF_SIGNED);
+ EXPECT_NE(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "orange")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_EQ(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "red")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_FAILED);
+ } else {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_EQ(verified_boot_key, empty_boot_key);
+ }
+}
+
+void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge,
+ AuthorizationSet expected_sw_enforced,
+ AuthorizationSet expected_hw_enforced,
+ SecurityLevel expected_security_level) {
+ EXPECT_EQ(41U, attestation.keymaster_version);
+ EXPECT_EQ(4U, attestation.attestation_version);
+ EXPECT_EQ(expected_security_level, attestation.attestation_security_level);
+ EXPECT_EQ(expected_security_level, attestation.keymaster_security_level);
+ EXPECT_EQ(challenge, attestation.attestation_challenge);
+
+ check_root_of_trust(attestation.root_of_trust);
+
+ // Sort all of the authorization lists, so that equality matching works.
+ expected_sw_enforced.Sort();
+ expected_hw_enforced.Sort();
+ attestation.software_enforced.Sort();
+ attestation.hardware_enforced.Sort();
+
+ EXPECT_EQ(expected_sw_enforced, attestation.software_enforced)
+ << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
+ EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced)
+ << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
+}
+
+} // namespace
+
+using std::string;
+using DeviceUniqueAttestationTest = Keymaster4_1HidlTest;
+
+TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+ convert(AttestKey(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain)));
+ CheckedDeleteKey();
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+ convert(AttestKey(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain)));
+}
+
+TEST_P(DeviceUniqueAttestationTest, Rsa) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK,
+ convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_CREATION_DATETIME, 1))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ EXPECT_EQ(ErrorCode::OK,
+ convert(AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ &cert_chain)));
+
+ EXPECT_EQ(1U, cert_chain.size());
+ auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+ EXPECT_EQ(ErrorCode::OK, err);
+
+ check_attestation_record(attestation, challenge,
+ /* sw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_CREATION_DATETIME, 1)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ /* hw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+ SecLevel());
+}
+
+TEST_P(DeviceUniqueAttestationTest, Ecdsa) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK,
+ convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_CREATION_DATETIME, 1))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ EXPECT_EQ(ErrorCode::OK,
+ convert(AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ &cert_chain)));
+
+ EXPECT_EQ(1U, cert_chain.size());
+ auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+ EXPECT_EQ(ErrorCode::OK, err);
+
+ check_attestation_record(attestation, challenge,
+ /* sw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_CREATION_DATETIME, 1)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ /* hw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+ SecLevel());
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
+
+} // namespace test
+} // namespace android::hardware::keymaster::V4_1
diff --git a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
index 4a19010..a26c688 100644
--- a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
+++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
@@ -14,8 +14,78 @@
* limitations under the License.
*/
+#include "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
namespace android::hardware::keymaster::V4_1::test {
-// TODO(swillden): Put tests here.
+using std::string;
+
+using EarlyBootKeyTest = Keymaster4_1HidlTest;
+
+// Because VTS tests are run on fully-booted machines, we can only run negative tests for early boot
+// keys, which cannot be created or used after /data is mounted. This is the only test we can run
+// in the normal case. The positive test will have to be done by the Android system, when it
+// creates/uses early boot keys during boot. It should fail to boot if the early boot key usage
+// fails.
+TEST_P(EarlyBootKeyTest, CannotCreateEarlyBootKeys) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+// This is a more comprenhensive test, but it can only be run on a machine which is still in early
+// boot stage, which no proper Android device is by the time we can run VTS. To use this,
+// un-disable it and modify vold to remove the call to earlyBootEnded(). Running the test will end
+// early boot, so you'll have to reboot between runs.
+TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {
+ // Should be able to create keys, since early boot has not ended
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+
+ // TAG_EARLY_BOOT_ONLY should be in hw-enforced.
+ EXPECT_TRUE(contains(aesKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(hmacKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(rsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(ecdsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+
+ // Should be able to use keys, since early boot has not ended
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ // End early boot
+ Return<ErrorCode> earlyBootResult = keymaster().earlyBootEnded();
+ EXPECT_TRUE(earlyBootResult.isOk());
+ EXPECT_EQ(earlyBootResult, ErrorCode::OK);
+
+ // Should not be able to use already-created keys.
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+
+ // Should not be able to create new keys
+ std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(EarlyBootKeyTest);
} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
new file mode 100644
index 0000000..efedf28
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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 "Keymaster4_1HidlTest.h"
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using std::string;
+
+void Keymaster4_1HidlTest::SetUp() {
+ keymaster41_ = IKeymasterDevice::getService(GetParam());
+ InitializeKeymaster(keymaster41_);
+}
+
+auto Keymaster4_1HidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation,
+ const string& message, const AuthorizationSet& in_params)
+ -> std::tuple<ErrorCode, string, AuthorizationSet /* out_params */> {
+ AuthorizationSet begin_out_params;
+ V4_0::ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_);
+ AuthorizationSet out_params(std::move(begin_out_params));
+ if (result != V4_0::ErrorCode::OK) {
+ return {convert(result), {}, out_params};
+ }
+
+ string output;
+ size_t consumed = 0;
+ AuthorizationSet update_params;
+ AuthorizationSet update_out_params;
+ result = Update(op_handle_, update_params, message, &update_out_params, &output, &consumed);
+ out_params.push_back(update_out_params);
+ if (result != V4_0::ErrorCode::OK) {
+ return {convert(result), output, out_params};
+ }
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ result = Finish(op_handle_, finish_params, message.substr(consumed), unused, &finish_out_params,
+ &output);
+ op_handle_ = V4_0::test::kOpHandleSentinel;
+ out_params.push_back(finish_out_params);
+
+ return {convert(result), output, out_params};
+}
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
new file mode 100644
index 0000000..6332c43
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+
+#include <KeymasterHidlTest.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using V4_0::test::HidlBuf;
+
+class Keymaster4_1HidlTest : public V4_0::test::KeymasterHidlTest {
+ public:
+ using super = V4_0::test::KeymasterHidlTest;
+
+ ErrorCode convert(V4_0::ErrorCode error_code) { return static_cast<ErrorCode>(error_code); }
+
+ // These methods hide the base class versions.
+ void SetUp();
+ IKeymasterDevice& keymaster() { return *keymaster41_; };
+
+ struct KeyData {
+ HidlBuf blob;
+ KeyCharacteristics characteristics;
+ };
+
+ std::tuple<ErrorCode, KeyData> GenerateKeyData(const AuthorizationSet& keyDescription) {
+ KeyData keyData;
+ ErrorCode errorCode = convert(
+ super::GenerateKey(keyDescription, &keyData.blob, &keyData.characteristics));
+ return {errorCode, keyData};
+ }
+
+ void CheckedDeleteKeyData(KeyData* keyData) { CheckedDeleteKey(&keyData->blob); }
+
+ template <typename TagType>
+ std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
+ KeyData /* ecdsaKey */>
+ CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
+ ErrorCode errorCode;
+
+ /* AES */
+ KeyData aesKeyData;
+ std::tie(errorCode, aesKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(tagToTest)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* HMAC */
+ KeyData hmacKeyData;
+ std::tie(errorCode, hmacKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* RSA */
+ KeyData rsaKeyData;
+ std::tie(errorCode, rsaKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(tagToTest)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* ECDSA */
+ KeyData ecdsaKeyData;
+ std::tie(errorCode, ecdsaKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .EcdsaSigningKey(256)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
+ }
+
+ std::tuple<ErrorCode, std::string /* processedMessage */, AuthorizationSet /* out_params */>
+ ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const std::string& message,
+ const AuthorizationSet& in_params);
+
+ ErrorCode UseAesKey(const HidlBuf& aesKeyBlob) {
+ auto [result, ciphertext, out_params] = ProcessMessage(
+ aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE));
+ return result;
+ }
+
+ ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) {
+ auto [result, mac, out_params] =
+ ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456",
+ AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128));
+ return result;
+ }
+
+ ErrorCode UseRsaKey(const HidlBuf& rsaKeyBlob) {
+ std::string message(2048 / 8, 'a');
+ auto [result, signature, out_params] = ProcessMessage(
+ rsaKeyBlob, KeyPurpose::SIGN, message,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+ return result;
+ }
+
+ ErrorCode UseEcdsaKey(const HidlBuf& ecdsaKeyBlob) {
+ auto [result, signature, out_params] =
+ ProcessMessage(ecdsaKeyBlob, KeyPurpose::SIGN, "a",
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+ return result;
+ }
+
+ static std::vector<std::string> build_params() {
+ auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ return params;
+ }
+
+ private:
+ sp<IKeymasterDevice> keymaster41_;
+};
+
+template <typename TypedTag>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag typedTag) {
+ return std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+ return param.tag == static_cast<V4_0::Tag>(typedTag);
+ }) != set.end();
+}
+
+#define INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
+ testing::ValuesIn(Keymaster4_1HidlTest::build_params()), \
+ android::hardware::PrintInstanceNameToString)
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
new file mode 100644
index 0000000..671bbbf
--- /dev/null
+++ b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 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 "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using UnlockedDeviceRequiredTest = Keymaster4_1HidlTest;
+
+// This may be a problematic test. It can't be run repeatedly without unlocking the device in
+// between runs... and on most test devices there are no enrolled credentials so it can't be
+// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning
+// device is to reboot it. For that reason, this is disabled by default. It can be used as part of
+// a manual test process, which includes unlocking between runs, which is why it's included here.
+// Well, that and the fact that it's the only test we can do without also making calls into the
+// Gatekeeper HAL. We haven't written any cross-HAL tests, and don't know what all of the
+// implications might be, so that may or may not be a solution.
+//
+// TODO(swillden): Use the Gatekeeper HAL to enroll some test credentials which we can verify to get
+// an unlock auth token. If that works, enable the improved test.
+TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
+
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ Return<ErrorCode> rc =
+ keymaster().deviceLocked(false /* passwordOnly */, {} /* verificationToken */);
+ ASSERT_TRUE(rc.isOk());
+ ASSERT_EQ(ErrorCode::OK, static_cast<ErrorCode>(rc));
+
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(UnlockedDeviceRequiredTest);
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index 9afd778..8dc41f7 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -48,9 +48,14 @@
/**
* Gets the supported operations in a model.
*
- * getSupportedOperations indicates which operations of a model are fully
- * supported by the vendor driver. If an operation may not be supported for
- * any reason, getSupportedOperations must return false for that operation.
+ * getSupportedOperations indicates which operations of the top-level
+ * subgraph are fully supported by the vendor driver. If an operation may
+ * not be supported for any reason, getSupportedOperations must return
+ * false for that operation.
+ *
+ * The {@link OperationType::IF} and {@link OperationType::WHILE}
+ * operations may only be fully supported if the vendor driver fully
+ * supports all operations in the referenced subgraphs.
*
* @param model A model whose operations--and their corresponding operands--
* are to be verified by the driver.
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 6c8fe43..a6d274a 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -17,9 +17,10 @@
package android.hardware.neuralnetworks@1.3;
import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
import @1.0::PerformanceInfo;
import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
import @1.2::OperandType;
import @1.2::OperationType;
import @1.2::SymmPerChannelQuantParams;
@@ -40,6 +41,13 @@
*/
TENSOR_QUANT8_ASYMM_SIGNED = 14,
+ /**
+ * A reference to a subgraph.
+ *
+ * Must have the lifetime {@link OperandLifeTime::SUBGRAPH}.
+ */
+ SUBGRAPH = 15,
+
/*
* DEPRECATED. Since HAL version 1.2, extensions are the preferred
* alternative to OEM operation and data types.
@@ -68,7 +76,7 @@
enum OperandTypeRange : uint32_t {
BASE_MIN = 0,
FUNDAMENTAL_MIN = 0,
- FUNDAMENTAL_MAX = 14,
+ FUNDAMENTAL_MAX = 15,
OEM_MIN = 10000,
OEM_MAX = 10001,
BASE_MAX = 0xFFFF,
@@ -4877,6 +4885,92 @@
QUANTIZED_LSTM = 95,
/**
+ * Executes one of the two referenced subgraphs as determined by a boolean
+ * value.
+ *
+ * The inputs and outputs of the two referenced subgraphs must agree with the
+ * signature of this operation. That is, if the operation has (3 + n) inputs
+ * and m outputs, both subgraphs must have n inputs and m outputs with the same
+ * types as the corresponding operation inputs and outputs.
+ *
+ * Inputs:
+ * * 0: A value of type {@link OperandType::TENSOR_BOOL8} and shape [1]
+ * that determines which of the two referenced subgraphs to execute.
+ * * 1: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+ * executed if the condition is true.
+ * * 2: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+ * executed if the condition is false.
+ * * 3 ~ (n + 2): Inputs to be passed to the subgraph selected for execution.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the selected subgraph.
+ */
+ IF = 96,
+
+ /**
+ * Executes the body subgraph until the condition subgraph outputs false.
+ *
+ * The inputs to this operation are the condition subgraph, the body subgraph,
+ * and operand values for the first iteration of the loop. The values are
+ * implicitly split into three groups of input-output, state-only, and
+ * input-only values, as described below.
+ *
+ * The outputs of this operation are the final values of input-output
+ * operands.
+ *
+ * Both the condition and body subgraph receive (m + k + n) inputs.
+ * * The first m (m >= 1) inputs are input-output operands. For the first
+ * iteration, these are initialized from the corresponding inputs of the
+ * WHILE operation. In subsequent iterations, their values come from the
+ * corresponding outputs of the body subgraph produced during the previous
+ * iteration.
+ * * The next k (k >= 0) inputs are state-only operands. They are similar to
+ * the input-output operands, except that their values are no longer
+ * available after the loop terminates.
+ * * The last n (n >= 0) inputs are input-only operands. Their values come
+ * from the corresponding inputs of the WHILE operation.
+ *
+ * The body subgraph produces (m + k) outputs.
+ * * The first m outputs are input-output operands. They become the outputs
+ * of the WHILE operation when a termination condition is reached.
+ * * The last k outputs are state-only operands. Their values are no longer
+ * available after the loop terminates.
+ *
+ * The numbers m, k, and n are inferred by the driver as follows:
+ * m = (WHILE operation output count)
+ * k = (body subgraph output count) - m
+ * n = (body subgraph input count) - m - k
+ *
+ * The pseudo-code below illustrates the flow of a WHILE operation with
+ * inputs condition, body, initial_input_output, initial_state, input_only
+ * (m = 1, k = 1, n = 1):
+ *
+ * input_output = initial_input_output
+ * state = initial_state
+ * while condition(input_output, state, input_only):
+ * input_output, state = body(input_output, state, input_only)
+ * return input_output
+ *
+ * Inputs:
+ * * 0: A {@link OperandType::SUBGRAPH} reference to the condition
+ * subgraph. The subgraph must have (m + k + n) inputs with
+ * the same types as the corresponding inputs of the WHILE operation
+ * and exactly one output of {@link OperandType::TENSOR_BOOL8}
+ * and shape [1].
+ * * 1: A {@link OperandType::SUBGRAPH} reference to the body subgraph.
+ * The subgraph must have (m + k + n) inputs and (m + k) outputs with
+ * the same types as the corresponding inputs and outputs of the WHILE
+ * operation.
+ * * (m inputs): Initial values for input-output operands.
+ * * (k inputs): Initial values for state-only operands.
+ * * (n inputs): Values for input-only operands.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the loop.
+ */
+ WHILE = 97,
+
+ /**
* DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
* OEM operation and data types.
*
@@ -4898,13 +4992,12 @@
enum OperationTypeRange : uint32_t {
BASE_MIN = 0,
FUNDAMENTAL_MIN = 0,
- FUNDAMENTAL_MAX = 95,
+ FUNDAMENTAL_MAX = 97,
OEM_MIN = 10000,
OEM_MAX = 10000,
BASE_MAX = 0xFFFF,
};
-
/**
* The capabilities of a driver.
*
@@ -4966,6 +5059,59 @@
};
/**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+ /**
+ * The operand is internal to the model. It's created by an operation and
+ * consumed by other operations. It must be an output operand of
+ * exactly one operation.
+ */
+ TEMPORARY_VARIABLE,
+
+ /**
+ * The operand is an input of a subgraph. It must not be an output
+ * operand of any operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_INPUT,
+
+ /**
+ * The operand is an output of a subgraph. It must be an output
+ * operand of exactly one operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_OUTPUT,
+
+ /**
+ * The operand is a constant found in Model.operandValues. It must
+ * not be an output operand of any operation.
+ */
+ CONSTANT_COPY,
+
+ /**
+ * The operand is a constant that was specified via a Memory
+ * object. It must not be an output operand of any operation.
+ */
+ CONSTANT_REFERENCE,
+
+ /**
+ * The operand does not have a value. This is valid only for optional
+ * arguments of operations.
+ */
+ NO_VALUE,
+
+ /**
+ * The operand is a reference to a subgraph. It must be an input to one
+ * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+ * operations.
+ */
+ SUBGRAPH,
+};
+
+/**
* Describes one operand of the model's graph.
*/
struct Operand {
@@ -5001,7 +5147,7 @@
* . The operand has lifetime CONSTANT_COPY or
* CONSTANT_REFERENCE.
*
- * . The operand has lifetime MODEL_INPUT. Fully
+ * . The operand has lifetime SUBGRAPH_INPUT. Fully
* specified dimensions must either be present in the
* Operand or they must be provided in the corresponding
* RequestArgument.
@@ -5049,8 +5195,8 @@
/**
* Where to find the data for this operand.
- * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
- * NO_VALUE:
+ * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+ * or NO_VALUE:
* - All the fields must be 0.
* If the lifetime is CONSTANT_COPY:
* - location.poolIndex is 0.
@@ -5060,6 +5206,11 @@
* - location.poolIndex is set.
* - location.offset is the offset in bytes into the specified pool.
* - location.length is set.
+ * If the lifetime is SUBGRAPH:
+ * - location.poolIndex is 0.
+ * - location.offset is the index of the referenced subgraph in
+ * {@link Model::referenced}.
+ * - location.length is 0.
*/
DataLocation location;
@@ -5098,32 +5249,19 @@
*/
struct Model {
/**
- * All operands included in the model.
+ * The top-level subgraph.
*/
- vec<Operand> operands;
+ Subgraph main;
/**
- * All operations included in the model.
+ * Referenced subgraphs.
*
- * The operations are sorted into execution order. Every operand
- * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
- * written before it is read.
- */
- vec<Operation> operations;
-
- /**
- * Input indexes of the model. There must be at least one.
+ * Each subgraph is referenced by the main subgraph or at least one other
+ * referenced subgraph.
*
- * Each value corresponds to the index of the operand in "operands".
+ * There must be no reference cycles.
*/
- vec<uint32_t> inputIndexes;
-
- /**
- * Output indexes of the model. There must be at least one.
- *
- * Each value corresponds to the index of the operand in "operands".
- */
- vec<uint32_t> outputIndexes;
+ vec<Subgraph> referenced;
/**
* A byte buffer containing operand data that were copied into the model.
@@ -5157,9 +5295,9 @@
* {@link OperandTypeRange::BASE_MAX} or
* {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
* as an extension operand. The low
- * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
- * correspond to the type ID within the extension and the high
- * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+ * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+ * value correspond to the type ID within the extension and the high
+ * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
* the "prefix", which maps uniquely to the extension name.
*
* For example, if a model contains an operation whose value is
@@ -5172,39 +5310,40 @@
* prefix corresponding to each extension name and at most one extension
* name corresponding to each prefix.
*/
- vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+ vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+ /**
+ * All operands included in the subgraph.
+ */
+ vec<Operand> operands;
/**
- * A correspondence between an extension name and a prefix of operand and
- * operation type values.
+ * All operations included in the subgraph.
+ *
+ * The operations are sorted into execution order. Every operand
+ * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+ * written before it is read.
*/
- struct ExtensionNameAndPrefix {
- /**
- * The extension name.
- *
- * See {@link Extension::name} for the format specification.
- */
- string name;
-
- /**
- * The unique extension identifier within the model.
- *
- * See {@link Model::extensionNameToPrefix}.
- */
- uint16_t prefix;
- };
+ vec<Operation> operations;
/**
- * Numeric values of extension operand and operation types have the
- * following structure:
- * - 16 high bits represent the "prefix", which corresponds uniquely to the
- * extension name.
- * - 16 low bits represent the type ID within the extension.
+ * Input indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
*/
- enum ExtensionTypeEncoding : uint8_t {
- HIGH_BITS_PREFIX = 16,
- LOW_BITS_TYPE = 16,
- };
+ vec<uint32_t> inputIndexes;
+
+ /**
+ * Output indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> outputIndexes;
};
/**
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index b1c72a9..f3319e5 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -19,9 +19,10 @@
package android.hardware.neuralnetworks@1.3;
import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
import @1.0::PerformanceInfo;
import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
import @1.2::OperandType;
import @1.2::OperationType;
import @1.2::SymmPerChannelQuantParams;
@@ -88,7 +89,6 @@
BASE_MAX = 0xFFFF,
};
-
/**
* The capabilities of a driver.
*
@@ -150,6 +150,59 @@
};
/**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+ /**
+ * The operand is internal to the model. It's created by an operation and
+ * consumed by other operations. It must be an output operand of
+ * exactly one operation.
+ */
+ TEMPORARY_VARIABLE,
+
+ /**
+ * The operand is an input of a subgraph. It must not be an output
+ * operand of any operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_INPUT,
+
+ /**
+ * The operand is an output of a subgraph. It must be an output
+ * operand of exactly one operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_OUTPUT,
+
+ /**
+ * The operand is a constant found in Model.operandValues. It must
+ * not be an output operand of any operation.
+ */
+ CONSTANT_COPY,
+
+ /**
+ * The operand is a constant that was specified via a Memory
+ * object. It must not be an output operand of any operation.
+ */
+ CONSTANT_REFERENCE,
+
+ /**
+ * The operand does not have a value. This is valid only for optional
+ * arguments of operations.
+ */
+ NO_VALUE,
+
+ /**
+ * The operand is a reference to a subgraph. It must be an input to one
+ * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+ * operations.
+ */
+ SUBGRAPH,
+};
+
+/**
* Describes one operand of the model's graph.
*/
struct Operand {
@@ -185,7 +238,7 @@
* . The operand has lifetime CONSTANT_COPY or
* CONSTANT_REFERENCE.
*
- * . The operand has lifetime MODEL_INPUT. Fully
+ * . The operand has lifetime SUBGRAPH_INPUT. Fully
* specified dimensions must either be present in the
* Operand or they must be provided in the corresponding
* RequestArgument.
@@ -233,8 +286,8 @@
/**
* Where to find the data for this operand.
- * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
- * NO_VALUE:
+ * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+ * or NO_VALUE:
* - All the fields must be 0.
* If the lifetime is CONSTANT_COPY:
* - location.poolIndex is 0.
@@ -244,6 +297,11 @@
* - location.poolIndex is set.
* - location.offset is the offset in bytes into the specified pool.
* - location.length is set.
+ * If the lifetime is SUBGRAPH:
+ * - location.poolIndex is 0.
+ * - location.offset is the index of the referenced subgraph in
+ * {@link Model::referenced}.
+ * - location.length is 0.
*/
DataLocation location;
@@ -282,32 +340,19 @@
*/
struct Model {
/**
- * All operands included in the model.
+ * The top-level subgraph.
*/
- vec<Operand> operands;
+ Subgraph main;
/**
- * All operations included in the model.
+ * Referenced subgraphs.
*
- * The operations are sorted into execution order. Every operand
- * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
- * written before it is read.
- */
- vec<Operation> operations;
-
- /**
- * Input indexes of the model. There must be at least one.
+ * Each subgraph is referenced by the main subgraph or at least one other
+ * referenced subgraph.
*
- * Each value corresponds to the index of the operand in "operands".
+ * There must be no reference cycles.
*/
- vec<uint32_t> inputIndexes;
-
- /**
- * Output indexes of the model. There must be at least one.
- *
- * Each value corresponds to the index of the operand in "operands".
- */
- vec<uint32_t> outputIndexes;
+ vec<Subgraph> referenced;
/**
* A byte buffer containing operand data that were copied into the model.
@@ -341,9 +386,9 @@
* {@link OperandTypeRange::BASE_MAX} or
* {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
* as an extension operand. The low
- * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
- * correspond to the type ID within the extension and the high
- * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+ * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+ * value correspond to the type ID within the extension and the high
+ * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
* the "prefix", which maps uniquely to the extension name.
*
* For example, if a model contains an operation whose value is
@@ -356,39 +401,40 @@
* prefix corresponding to each extension name and at most one extension
* name corresponding to each prefix.
*/
- vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+ vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+ /**
+ * All operands included in the subgraph.
+ */
+ vec<Operand> operands;
/**
- * A correspondence between an extension name and a prefix of operand and
- * operation type values.
+ * All operations included in the subgraph.
+ *
+ * The operations are sorted into execution order. Every operand
+ * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+ * written before it is read.
*/
- struct ExtensionNameAndPrefix {
- /**
- * The extension name.
- *
- * See {@link Extension::name} for the format specification.
- */
- string name;
-
- /**
- * The unique extension identifier within the model.
- *
- * See {@link Model::extensionNameToPrefix}.
- */
- uint16_t prefix;
- };
+ vec<Operation> operations;
/**
- * Numeric values of extension operand and operation types have the
- * following structure:
- * - 16 high bits represent the "prefix", which corresponds uniquely to the
- * extension name.
- * - 16 low bits represent the type ID within the extension.
+ * Input indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
*/
- enum ExtensionTypeEncoding : uint8_t {
- HIGH_BITS_PREFIX = 16,
- LOW_BITS_TYPE = 16,
- };
+ vec<uint32_t> inputIndexes;
+
+ /**
+ * Output indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> outputIndexes;
};
/**
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index fe8d907..5cb466f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -308,7 +308,7 @@
model,
[&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) {
ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_EQ(supported.size(), model.operations.size());
+ ASSERT_EQ(supported.size(), model.main.operations.size());
fullySupportsModel = std::all_of(supported.begin(), supported.end(),
[](bool valid) { return valid; });
});
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 4f747f4..805d5b5 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -59,7 +59,6 @@
using implementation::PreparedModelCallback;
using V1_0::DataLocation;
using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
using V1_0::RequestArgument;
using V1_1::ExecutionPreference;
using V1_2::Constant;
@@ -269,10 +268,10 @@
}
}
- return {.operands = std::move(operands),
- .operations = std::move(operations),
- .inputIndexes = testModel.inputIndexes,
- .outputIndexes = testModel.outputIndexes,
+ return {.main = {.operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = testModel.inputIndexes,
+ .outputIndexes = testModel.outputIndexes},
.operandValues = std::move(operandValues),
.pools = std::move(pools),
.relaxComputationFloat32toFloat16 = testModel.isRelaxed};
@@ -290,8 +289,8 @@
}
static void makeOutputDimensionsUnspecified(Model* model) {
- for (auto i : model->outputIndexes) {
- auto& dims = model->operands[i].dimensions;
+ for (auto i : model->main.outputIndexes) {
+ auto& dims = model->main.operands[i].dimensions;
std::fill(dims.begin(), dims.end(), 0);
}
}
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 8395111..cc86264 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -25,7 +25,6 @@
using implementation::PreparedModelCallback;
using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
using V1_1::ExecutionPreference;
using V1_2::SymmPerChannelQuantParams;
using HidlToken =
@@ -83,22 +82,22 @@
}
static uint32_t addOperand(Model* model) {
- return hidl_vec_push_back(&model->operands,
+ return hidl_vec_push_back(&model->main.operands,
{
.type = OperandType::INT32,
.dimensions = {},
.numberOfConsumers = 0,
.scale = 0.0f,
.zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
+ .lifetime = OperandLifeTime::SUBGRAPH_INPUT,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
});
}
static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
uint32_t index = addOperand(model);
- model->operands[index].numberOfConsumers = 1;
- model->operands[index].lifetime = lifetime;
+ model->main.operands[index].numberOfConsumers = 1;
+ model->main.operands[index].lifetime = lifetime;
return index;
}
@@ -112,13 +111,13 @@
};
static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
for (uint32_t invalidOperandType : invalidOperandTypes) {
const std::string message = "mutateOperandTypeTest: operand " +
std::to_string(operand) + " set to value " +
std::to_string(invalidOperandType);
validate(device, message, model, [operand, invalidOperandType](Model* model) {
- model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+ model->main.operands[operand].type = static_cast<OperandType>(invalidOperandType);
});
}
}
@@ -150,15 +149,15 @@
}
static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+ const uint32_t invalidRank = getInvalidRank(model.main.operands[operand].type);
if (invalidRank == 0) {
continue;
}
const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
" has rank of " + std::to_string(invalidRank);
validate(device, message, model, [operand, invalidRank](Model* model) {
- model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+ model->main.operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
});
}
}
@@ -190,12 +189,12 @@
}
static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- const float invalidScale = getInvalidScale(model.operands[operand].type);
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+ const float invalidScale = getInvalidScale(model.main.operands[operand].type);
const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
" has scale of " + std::to_string(invalidScale);
validate(device, message, model, [operand, invalidScale](Model* model) {
- model->operands[operand].scale = invalidScale;
+ model->main.operands[operand].scale = invalidScale;
});
}
}
@@ -229,15 +228,15 @@
}
static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
const std::vector<int32_t> invalidZeroPoints =
- getInvalidZeroPoints(model.operands[operand].type);
+ getInvalidZeroPoints(model.main.operands[operand].type);
for (int32_t invalidZeroPoint : invalidZeroPoints) {
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
std::to_string(invalidZeroPoint);
validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
- model->operands[operand].zeroPoint = invalidZeroPoint;
+ model->main.operands[operand].zeroPoint = invalidZeroPoint;
});
}
}
@@ -310,11 +309,11 @@
static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) {
// Do not test OEM types
- if (type == model.operands[operand].type || type == OperandType::OEM ||
+ if (type == model.main.operands[operand].type || type == OperandType::OEM ||
type == OperandType::TENSOR_OEM_BYTE) {
return true;
}
- for (const Operation& operation : model.operations) {
+ for (const Operation& operation : model.main.operations) {
// Skip mutateOperationOperandTypeTest for the following operations.
// - LSH_PROJECTION's second argument is allowed to have any type.
// - ARGMIN and ARGMAX's first argument can be any of
@@ -401,7 +400,7 @@
}
static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) {
continue;
@@ -410,7 +409,7 @@
std::to_string(operand) + " set to type " +
toString(invalidOperandType);
validate(device, message, model, [operand, invalidOperandType](Model* model) {
- mutateOperand(&model->operands[operand], invalidOperandType);
+ mutateOperand(&model->main.operands[operand], invalidOperandType);
});
}
}
@@ -425,13 +424,13 @@
};
static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
for (uint32_t invalidOperationType : invalidOperationTypes) {
const std::string message = "mutateOperationTypeTest: operation " +
std::to_string(operation) + " set to value " +
std::to_string(invalidOperationType);
validate(device, message, model, [operation, invalidOperationType](Model* model) {
- model->operations[operation].type =
+ model->main.operations[operation].type =
static_cast<OperationType>(invalidOperationType);
});
}
@@ -441,14 +440,14 @@
///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- const uint32_t invalidOperand = model.operands.size();
- for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.main.operands.size();
+ for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
const std::string message = "mutateOperationInputOperandIndexTest: operation " +
std::to_string(operation) + " input " +
std::to_string(input);
validate(device, message, model, [operation, input, invalidOperand](Model* model) {
- model->operations[operation].inputs[input] = invalidOperand;
+ model->main.operations[operation].inputs[input] = invalidOperand;
});
}
}
@@ -457,14 +456,15 @@
///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- const uint32_t invalidOperand = model.operands.size();
- for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.main.operands.size();
+ for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+ ++output) {
const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
std::to_string(operation) + " output " +
std::to_string(output);
validate(device, message, model, [operation, output, invalidOperand](Model* model) {
- model->operations[operation].outputs[output] = invalidOperand;
+ model->main.operations[operation].outputs[output] = invalidOperand;
});
}
}
@@ -485,17 +485,17 @@
}
static void removeOperand(Model* model, uint32_t index) {
- hidl_vec_removeAt(&model->operands, index);
- for (Operation& operation : model->operations) {
+ hidl_vec_removeAt(&model->main.operands, index);
+ for (Operation& operation : model->main.operations) {
removeValueAndDecrementGreaterValues(&operation.inputs, index);
removeValueAndDecrementGreaterValues(&operation.outputs, index);
}
- removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
- removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->main.inputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->main.outputIndexes, index);
}
static bool removeOperandSkip(size_t operand, const Model& model) {
- for (const Operation& operation : model.operations) {
+ for (const Operation& operation : model.main.operations) {
// Skip removeOperandTest for the following operations.
// - SPLIT's outputs are not checked during prepareModel.
if (operation.type == OperationType::SPLIT) {
@@ -520,7 +520,7 @@
}
static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
if (removeOperandSkip(operand, model)) {
continue;
}
@@ -533,14 +533,14 @@
///////////////////////// REMOVE OPERATION /////////////////////////
static void removeOperation(Model* model, uint32_t index) {
- for (uint32_t operand : model->operations[index].inputs) {
- model->operands[operand].numberOfConsumers--;
+ for (uint32_t operand : model->main.operations[index].inputs) {
+ model->main.operands[operand].numberOfConsumers--;
}
- hidl_vec_removeAt(&model->operations, index);
+ hidl_vec_removeAt(&model->main.operations, index);
}
static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message = "removeOperationTest: operation " + std::to_string(operation);
validate(device, message, model,
[operation](Model* model) { removeOperation(model, operation); });
@@ -615,9 +615,9 @@
}
static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
- const Operation& op = model.operations[operation];
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
+ const Operation& op = model.main.operations[operation];
if (removeOperationInputSkip(op, input)) {
continue;
}
@@ -625,9 +625,9 @@
std::to_string(operation) + ", input " +
std::to_string(input);
validate(device, message, model, [operation, input](Model* model) {
- uint32_t operand = model->operations[operation].inputs[input];
- model->operands[operand].numberOfConsumers--;
- hidl_vec_removeAt(&model->operations[operation].inputs, input);
+ uint32_t operand = model->main.operations[operation].inputs[input];
+ model->main.operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
});
}
}
@@ -636,13 +636,14 @@
///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+ ++output) {
const std::string message = "removeOperationOutputTest: operation " +
std::to_string(operation) + ", output " +
std::to_string(output);
validate(device, message, model, [operation, output](Model* model) {
- hidl_vec_removeAt(&model->operations[operation].outputs, output);
+ hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
});
}
}
@@ -669,15 +670,15 @@
}
static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- if (addOperationInputSkip(model.operations[operation])) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ if (addOperationInputSkip(model.main.operations[operation])) {
continue;
}
const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
- hidl_vec_push_back(&model->operations[operation].inputs, index);
- hidl_vec_push_back(&model->inputIndexes, index);
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
+ hidl_vec_push_back(&model->main.operations[operation].inputs, index);
+ hidl_vec_push_back(&model->main.inputIndexes, index);
});
}
}
@@ -685,13 +686,13 @@
///////////////////////// ADD OPERATION OUTPUT /////////////////////////
static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message =
"addOperationOutputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
- hidl_vec_push_back(&model->operations[operation].outputs, index);
- hidl_vec_push_back(&model->outputIndexes, index);
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
+ hidl_vec_push_back(&model->main.operations[operation].outputs, index);
+ hidl_vec_push_back(&model->main.outputIndexes, index);
});
}
}
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 724d014..d629a3f 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -228,6 +228,16 @@
BAND_261 = 261,
};
+enum UtranBands : @1.1::UtranBands {
+ /** TD-SCDMA bands. 3GPP TS 25.102, Table 5.2: Frequency bands */
+ BAND_A = 101,
+ BAND_B = 102,
+ BAND_C = 103,
+ BAND_D = 104,
+ BAND_E = 105,
+ BAND_F = 106,
+};
+
/**
* Overwritten from @1.2::NetworkScanRequest to update
* RadioAccessSpecifier to 1.5 version
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
index 85c4f99..182985e 100644
--- a/radio/1.5/vts/functional/Android.bp
+++ b/radio/1.5/vts/functional/Android.bp
@@ -34,6 +34,7 @@
"android.hardware.radio@1.0",
"android.hardware.radio.config@1.0",
"android.hardware.radio.config@1.1",
+ "android.hardware.radio.config@1.3",
],
header_libs: ["radio.util.header@1.0"],
test_suites: ["general-tests"]
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
index a5d236d..c29ebf9 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -47,9 +47,9 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
- sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
+ sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig =
::testing::VtsHalHidlTargetTestBase::getService<
- ::android::hardware::radio::config::V1_1::IRadioConfig>();
+ ::android::hardware::radio::config::V1_3::IRadioConfig>();
/* Enforce Vts tesing with RadioConfig is existed. */
ASSERT_NE(nullptr, radioConfig.get());
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 217caf5..c2a7d8a 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -22,7 +22,7 @@
#include <condition_variable>
#include <mutex>
-#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
#include <android/hardware/radio/1.5/IRadio.h>
#include <android/hardware/radio/1.5/IRadioIndication.h>
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
index 88de666..7360270 100644
--- a/radio/config/1.3/Android.bp
+++ b/radio/config/1.3/Android.bp
@@ -17,6 +17,9 @@
"android.hardware.radio.config@1.1",
"android.hardware.radio.config@1.2",
"android.hardware.radio@1.0",
+ "android.hardware.radio@1.1",
+ "android.hardware.radio@1.4",
+ "android.hardware.radio@1.5",
"android.hidl.base@1.0",
],
gen_java: true,
diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal
index a0ce6e0..d01f54b 100644
--- a/radio/config/1.3/IRadioConfig.hal
+++ b/radio/config/1.3/IRadioConfig.hal
@@ -27,5 +27,13 @@
* serial to different methods), multiple responses (one for each method call) must still be served.
*/
interface IRadioConfig extends @1.1::IRadioConfig {
-
+ /**
+ * Request current phone capability.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getPhoneCapabilityResponse_1_3() which
+ * will return <@1.3::PhoneCapability>.
+ */
+ oneway getPhoneCapability_1_3(int32_t serial);
};
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
index 9c4c971..e13aa1e 100644
--- a/radio/config/1.3/IRadioConfigResponse.hal
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -16,11 +16,22 @@
package android.hardware.radio.config@1.3;
+import android.hardware.radio@1.0::RadioResponseInfo;
import @1.2::IRadioConfigResponse;
+import @1.3::PhoneCapability;
/**
* Interface declaring response functions to solicited radio config requests.
*/
interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
-
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param phoneCapability <@1.3::PhoneCapability> it defines modem's capability for example
+ * how many logical modems it has, how many data connections it supports.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ */
+ oneway getPhoneCapabilityResponse_1_3(RadioResponseInfo info, PhoneCapability phoneCapability);
};
diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp
index c28119c..01e98f1 100644
--- a/radio/config/1.3/default/RadioConfig.cpp
+++ b/radio/config/1.3/default/RadioConfig.cpp
@@ -24,7 +24,6 @@
namespace implementation {
using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config;
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
Return<void> RadioConfig::setResponseFunctions(
@@ -105,6 +104,14 @@
return Void();
}
+// Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow.
+Return<void> RadioConfig::getPhoneCapability_1_3(int32_t /* serial */) {
+ V1_3::PhoneCapability phoneCapability;
+ RadioResponseInfo info;
+ mRadioConfigResponseV1_3->getPhoneCapabilityResponse_1_3(info, phoneCapability);
+ return Void();
+}
+
} // namespace implementation
} // namespace V1_3
} // namespace config
diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h
index 00585e6..57ff368 100644
--- a/radio/config/1.3/default/RadioConfig.h
+++ b/radio/config/1.3/default/RadioConfig.h
@@ -62,6 +62,9 @@
Return<void> setPreferredDataModem(int32_t serial, uint8_t modemId);
Return<void> setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig);
Return<void> getModemsConfig(int32_t serial);
+
+ // Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow.
+ Return<void> getPhoneCapability_1_3(int32_t serial);
};
} // namespace implementation
diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp
index eb77a48..608fa1c 100644
--- a/radio/config/1.3/default/RadioConfigIndication.cpp
+++ b/radio/config/1.3/default/RadioConfigIndication.cpp
@@ -23,10 +23,6 @@
namespace V1_3 {
namespace implementation {
-using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config::V1_0;
-using namespace ::android::hardware::radio::config::V1_2;
-
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
Return<void> RadioConfigIndication::simSlotsStatusChanged(
RadioIndicationType /* type */, const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h
index 3697492..c92446c 100644
--- a/radio/config/1.3/default/RadioConfigIndication.h
+++ b/radio/config/1.3/default/RadioConfigIndication.h
@@ -31,10 +31,6 @@
using namespace ::android::hardware::radio::V1_0;
using namespace ::android::hardware::radio::config;
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp
index 48e81da..1d48a13 100644
--- a/radio/config/1.3/default/RadioConfigResponse.cpp
+++ b/radio/config/1.3/default/RadioConfigResponse.cpp
@@ -23,11 +23,6 @@
namespace V1_3 {
namespace implementation {
-using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config::V1_0;
-using namespace ::android::hardware::radio::config::V1_1;
-using namespace ::android::hardware::radio::config::V1_2;
-
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
const RadioResponseInfo& /* info */,
@@ -73,6 +68,13 @@
return Void();
}
+// Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse_1_3(
+ const RadioResponseInfo& /* info */, const V1_3::PhoneCapability& /* phoneCapability */) {
+ // TODO implement
+ return Void();
+}
+
} // namespace implementation
} // namespace V1_3
} // namespace config
diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h
index 0f0033f..dc169bb 100644
--- a/radio/config/1.3/default/RadioConfigResponse.h
+++ b/radio/config/1.3/default/RadioConfigResponse.h
@@ -28,43 +28,36 @@
namespace V1_3 {
namespace implementation {
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
+using namespace ::android::hardware::radio::config;
+
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
-using ::android::hardware::Void;
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
struct RadioConfigResponse : public IRadioConfigResponse {
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
Return<void> getSimSlotsStatusResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus)
- override;
- Return<void> setSimSlotsMappingResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+ const RadioResponseInfo& info,
+ const hidl_vec<V1_0::SimSlotStatus>& slotStatus) override;
+ Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info) override;
// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
- Return<void> getPhoneCapabilityResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability)
- override;
- Return<void> setPreferredDataModemResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
- Return<void> setModemsConfigResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
- Return<void> getModemsConfigResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override;
+ Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+ const V1_1::PhoneCapability& phoneCapability) override;
+ Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info) override;
+ Return<void> setModemsConfigResponse(const RadioResponseInfo& info) override;
+ Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+ const V1_1::ModemsConfig& modemsConfig) override;
// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
Return<void> getSimSlotsStatusResponse_1_2(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus)
- override;
+ const RadioResponseInfo& info,
+ const hidl_vec<V1_2::SimSlotStatus>& slotStatus) override;
- // Methods from ::android::hidl::base::V1_0::IBase follow.
+ // Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow.
+ Return<void> getPhoneCapabilityResponse_1_3(
+ const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) override;
};
} // namespace implementation
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
index 866002a..3414534 100644
--- a/radio/config/1.3/types.hal
+++ b/radio/config/1.3/types.hal
@@ -15,3 +15,181 @@
*/
package android.hardware.radio.config@1.3;
+
+import android.hardware.radio@1.1::GeranBands;
+import android.hardware.radio@1.1::UtranBands;
+import android.hardware.radio@1.1::EutranBands;
+import android.hardware.radio@1.4::RadioAccessFamily;
+import android.hardware.radio@1.5::NgranBands;
+
+/** Type for the SIM slot. */
+enum SlotType : int32_t {
+ /** Slot type for UICC/pSIM (physical SIM). */
+ UICC = 1,
+ /** Slot type for iUICC/iSIM (integrated SIM). */
+ IUICC = 2,
+ /** Slot type for eUICC/eSIM (embedded SIM). */
+ EUICC = 3,
+ /** Slot type for soft SIM (no physical SIM). */
+ SOFT_SIM = 4,
+};
+
+/** A field in PhoneCapability that holds information about the SIM slot. */
+struct SimSlotCapability {
+ /** Corresponds to physicalSlotId in Radio@1.2::CardStatus. */
+ uint32_t physicalSlotId;
+
+ /** Type of slot. */
+ SlotType slotType;
+};
+
+/** Bitmask of features that can be supported by a single modem. */
+enum ModemFeatures : int32_t {
+ /** 3GPP2 capability. */
+ THREE_GPP2_REG = 1 << 0,
+ /** 3GPP capability. */
+ THREE_GPP_REG = 1 << 1,
+ /** CDMA 2000 with EHRPD capability. */
+ CDMA2000_EHRPD_REG = 1 << 2,
+ /** GSM capability. */
+ GERAN_REG = 1 << 3,
+ /** UMTS capability. */
+ UTRAN_REG = 1 << 4,
+ /** LTE capability. */
+ EUTRAN_REG = 1 << 5,
+ /** 5G capability. */
+ NGRAN_REG = 1 << 6,
+ /** Dual Connectivity capability. */
+ EN_DC_REG = 1 << 7,
+ /** VoLTE capability (IMS registered). */
+ PS_VOICE_REG = 1 << 8,
+ /** CS voice call capability. */
+ CS_VOICE_SESSION = 1 << 9,
+ /** Internet connection capability. */
+ INTERACTIVE_DATA_SESSION = 1 << 10,
+ /** Dedicated bearer capability. */
+ DEDICATED_BEARER = 1 << 11,
+ /** Network scanning capability. */
+ NETWORK_SCAN = 1 << 12,
+ /** CDMA capability for SIM associated with modem. */
+ CSIM = 1 << 13,
+};
+
+struct ConcurrentModemFeatures {
+ /**
+ * A vector of concurrently supportable modem features across all modems.
+ * Each entry in the vector is a bitfield of ModemFeatures that can be used
+ * concurrently with the other ModemFeatures in that list.
+ * Each bitfield must be the full set of features for a single modem.
+ *
+ * On a Dual-SIM device, each entry will be a vector of length 2.
+ * The examples below depict the modemFeatures for four Dual-SIM setups:
+ * 1. Only one modem can PS attach (IMS registered).
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG)
+ * }
+ * or
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * INTERACTIVE_DATA_SESSION),
+ * (GERAN_REG | UTRAN_REG | CS_VOICE_SESSION)
+ * }
+ * 2. Both modems can PS attach (dual VoLTE).
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG)
+ * }
+ * 3. Both modems can maintain an Internet connection, but they share
+ * one RF hardware.
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * INTERACTIVE_DATA_SESSION)
+ * }
+ * 4. Both modems can maintain an Internet connection, and they have
+ * their own RF hardware.
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * INTERACTIVE_DATA_SESSION | DEDICATED_BEARER)
+ * }
+ */
+ vec<bitfield<ModemFeatures>> modemFeatures;
+};
+
+/**
+ * Overwritten from @1.1::PhoneCapability to add new capabilities and deprecate
+ * maxActiveData, maxActiveInternetData, isInternetLingeringSupported, logicalModemList.
+ * Replaces RadioConfig@1.1::ModemInfo and should replace Radio@1.4::RadioCapabilities
+ * in the next major version upgrade. In the future, this should be extended instead of overwritten.
+ */
+struct PhoneCapability {
+ /**
+ * 3GPP UE category for UTRAN downlink direction.
+ * 25.306 Table 5.1a
+ */
+ uint8_t utranUeCategoryDl;
+ /**
+ * 3GPP UE category for UTRAN uplink direction.
+ * 25.306 Table 5.1g
+ */
+ uint8_t utranUeCategoryUl;
+ /**
+ * 3GPP UE category for EUTRAN downlink direction.
+ * 25.306 Table 4.1a
+ */
+ uint8_t eutranUeCategoryDl;
+ /**
+ * 3GPP UE category for EUTRAN uplink direction.
+ * 25.306 Table 4.1a-2
+ */
+ uint8_t eutranUeCategoryUl;
+
+ /**
+ * Length of grace period for switching between logical modems, in milliseconds.
+ * Used only when the number of logical modems is greater than the number of
+ * Internet connections the device can support, otherwise must be 0.
+ */
+ uint64_t psDataConnectionLingerTimeMillis;
+
+ vec<GeranBands> geranBands;
+ vec<UtranBands> utranBands;
+ vec<EutranBands> eutranBands;
+ vec<NgranBands> ngranBands;
+
+ /**
+ * 32-bit bitmap of supported Radio@1.4::RadioAccessFamily types.
+ * Note that RadioAccessFamily is actually the radio access technologies, so it should be
+ * renamed in the next major version upgrade.
+ */
+ bitfield<RadioAccessFamily> supportedRats;
+
+ /**
+ * List of unique logical modem UUIDs from Radio@1.4::RadioCapabilities.
+ * A UUID is typically "com.xxxx.lmX" where X is the logical modem ID.
+ * Must be equal to the number of logical modems in the device.
+ * Radio@1.2::RadioConst::MAX_UUID_LENGTH is the max length of each UUID.
+ */
+ vec<string> logicalModemUuids;
+
+ /**
+ * List of SIM slot capabilities. The order of physical slot IDs must correspond to
+ * the order of modems in logicalModemUuids.
+ */
+ vec<SimSlotCapability> simSlotCapabilities;
+
+ /**
+ * A vector of all sets of concurrently supportable modem feature sets. The order of modems
+ * in modemFeatures must correspond to the order of modems in logicalModemUuids.
+ * Each entry in concurrentFeatureSupport is independent of others in the list
+ * and represents a set of concurrently supportable features across all modems.
+ * Each entry in ConcurrentModemFeatures::modemFeatures is a bitfield of
+ * concurrently supported ModemFeatures for one modem.
+ */
+ vec<ConcurrentModemFeatures> concurrentFeatureSupport;
+};
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
index 07e9ede..7f90023 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
@@ -17,3 +17,34 @@
#include <radio_config_hidl_hal_utils.h>
#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+/*
+ * Test IRadioConfig.getPhoneCapability_1_3()
+ */
+TEST_P(RadioConfigHidlTest, getPhoneCapability_1_3) {
+ serial = GetRandomSerialNumber();
+ Return<void> res = radioConfig->getPhoneCapability_1_3(serial);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+ EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+ ALOGI("getPhoneCapability_1_3, rspInfo.error = %s\n",
+ toString(radioConfigRsp->rspInfo.error).c_str());
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioConfigRsp->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
+
+ if (radioConfigRsp->rspInfo.error == RadioError ::NONE) {
+ int numModems = radioConfigRsp->phoneCap_1_3.logicalModemUuids.size();
+ EXPECT_GE(numModems, 0);
+ // length of simSlotCapabilities should be equal to length of logicalModemUuids.
+ EXPECT_EQ(numModems, radioConfigRsp->phoneCap_1_3.simSlotCapabilities.size());
+ // length of modemFeatures in each ConcurrentModemFeatures should be
+ // equal to length of logicalModemUuids.
+ for (V1_3::ConcurrentModemFeatures cmf :
+ radioConfigRsp->phoneCap_1_3.concurrentFeatureSupport) {
+ EXPECT_EQ(numModems, cmf.modemFeatures.size());
+ }
+ }
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
index dbb4bf4..cd48b25 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
@@ -17,7 +17,7 @@
#include <radio_config_hidl_hal_utils.h>
void RadioConfigHidlTest::SetUp() {
- radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam());
+ radioConfig = V1_3::IRadioConfig::getService(GetParam());
ASSERT_NE(nullptr, radioConfig.get());
radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
index 9b78c04..b21c7c0 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -28,19 +28,18 @@
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
+#include <log/log.h>
#include "vts_test_util.h"
-using namespace ::android::hardware::radio::config::V1_1;
-using namespace ::android::hardware::radio::config::V1_2;
-using namespace ::android::hardware::radio::config::V1_3;
+using namespace ::android::hardware::radio::config;
using ::android::sp;
-using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
+using ::android::hardware::radio::V1_0::RadioIndicationType;
using ::android::hardware::radio::V1_0::RadioResponseInfo;
using ::android::hardware::radio::V1_0::RadioResponseType;
@@ -49,43 +48,46 @@
class RadioConfigHidlTest;
/* Callback class for radio config response */
-class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse {
+class RadioConfigResponse : public V1_3::IRadioConfigResponse {
protected:
RadioConfigHidlTest& parent;
public:
RadioResponseInfo rspInfo;
- PhoneCapability phoneCap;
+ V1_1::PhoneCapability phoneCap_1_1;
+ V1_3::PhoneCapability phoneCap_1_3;
RadioConfigResponse(RadioConfigHidlTest& parent);
virtual ~RadioConfigResponse() = default;
/* 1.0 Api */
- Return<void> getSimSlotsStatusResponse(
- const RadioResponseInfo& info,
- const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus);
+ Return<void> getSimSlotsStatusResponse(const RadioResponseInfo& info,
+ const hidl_vec<V1_0::SimSlotStatus>& slotStatus);
Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
/* 1.1 Api */
Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
- const PhoneCapability& phoneCapability);
+ const V1_1::PhoneCapability& phoneCapability);
Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
- const ModemsConfig& mConfig);
+ const V1_1::ModemsConfig& mConfig);
Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
/* 1.2 Api */
Return<void> getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info,
- const hidl_vec<SimSlotStatus>& slotStatus);
+ const hidl_vec<V1_2::SimSlotStatus>& slotStatus);
+
+ /* 1.3 Api */
+ Return<void> getPhoneCapabilityResponse_1_3(const RadioResponseInfo& info,
+ const V1_3::PhoneCapability& phoneCapability);
};
/* Callback class for radio config indication */
-class RadioConfigIndication
- : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication {
+class RadioConfigIndication : public V1_3::IRadioConfigIndication {
protected:
RadioConfigHidlTest& parent;
@@ -94,9 +96,8 @@
virtual ~RadioConfigIndication() = default;
/* 1.2 Api */
- Return<void> simSlotsStatusChanged_1_2(
- ::android::hardware::radio::V1_0::RadioIndicationType type,
- const hidl_vec<SimSlotStatus>& slotStatus);
+ Return<void> simSlotsStatusChanged_1_2(RadioIndicationType type,
+ const hidl_vec<V1_2::SimSlotStatus>& slotStatus);
};
// The main test class for Radio config HIDL.
@@ -121,7 +122,7 @@
int serial;
/* radio config service handle */
- sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig;
+ sp<V1_3::IRadioConfig> radioConfig;
/* radio config response handle */
sp<RadioConfigResponse> radioConfigRsp;
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
index 1ca960e..22098d3 100644
--- a/radio/config/1.3/vts/functional/radio_config_response.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -16,17 +16,18 @@
#include <radio_config_hidl_hal_utils.h>
-using ::android::hardware::radio::V1_0::RadioResponseInfo;
+using namespace ::android::hardware::radio::config;
-// SimSlotStatus slotStatus;
+using ::android::hardware::hidl_vec;
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
/* 1.0 Apis */
Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
const RadioResponseInfo& /* info */,
- const ::android::hardware::hidl_vec<
- ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) {
+ const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
return Void();
}
@@ -36,9 +37,9 @@
/* 1.1 Apis */
Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
- const RadioResponseInfo& info, const PhoneCapability& phoneCapability) {
+ const RadioResponseInfo& info, const V1_1::PhoneCapability& phoneCapability) {
rspInfo = info;
- phoneCap = phoneCapability;
+ phoneCap_1_1 = phoneCapability;
parent.notify(info.serial);
return Void();
}
@@ -49,7 +50,7 @@
}
Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */,
- const ModemsConfig& /* mConfig */) {
+ const V1_1::ModemsConfig& /* mConfig */) {
return Void();
}
@@ -60,6 +61,15 @@
/* 1.2 Apis */
Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
const RadioResponseInfo& /* info */,
- const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) {
+ const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
return Void();
-}
\ No newline at end of file
+}
+
+/* 1.3 Apis */
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse_1_3(
+ const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) {
+ rspInfo = info;
+ phoneCap_1_3 = phoneCapability;
+ parent.notify(info.serial);
+ return Void();
+}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 3afe37d..2eaab36 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1131,9 +1131,14 @@
@export
enum FrontendAnalogType : uint32_t {
UNDEFINED = 0,
- PAL = 1 << 0,
- SECAM = 1 << 1,
- NTSC = 1 << 2,
+ AUTO = 1 << 0,
+ PAL = 1 << 1,
+ PAL_M = 1 << 2,
+ PAL_N = 1 << 3,
+ PAL_60 = 1 << 4,
+ NTSC = 1 << 5,
+ NTSC_443 = 1 << 6,
+ SECAM = 1 << 7,
};
/**
@@ -1142,23 +1147,24 @@
@export
enum FrontendAnalogSifStandard : uint32_t {
UNDEFINED = 0,
- BG = 1 << 0,
- BG_A2 = 1 << 1,
- BG_NICAM = 1 << 2,
- I = 1 << 3,
- DK = 1 << 4,
- DK1 = 1 << 5,
- DK2 = 1 << 6,
- DK3 = 1 << 7,
- DK_NICAM = 1 << 8,
- L = 1 << 9,
- M = 1 << 10,
- M_BTSC = 1 << 11,
- M_A2 = 1 << 12,
- M_EIA_J = 1 << 13,
- I_NICAM = 1 << 14,
- L_NICAM = 1 << 15,
- L_PRIME = 1 << 16,
+ AUTO = 1 << 0,
+ BG = 1 << 1,
+ BG_A2 = 1 << 2,
+ BG_NICAM = 1 << 3,
+ I = 1 << 4,
+ DK = 1 << 5,
+ DK1_A2 = 1 << 6,
+ DK2_A2 = 1 << 7,
+ DK3_A2 = 1 << 8,
+ DK_NICAM = 1 << 9,
+ L = 1 << 10,
+ M = 1 << 11,
+ M_BTSC = 1 << 12,
+ M_A2 = 1 << 13,
+ M_EIAJ = 1 << 14,
+ I_NICAM = 1 << 15,
+ L_NICAM = 1 << 16,
+ L_PRIME = 1 << 17,
};
/**
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
index 58ef165..b501a95 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -20,6 +20,7 @@
import @1.2::ISupplicantStaIface;
import ISupplicantStaNetwork;
import ISupplicantStaIfaceCallback;
+import @1.0::MacAddress;
/**
* Interface exposed by the supplicant for each station mode network
@@ -90,4 +91,32 @@
*/
getKeyMgmtCapabilities_1_3()
generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+
+ /**
+ * Flush FILS HLP IEs
+ * Use this to flush all the HLP IEs in wpa_supplicant
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+ * |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+ */
+ filsHlpFlushRequest() generates (SupplicantStatus status);
+
+ /**
+ * Add FILS HLP IEs
+ * Use this to add a HLP IE to wpa_supplicant
+ *
+ * @param dst_mac MAC address of the destination
+ * @param pkt The contents of the HLP IE starting from ethertype
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+ * |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+ */
+ filsHlpAddRequest(MacAddress dst_mac, vec<uint8_t> pkt) generates (SupplicantStatus status);
};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
index 0be43d8..6828dcd 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
@@ -17,6 +17,10 @@
package android.hardware.wifi.supplicant@1.3;
import @1.2::ISupplicantStaIfaceCallback;
+import @1.0::ISupplicantStaIfaceCallback.State;
+import @1.0::Bssid;
+import @1.0::SupplicantNetworkId;
+import @1.0::Ssid;
/**
* Callback Interface exposed by the supplicant service
@@ -190,4 +194,26 @@
* Indicates an EAP authentication failure.
*/
oneway onEapFailure_1_3(uint32_t errorCode);
+
+ /**
+ * Used to indicate a state change event on this particular iface. If this
+ * event is triggered by a particular network, the |SupplicantNetworkId|,
+ * |ssid|, |bssid| parameters must indicate the parameters of the network/AP
+ * which caused this state transition.
+ *
+ * @param newState New State of the interface. This must be one of the |State|
+ * values above.
+ * @param bssid BSSID of the corresponding AP which caused this state
+ * change event. This must be zero'ed if this event is not
+ * specific to a particular network.
+ * @param id ID of the corresponding network which caused this
+ * state change event. This must be invalid (UINT32_MAX) if this
+ * event is not specific to a particular network.
+ * @param ssid SSID of the corresponding network which caused this state
+ * change event. This must be empty if this event is not specific
+ * to a particular network.
+ * @param filsHlpSent If FILS HLP IEs were included in this association.
+ */
+ oneway onStateChanged_1_3(State newState, Bssid bssid, SupplicantNetworkId id, Ssid ssid,
+ bool filsHlpSent);
};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
index e579d24..0566a21 100644
--- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -44,6 +44,14 @@
* WAPI Cert
*/
WAPI_CERT = 1 << 13,
+ /**
+ * FILS shared key authentication with sha-256
+ */
+ FILS_SHA256 = 1 << 18,
+ /**
+ * FILS shared key authentication with sha-384
+ */
+ FILS_SHA384 = 1 << 19,
};
/**
@@ -268,4 +276,16 @@
* @return authAlgMask Combination of |AuthAlgMask| values.
*/
getAuthAlg_1_3() generates (SupplicantStatus status, bitfield<AuthAlgMask> authAlgMask);
+
+ /**
+ * Enable EAP ERP for this network.
+ *
+ * @param enable true to set, false otherwise.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setEapErp(bool enable) generates (SupplicantStatus status);
};
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 3a30cec..f7019d2 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -261,6 +261,12 @@
const ISupplicantStaIfaceCallback::BssTmData& /* data */) override {
return Void();
}
+ Return<void> onStateChanged_1_3(
+ ISupplicantStaIfaceCallback::State /* newState */,
+ const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */,
+ const hidl_vec<uint8_t>& /* ssid */, bool /* filsHlpSent */) override {
+ return Void();
+ }
};
class IfacePmkCacheCallback : public IfaceCallback {
@@ -506,6 +512,83 @@
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}
+
+/*
+ * FilsHlpAddRequest
+ */
+TEST_P(SupplicantStaIfaceHidlTest, FilsHlpAddRequest) {
+ uint32_t keyMgmtMask = 0;
+ uint8_t destMacAddr[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
+ std::vector<uint8_t> pktBuffer = {
+ 0x08, 0x00, 0x45, 0x10, 0x01, 0x3a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+ 0x39, 0xa4, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x44,
+ 0x00, 0x43, 0x01, 0x26, 0x77, 0x1e, 0x01, 0x01, 0x06, 0x00, 0x81, 0xf9,
+ 0xf7, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xc3,
+ 0x65, 0xca, 0x34, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x01, 0x3d,
+ 0x07, 0x01, 0x86, 0xc3, 0x65, 0xca, 0x34, 0x63, 0x39, 0x02, 0x05, 0xdc,
+ 0x3c, 0x0e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2d, 0x64, 0x68,
+ 0x63, 0x70, 0x2d, 0x52, 0x37, 0x0a, 0x01, 0x03, 0x06, 0x0f, 0x1a, 0x1c,
+ 0x33, 0x3a, 0x3b, 0x2b, 0xff, 0x00};
+
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ SupplicantStatusCode expectedStatusCode =
+ (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 |
+ ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384))
+ ? SupplicantStatusCode::SUCCESS
+ : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+ sta_iface_->filsHlpAddRequest(
+ destMacAddr, pktBuffer,
+ [expectedStatusCode](const SupplicantStatus& status) {
+ EXPECT_EQ(expectedStatusCode, status.code);
+ });
+}
+
+/*
+ * FilsHlpFlushRequest
+ */
+TEST_P(SupplicantStaIfaceHidlTest, FilsHlpFlushRequest) {
+ uint32_t keyMgmtMask = 0;
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ SupplicantStatusCode expectedStatusCode =
+ (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 |
+ ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384))
+ ? SupplicantStatusCode::SUCCESS
+ : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+ sta_iface_->filsHlpFlushRequest(
+ [expectedStatusCode](const SupplicantStatus& status) {
+ EXPECT_EQ(expectedStatusCode, status.code);
+ });
+}
INSTANTIATE_TEST_CASE_P(
PerInstance, SupplicantStaIfaceHidlTest,
testing::Combine(
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
index d82db50..13f3366 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -285,6 +285,28 @@
});
}
}
+/*
+ * SetEapErp
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetEapErp) {
+ uint32_t keyMgmtMask = 0;
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ SupplicantStatusCode expectedStatusCode =
+ (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 |
+ ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384))
+ ? SupplicantStatusCode::SUCCESS
+ : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+ sta_network_->setEapErp(
+ true, [expectedStatusCode](const SupplicantStatus &status) {
+ EXPECT_EQ(expectedStatusCode, status.code);
+ });
+}
INSTANTIATE_TEST_CASE_P(
PerInstance, SupplicantStaNetworkHidlTest,
testing::Combine(