Merge "Verify that imported keys have the correct characteristics."
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 6a0cfa5..3851c0f 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -44,9 +44,6 @@
platform_apis: true,
},
ndk: {
- vndk: {
- enabled: true,
- },
apex_available: [
"//apex_available:platform",
"com.android.bluetooth",
diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
index f111c01..4d6f003 100644
--- a/audio/common/all-versions/test/utility/src/ValidateXml.cpp
+++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
@@ -63,11 +63,8 @@
xmlSetGenericErrorFunc(this, errorCb);
}
~Libxml2Global() {
- // TODO: check if all those cleanup are needed
xmlSetGenericErrorFunc(nullptr, nullptr);
- xmlSchemaCleanupTypes();
xmlCleanupParser();
- xmlCleanupThreads();
}
const std::string& getErrors() { return errors; }
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index f25c391..dfc2386 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -715,7 +715,7 @@
sink.base.channelMask.value(getConfig().base.channelMask);
sink.ext.mix({});
sink.ext.mix().ioHandle = helper.getIoHandle();
- sink.ext.mix().useCase.source(toString(xsd::AudioSource::AUDIO_SOURCE_MIC));
+ sink.ext.mix().useCase.source(initMetadata.tracks[0].source);
EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source},
hidl_vec<AudioPortConfig>{sink},
returnIn(res, mPatchHandle)));
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 435c62d..61d447d 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1239,23 +1239,30 @@
: public OpenStreamTest<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn> {
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ auto flags = getInputFlags();
#if MAJOR_VERSION <= 6
address.device = AudioDevice::IN_DEFAULT;
#elif MAJOR_VERSION >= 7
auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
getDeviceName(), getMixPortName());
+ auto& metadata = initMetadata.tracks[0];
if (maybeSourceAddress.has_value() &&
!xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType)) {
address = maybeSourceAddress.value();
- auto& metadata = initMetadata.tracks[0];
metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
metadata.channelMask = getConfig().base.channelMask;
} else {
address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
}
-#endif
+#if MAJOR_VERSION == 7 && MINOR_VERSION >= 1
+ auto flagsIt = std::find(flags.begin(), flags.end(),
+ toString(xsd::AudioInOutFlag::AUDIO_INPUT_FLAG_ULTRASOUND));
+ if (flagsIt != flags.end()) {
+ metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_ULTRASOUND);
+ }
+#endif // 7.1
+#endif // MAJOR_VERSION >= 7
const AudioConfig& config = getConfig();
- auto flags = getInputFlags();
testOpen(
[&](AudioIoHandle handle, AudioConfig config, auto cb) {
return getDevice()->openInputStream(handle, address, config, flags,
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 29a9cd4..0b77d45 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -232,10 +232,12 @@
public class ValueType {
ctor public ValueType();
+ method public String getAndroid_type();
method public String getLiteral();
- method public int getNumerical();
+ method public long getNumerical();
+ method public void setAndroid_type(String);
method public void setLiteral(String);
- method public void setNumerical(int);
+ method public void setNumerical(long);
}
public class ValuesType {
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 842e724..3ce12e7 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -189,9 +189,20 @@
</xs:complexType>
<xs:complexType name="valueType">
<xs:attribute name="literal" type="xs:string" use="required"/>
- <xs:attribute name="numerical" type="xs:int" use="required"/>
+ <xs:attribute name="numerical" type="xs:long" use="required"/>
+ <xs:attribute name="android_type" type="longDecimalOrHexType" use="optional"/>
</xs:complexType>
+ <xs:simpleType name="longDecimalOrHexType">
+ <xs:union memberTypes="xs:long longHexType" />
+ </xs:simpleType>
+
+ <xs:simpleType name="longHexType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="0x[0-9A-Fa-f]{1,16}"/>
+ </xs:restriction>
+ </xs:simpleType>
+
<xs:complexType name="attributesRefType">
<xs:sequence>
<xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="1"/>
diff --git a/authsecret/aidl/Android.bp b/authsecret/aidl/Android.bp
index 432c1b9..90e128d 100644
--- a/authsecret/aidl/Android.bp
+++ b/authsecret/aidl/Android.bp
@@ -16,11 +16,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/automotive/OWNERS b/automotive/OWNERS
index 43c5f3e..09e257c 100644
--- a/automotive/OWNERS
+++ b/automotive/OWNERS
@@ -1,6 +1 @@
-pirozzoj@google.com
-twasilczyk@google.com
-krachuri@google.com
-gurunagarajan@google.com
-keunyoung@google.com
-felipeal@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/automotive/audiocontrol/OWNERS b/automotive/audiocontrol/OWNERS
new file mode 100644
index 0000000..f55eff3
--- /dev/null
+++ b/automotive/audiocontrol/OWNERS
@@ -0,0 +1 @@
+oscarazu@google.com
diff --git a/automotive/can/OWNERS b/automotive/can/OWNERS
new file mode 100644
index 0000000..ffa4828
--- /dev/null
+++ b/automotive/can/OWNERS
@@ -0,0 +1,3 @@
+kevinme@google.com
+chrisweir@google.com
+twasilczyk@google.com
diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp
index 26c53fa..1b180d9 100644
--- a/automotive/occupant_awareness/aidl/Android.bp
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/automotive/sv/OWNERS b/automotive/sv/OWNERS
new file mode 100644
index 0000000..af6788b
--- /dev/null
+++ b/automotive/sv/OWNERS
@@ -0,0 +1 @@
+tanmayp@google.com
diff --git a/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp b/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
index 90cdc66..fb8df99 100644
--- a/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
+++ b/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
@@ -88,11 +88,18 @@
}
mBtHci->close();
mBtHci.clear();
+ for (size_t i = 0; i < mFdCount; ++i) {
+ if (mFdList[i]) {
+ close(mFdList[i]);
+ }
+ }
}
bool init(const uint8_t* data, size_t size);
void process();
private:
+ size_t mFdCount = 1;
+ int32_t mFdList[CH_MAX] = {0};
sp<BluetoothHci> mBtHci = nullptr;
FuzzedDataProvider* mFdp = nullptr;
};
@@ -143,17 +150,15 @@
bool shouldSetH4Protocol = mFdp->ConsumeBool();
BtVendor* btVendor = BtVendor::getInstance();
- size_t fdcount = 1;
- int32_t fdList[CH_MAX] = {0};
if (!shouldSetH4Protocol) {
- fdcount = mFdp->ConsumeIntegralInRange<size_t>(kMinFdcount, CH_MAX - 1);
+ mFdCount = mFdp->ConsumeIntegralInRange<size_t>(kMinFdcount, CH_MAX - 1);
}
- for (size_t i = 0; i < fdcount; ++i) {
- fdList[i] = open("/dev/null", O_RDWR | O_CREAT);
+ for (size_t i = 0; i < mFdCount; ++i) {
+ mFdList[i] = open("/dev/null", O_RDWR | O_CREAT);
}
- btVendor->populateFdList(fdList, fdcount);
+ btVendor->populateFdList(mFdList, mFdCount);
mBtHci->initialize(bluetoothCallback);
if (!bluetoothCallback->isInitialized) {
@@ -181,12 +186,6 @@
}
btVendor->callRemainingCbacks();
-
- for (size_t i = 0; i < fdcount; ++i) {
- if (fdList[i]) {
- close(fdList[i]);
- }
- }
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
index d64751a..98b62ef 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -20,8 +20,11 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <option name="bluetooth" value="off" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+ <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
+ <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+ <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 52671b8..aca301c 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -40,9 +40,6 @@
enabled: false,
},
ndk: {
- vndk: {
- enabled: true,
- },
apex_available: [
"//apex_available:platform",
"com.android.bluetooth",
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
index 911c928..c16ff54 100644
--- a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
@@ -91,17 +91,21 @@
else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH)
buffer_modifier = kBufferInCount;
+ // 24 bit audio stream is sent as unpacked
+ int bytes_per_sample =
+ (pcm_config.bitsPerSample == 24) ? 4 : (pcm_config.bitsPerSample / 8);
+
uint32_t data_mq_size =
(ceil(pcm_config.sampleRateHz) / 1000) *
- channel_mode_to_channel_count(pcm_config.channelMode) *
- (pcm_config.bitsPerSample / 8) * (pcm_config.dataIntervalUs / 1000) *
- buffer_modifier;
+ channel_mode_to_channel_count(pcm_config.channelMode) * bytes_per_sample *
+ (pcm_config.dataIntervalUs / 1000) * buffer_modifier;
if (data_mq_size <= 0) {
LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
<< ", SampleRateHz: " << pcm_config.sampleRateHz
<< ", ChannelMode: " << toString(pcm_config.channelMode)
<< ", BitsPerSample: "
<< static_cast<int>(pcm_config.bitsPerSample)
+ << ", BytesPerSample: " << bytes_per_sample
<< ", DataIntervalUs: " << pcm_config.dataIntervalUs
<< ", SessionType: " << toString(session_type_);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index fc54c70..1fb0e41 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -37,7 +37,7 @@
namespace audio {
static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
- .sampleRateHz = {16000, 24000, 44100, 48000, 88200, 96000},
+ .sampleRateHz = {16000, 24000, 32000, 44100, 48000, 88200, 96000},
.channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
.bitsPerSample = {16, 24, 32},
.dataIntervalUs = {},
@@ -115,6 +115,20 @@
.octetsPerFrame = {40}};
// Default Supported Codecs
+// LC3 24_2: sample rate: 24 kHz, frame duration: 10 ms, octets per frame: 60
+static const Lc3Capabilities kLc3Capability_24_2 = {
+ .samplingFrequencyHz = {24000},
+ .frameDurationUs = {10000},
+ .octetsPerFrame = {60}};
+
+// Default Supported Codecs
+// LC3 32_2: sample rate: 32 kHz, frame duration: 10 ms, octets per frame: 80
+static const Lc3Capabilities kLc3Capability_32_2 = {
+ .samplingFrequencyHz = {32000},
+ .frameDurationUs = {10000},
+ .octetsPerFrame = {80}};
+
+// Default Supported Codecs
// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
static const Lc3Capabilities kLc3Capability_48_4 = {
.samplingFrequencyHz = {48000},
@@ -122,7 +136,8 @@
.octetsPerFrame = {120}};
static const std::vector<Lc3Capabilities> supportedLc3CapabilityList = {
- kLc3Capability_48_4, kLc3Capability_16_2, kLc3Capability_16_1};
+ kLc3Capability_48_4, kLc3Capability_32_2, kLc3Capability_24_2,
+ kLc3Capability_16_2, kLc3Capability_16_1};
static AudioLocation stereoAudio = static_cast<AudioLocation>(
static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
diff --git a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
index ac17d6d..572a8b6 100644
--- a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
+++ b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
@@ -25,9 +25,8 @@
// Helper library to implement the IBootControl HAL using the misc partition.
class BootControl {
- using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
-
public:
+ using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
bool Init();
unsigned int GetNumberSlots();
unsigned int GetCurrentSlot();
diff --git a/boot/1.1/default/boot_control/include/private/boot_control_definition.h b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
index 8f02111..57c2f73 100644
--- a/boot/1.1/default/boot_control/include/private/boot_control_definition.h
+++ b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <stdint.h>
+
+#include <bootloader_message/bootloader_message.h>
/**
* The A/B-specific bootloader message structure (4-KiB).
diff --git a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
index c38f257..05f136e 100644
--- a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
+++ b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
@@ -1,4 +1,5 @@
/*
+
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +20,7 @@
#include <vector>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/hardware/boot/1.1/IBootControl.h>
#include <android/hardware/boot/1.1/types.h>
#include <gmock/gmock.h>
@@ -37,9 +39,21 @@
using ::android::hardware::boot::V1_1::MergeStatus;
using ::testing::Contains;
+bool IsVirtualAbEnabled();
+
+#define SKIP_IF_NON_VIRTUAL_AB() \
+ do { \
+ if (!IsVirtualAbEnabled()) GTEST_SKIP() << "Test for Virtual A/B devices only"; \
+ } while (0)
+
+bool IsVirtualAbEnabled() {
+ return android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
+}
+
class BootHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
+ SKIP_IF_NON_VIRTUAL_AB();
boot = IBootControl::getService(GetParam());
ASSERT_NE(boot, nullptr);
diff --git a/boot/aidl/Android.bp b/boot/aidl/Android.bp
new file mode 100644
index 0000000..be38245
--- /dev/null
+++ b/boot/aidl/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.boot",
+ vendor_available: true,
+ srcs: ["android/hardware/boot/*.aidl"],
+ stability: "vintf",
+ recovery_available: true,
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl
new file mode 100644
index 0000000..c8ab51e
--- /dev/null
+++ b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.boot;
+@VintfStability
+interface IBootControl {
+ int getActiveBootSlot();
+ int getCurrentSlot();
+ int getNumberSlots();
+ android.hardware.boot.MergeStatus getSnapshotMergeStatus();
+ String getSuffix(in int slot);
+ boolean isSlotBootable(in int slot);
+ boolean isSlotMarkedSuccessful(in int slot);
+ void markBootSuccessful();
+ void setActiveBootSlot(in int slot);
+ void setSlotAsUnbootable(in int slot);
+ void setSnapshotMergeStatus(in android.hardware.boot.MergeStatus status);
+ const int INVALID_SLOT = -1;
+ const int COMMAND_FAILED = -2;
+}
diff --git a/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl
new file mode 100644
index 0000000..53c6204
--- /dev/null
+++ b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.boot;
+@Backing(type="int") @VintfStability
+enum MergeStatus {
+ NONE = 0,
+ UNKNOWN = 1,
+ SNAPSHOTTED = 2,
+ MERGING = 3,
+ CANCELLED = 4,
+}
diff --git a/boot/aidl/android/hardware/boot/IBootControl.aidl b/boot/aidl/android/hardware/boot/IBootControl.aidl
new file mode 100644
index 0000000..6c9e8ce
--- /dev/null
+++ b/boot/aidl/android/hardware/boot/IBootControl.aidl
@@ -0,0 +1,158 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package android.hardware.boot;
+
+import android.hardware.boot.MergeStatus;
+
+@VintfStability
+interface IBootControl {
+ const int INVALID_SLOT = -1;
+ const int COMMAND_FAILED = -2;
+ /**
+ * Returns the active slot to boot into on the next boot. If
+ * setActiveBootSlot() has been called, the getter function should return the
+ * same slot as the one provided in the last setActiveBootSlot() call.
+ * The returned value is always guaranteed to be strictly less than the
+ * value returned by getNumberSlots. Slots start at 0 and finish at
+ * getNumberSlots() - 1. For instance, a system with A/B must return 0 or 1.
+ * @return the active slot to boot into on the next boot.
+ */
+ int getActiveBootSlot();
+
+ /**
+ * getCurrentSlot() returns the slot number of that the current boot is booted
+ * from, for example slot number 0 (Slot A). It is assumed that if the current
+ * slot is A, then the block devices underlying B can be accessed directly
+ * without any risk of corruption.
+ * The returned value is always guaranteed to be strictly less than the
+ * value returned by getNumberSlots. Slots start at 0 and finish at
+ * getNumberSlots() - 1. The value returned here must match the suffix passed
+ * from the bootloader, regardless of which slot is active or successful.
+ * @return the slot number of that the current boot is booted
+ */
+ int getCurrentSlot();
+
+ /**
+ * getNumberSlots() returns the number of available slots.
+ * For instance, a system with a single set of partitions must return
+ * 1, a system with A/B must return 2, A/B/C -> 3 and so on. A system with
+ * less than two slots doesn't support background updates, for example if
+ * running from a virtual machine with only one copy of each partition for the
+ * purpose of testing.
+ * @return number of available slots
+ */
+ int getNumberSlots();
+
+ /**
+ * Returns whether a snapshot-merge of any dynamic partition is in progress.
+ *
+ * This function must return the merge status set by the last setSnapshotMergeStatus call and
+ * recorded by the bootloader with one exception. If the partitions are being flashed from the
+ * bootloader such that the pending merge must be canceled (for example, if the super partition
+ * is being flashed), this function must return CANCELLED.
+ *
+ * @param out success True if the merge status is read successfully, false otherwise.
+ * @return Merge status.
+ */
+ MergeStatus getSnapshotMergeStatus();
+
+ /**
+ * getSuffix() returns the string suffix used by partitions that correspond to
+ * the slot number passed in as a parameter. The bootloader must pass the
+ * suffix of the currently active slot either through a kernel command line
+ * property at androidboot.slot_suffix, or the device tree at
+ * /firmware/android/slot_suffix.
+ * @return suffix for the input slot, or the empty string "" if slot
+ * does not match an existing slot.
+ */
+ String getSuffix(in int slot);
+
+ /**
+ * isSlotBootable() returns if the slot passed in parameter is bootable. Note
+ * that slots can be made unbootable by both the bootloader and by the OS
+ * using setSlotAsUnbootable.
+ * @return true if the slot is bootable, false if it's not.
+ * @throws service specific error INVALID_SLOT if slot is invalid.
+ */
+ boolean isSlotBootable(in int slot);
+
+ /**
+ * isSlotMarkedSuccessful() returns if the slot passed in parameter has been
+ * marked as successful using markBootSuccessful. Note that only the current
+ * slot can be marked as successful but any slot can be queried.
+ * @return true if the slot has been marked as successful, false if it has
+ * not.
+ * @throws service specific error INVALID_SLOT if slot is invalid.
+ */
+ boolean isSlotMarkedSuccessful(in int slot);
+
+ /**
+ * markBootSuccessful() marks the current slot as having booted successfully.
+ *
+ * @throws Service specific error COMMAND_FAILED if command failed.
+ */
+ void markBootSuccessful();
+
+ /**
+ * setActiveBootSlot() marks the slot passed in parameter as the active boot
+ * slot (see getCurrentSlot for an explanation of the "slot" parameter). This
+ * overrides any previous call to setSlotAsUnbootable.
+ * @throws Service specific error INVALID_SLOT if slot is invalid, or COMMAND_FAILED if
+ * operation failed.
+ */
+ void setActiveBootSlot(in int slot);
+
+ /**
+ * setSlotAsUnbootable() marks the slot passed in parameter as
+ * an unbootable. This can be used while updating the contents of the slot's
+ * partitions, so that the system must not attempt to boot a known bad set up.
+ * @throws Service specific error INVALID_SLOT if slot is invalid, or COMMAND_FAILED if
+ * operation failed.
+ */
+ void setSlotAsUnbootable(in int slot);
+
+ /**
+ * Sets whether a snapshot-merge of any dynamic partition is in progress.
+ *
+ * After the merge status is set to a given value, subsequent calls to
+ * getSnapshotMergeStatus must return the set value.
+ *
+ * The merge status must be persistent across reboots. That is, getSnapshotMergeStatus
+ * must return the same value after a reboot if the merge status is not altered in any way
+ * (e.g. set by setSnapshotMergeStatus or set to CANCELLED by bootloader).
+ *
+ * Read/write access to the merge status must be atomic. When the HAL is processing a
+ * setSnapshotMergeStatus call, all subsequent calls to getSnapshotMergeStatus must block until
+ * setSnapshotMergeStatus has returned.
+ *
+ * A MERGING state indicates that dynamic partitions are partially comprised by blocks in the
+ * userdata partition.
+ *
+ * When the merge status is set to MERGING, the following operations must be prohibited from the
+ * bootloader:
+ * - Flashing or erasing "userdata" or "metadata".
+ *
+ * The following operations may be prohibited when the status is set to MERGING. If not
+ * prohibited, it is recommended that the user receive a warning.
+ * - Changing the active slot (e.g. via "fastboot set_active")
+ *
+ * @param status Merge status.
+ *
+ * @throws service specific error COMMAND_FAILED if operation failed.
+ */
+ void setSnapshotMergeStatus(in MergeStatus status);
+}
diff --git a/boot/aidl/android/hardware/boot/MergeStatus.aidl b/boot/aidl/android/hardware/boot/MergeStatus.aidl
new file mode 100644
index 0000000..16ac85f
--- /dev/null
+++ b/boot/aidl/android/hardware/boot/MergeStatus.aidl
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package android.hardware.boot;
+
+@VintfStability
+@Backing(type="int")
+enum MergeStatus {
+ /**
+ * No snapshot or merge is in progress.
+ */
+ NONE = 0,
+ /**
+ * The merge status could not be determined.
+ */
+ UNKNOWN,
+ /**
+ * Partitions are being snapshotted, but no merge has been started.
+ */
+ SNAPSHOTTED,
+ /**
+ * At least one partition has merge is in progress.
+ */
+ MERGING,
+ /**
+ * A merge was in progress, but it was canceled by the bootloader.
+ */
+ CANCELLED,
+}
diff --git a/boot/aidl/client/Android.bp b/boot/aidl/client/Android.bp
new file mode 100644
index 0000000..db4a7ea
--- /dev/null
+++ b/boot/aidl/client/Android.bp
@@ -0,0 +1,31 @@
+
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+ name: "libboot_control_client",
+ srcs: [
+ "BootControlClient.cpp"
+ ],
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: ["android.hardware.boot-V1-ndk"],
+ recovery_available: true,
+ shared_libs: [
+ "android.hardware.boot-V1-ndk",
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot@1.2",
+ "libhidlbase",
+ "libbinder_ndk",
+ "libbase",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/boot/aidl/client/BootControlClient.cpp b/boot/aidl/client/BootControlClient.cpp
new file mode 100644
index 0000000..28070eb
--- /dev/null
+++ b/boot/aidl/client/BootControlClient.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BootControlClient.h>
+
+#include <aidl/android/hardware/boot/IBootControl.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <android/hardware/boot/1.2/IBootControl.h>
+#include "utils/StrongPointer.h"
+
+#define CONCAT(x, y) x##y
+
+#define LOG_NDK_STATUS(x) \
+ do { \
+ const auto CONCAT(status, __COUNTER__) = x; \
+ if (!CONCAT(status, __COUNTER__).isOk()) { \
+ LOG(ERROR) << #x << " failed " << CONCAT(status, __COUNTER__).getDescription(); \
+ } \
+ } while (0)
+
+using aidl::android::hardware::boot::MergeStatus;
+
+std::ostream& operator<<(std::ostream& os, MergeStatus status) {
+ switch (status) {
+ case MergeStatus::NONE:
+ os << "MergeStatus::NONE";
+ break;
+ case MergeStatus::UNKNOWN:
+ os << "MergeStatus::UNKNOWN";
+ break;
+ case MergeStatus::SNAPSHOTTED:
+ os << "MergeStatus::SNAPSHOTTED";
+ break;
+ case MergeStatus::MERGING:
+ os << "MergeStatus::MERGING";
+ break;
+ case MergeStatus::CANCELLED:
+ os << "MergeStatus::CANCELLED";
+ break;
+ default:
+ os << static_cast<int>(status);
+ break;
+ }
+ return os;
+}
+
+namespace android::hal {
+class BootControlClientAidl final : public BootControlClient {
+ using IBootControl = ::aidl::android::hardware::boot::IBootControl;
+
+ public:
+ BootControlClientAidl(std::shared_ptr<IBootControl> module) : module_(module) {}
+
+ BootControlVersion GetVersion() const override { return BootControlVersion::BOOTCTL_AIDL; }
+
+ ~BootControlClientAidl() = default;
+ virtual int32_t GetNumSlots() const {
+ int32_t ret = -1;
+ LOG_NDK_STATUS(module_->getNumberSlots(&ret));
+ return ret;
+ }
+
+ int32_t GetCurrentSlot() const {
+ int32_t ret = -1;
+ LOG_NDK_STATUS(module_->getCurrentSlot(&ret));
+ return ret;
+ }
+ MergeStatus getSnapshotMergeStatus() const {
+ MergeStatus status = MergeStatus::UNKNOWN;
+ LOG_NDK_STATUS(module_->getSnapshotMergeStatus(&status));
+ return status;
+ }
+ std::string GetSuffix(int32_t slot) const {
+ std::string ret;
+ const auto status = module_->getSuffix(slot, &ret);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ return {};
+ }
+ return ret;
+ }
+
+ std::optional<bool> IsSlotBootable(int32_t slot) const {
+ bool ret = false;
+ const auto status = module_->isSlotBootable(slot, &ret);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ return {};
+ }
+ return ret;
+ }
+
+ CommandResult MarkSlotUnbootable(int32_t slot) {
+ const auto status = module_->setSlotAsUnbootable(slot);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+
+ CommandResult SetActiveBootSlot(int slot) {
+ const auto status = module_->setActiveBootSlot(slot);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+ int GetActiveBootSlot() const {
+ int ret = -1;
+ LOG_NDK_STATUS(module_->getActiveBootSlot(&ret));
+ return ret;
+ }
+
+ // Check if |slot| is marked boot successfully.
+ std::optional<bool> IsSlotMarkedSuccessful(int slot) const {
+ bool ret = false;
+ const auto status = module_->isSlotMarkedSuccessful(slot, &ret);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ return {};
+ }
+ return ret;
+ }
+
+ CommandResult MarkBootSuccessful() {
+ const auto status = module_->markBootSuccessful();
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+
+ CommandResult SetSnapshotMergeStatus(aidl::android::hardware::boot::MergeStatus merge_status) {
+ const auto status = module_->setSnapshotMergeStatus(merge_status);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+
+ private:
+ const std::shared_ptr<IBootControl> module_;
+};
+
+using namespace android::hardware::boot;
+
+class BootControlClientHIDL final : public BootControlClient {
+ public:
+ BootControlClientHIDL(android::sp<V1_0::IBootControl> module_v1,
+ android::sp<V1_1::IBootControl> module_v1_1,
+ android::sp<V1_2::IBootControl> module_v1_2)
+ : module_v1_(module_v1), module_v1_1_(module_v1_1), module_v1_2_(module_v1_2) {
+ CHECK(module_v1_ != nullptr);
+ }
+ BootControlVersion GetVersion() const override {
+ if (module_v1_2_ != nullptr) {
+ return BootControlVersion::BOOTCTL_V1_2;
+ } else if (module_v1_1_ != nullptr) {
+ return BootControlVersion::BOOTCTL_V1_1;
+ } else {
+ return BootControlVersion::BOOTCTL_V1_0;
+ }
+ }
+ int32_t GetNumSlots() const {
+ const auto ret = module_v1_->getNumberSlots();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return ret.withDefault(-1);
+ }
+
+ int32_t GetCurrentSlot() const {
+ const auto ret = module_v1_->getCurrentSlot();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return ret.withDefault(-1);
+ }
+
+ std::string GetSuffix(int32_t slot) const {
+ std::string suffix;
+ const auto ret = module_v1_->getSuffix(
+ slot,
+ [&](const ::android::hardware::hidl_string& slotSuffix) { suffix = slotSuffix; });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ }
+ return suffix;
+ }
+
+ std::optional<bool> IsSlotBootable(int32_t slot) const {
+ const auto ret = module_v1_->isSlotBootable(slot);
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ return {};
+ }
+ const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+ if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+ return {};
+ }
+ return bool_result == V1_0::BoolResult::TRUE;
+ }
+
+ CommandResult MarkSlotUnbootable(int32_t slot) {
+ CommandResult result;
+ const auto ret =
+ module_v1_->setSlotAsUnbootable(slot, [&](const V1_0::CommandResult& error) {
+ result.success = error.success;
+ result.errMsg = error.errMsg;
+ });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ }
+ return result;
+ }
+
+ CommandResult SetActiveBootSlot(int32_t slot) {
+ CommandResult result;
+ const auto ret = module_v1_->setActiveBootSlot(slot, [&](const V1_0::CommandResult& error) {
+ result.success = error.success;
+ result.errMsg = error.errMsg;
+ });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ }
+ return result;
+ }
+
+ CommandResult MarkBootSuccessful() {
+ CommandResult result;
+ const auto ret = module_v1_->markBootSuccessful([&](const V1_0::CommandResult& error) {
+ result.success = error.success;
+ result.errMsg = error.errMsg;
+ });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return result;
+ }
+
+ std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const {
+ const auto ret = module_v1_->isSlotMarkedSuccessful(slot);
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ return {};
+ }
+ const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+ if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+ return {};
+ }
+ return bool_result == V1_0::BoolResult::TRUE;
+ }
+
+ MergeStatus getSnapshotMergeStatus() const {
+ if (module_v1_1_ == nullptr) {
+ LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.1";
+ return MergeStatus::UNKNOWN;
+ }
+ const auto ret = module_v1_1_->getSnapshotMergeStatus();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return static_cast<MergeStatus>(
+ ret.withDefault(static_cast<V1_1::MergeStatus>(MergeStatus::UNKNOWN)));
+ }
+
+ CommandResult SetSnapshotMergeStatus(MergeStatus merge_status) {
+ if (module_v1_1_ == nullptr) {
+ return {.success = false,
+ .errMsg = "setSnapshotMergeStatus is unsupported, requires at least boot v1.1"};
+ }
+ const auto ret =
+ module_v1_1_->setSnapshotMergeStatus(static_cast<V1_1::MergeStatus>(merge_status));
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+ << " failed " << ret.description();
+ }
+ return {.success = ret.isOk(), .errMsg = ret.description()};
+ }
+
+ int32_t GetActiveBootSlot() const {
+ if (module_v1_2_ == nullptr) {
+ LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.2";
+ return -1;
+ }
+ const auto ret = module_v1_2_->getActiveBootSlot();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return ret.withDefault(-1);
+ }
+
+ private:
+ android::sp<V1_0::IBootControl> module_v1_;
+ android::sp<V1_1::IBootControl> module_v1_1_;
+ android::sp<V1_2::IBootControl> module_v1_2_;
+};
+
+std::unique_ptr<BootControlClient> BootControlClient::WaitForService() {
+ const auto instance_name =
+ std::string(::aidl::android::hardware::boot::IBootControl::descriptor) + "/default";
+
+ if (auto module = ::aidl::android::hardware::boot::IBootControl::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str())));
+ module != nullptr) {
+ LOG(INFO) << "Using AIDL version of IBootControl";
+ return std::make_unique<BootControlClientAidl>(module);
+ }
+ LOG(INFO) << "AIDL IBootControl not available, falling back to HIDL.";
+
+ android::sp<V1_0::IBootControl> v1_0_module;
+ android::sp<V1_1::IBootControl> v1_1_module;
+ android::sp<V1_2::IBootControl> v1_2_module;
+ v1_0_module = V1_0::IBootControl::getService();
+ if (v1_0_module == nullptr) {
+ LOG(ERROR) << "Error getting bootctrl v1.0 module.";
+ return nullptr;
+ }
+ v1_1_module = V1_1::IBootControl::castFrom(v1_0_module);
+ v1_2_module = V1_2::IBootControl::castFrom(v1_0_module);
+ if (v1_2_module != nullptr) {
+ LOG(INFO) << "Using HIDL version 1.2 of IBootControl";
+ } else if (v1_1_module != nullptr) {
+ LOG(INFO) << "Using HIDL version 1.1 of IBootControl";
+ } else {
+ LOG(INFO) << "Using HIDL version 1.0 of IBootControl";
+ }
+
+ return std::make_unique<BootControlClientHIDL>(v1_0_module, v1_1_module, v1_2_module);
+}
+
+} // namespace android::hal
diff --git a/boot/aidl/client/include/BootControlClient.h b/boot/aidl/client/include/BootControlClient.h
new file mode 100644
index 0000000..472e82e
--- /dev/null
+++ b/boot/aidl/client/include/BootControlClient.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BOOT_CONTROL_CLIENT_H_
+#define __BOOT_CONTROL_CLIENT_H_
+
+#include <aidl/android/hardware/boot/MergeStatus.h>
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+
+namespace android::hal {
+
+struct CommandResult {
+ bool success;
+ std::string errMsg;
+ constexpr bool IsOk() const { return success; }
+};
+
+enum class BootControlVersion { BOOTCTL_V1_0, BOOTCTL_V1_1, BOOTCTL_V1_2, BOOTCTL_AIDL };
+
+class BootControlClient {
+ public:
+ using MergeStatus = aidl::android::hardware::boot::MergeStatus;
+ virtual ~BootControlClient() = default;
+ virtual BootControlVersion GetVersion() const = 0;
+ // Return the number of update slots in the system. A system will normally
+ // have two slots, named "A" and "B" in the documentation, but sometimes
+ // images running from other media can have only one slot, like some USB
+ // image. Systems with only one slot won't be able to update.
+ [[nodiscard]] virtual int32_t GetNumSlots() const = 0;
+
+ // Return the slot where we are running the system from. On success, the
+ // result is a number between 0 and GetNumSlots() - 1. Otherwise, log an error
+ // and return kInvalidSlot.
+ [[nodiscard]] virtual int32_t GetCurrentSlot() const = 0;
+
+ // Return string suffix for input slot. Usually, for slot 0 the suffix is _a, and for slot 1 the
+ // suffix is _b.
+ [[nodiscard]] virtual std::string GetSuffix(int32_t slot) const = 0;
+
+ // Returns whether the passed |slot| is marked as bootable. Returns false if
+ // the slot is invalid.
+ [[nodiscard]] virtual std::optional<bool> IsSlotBootable(int32_t slot) const = 0;
+
+ // Mark the specified slot unbootable. No other slot flags are modified.
+ // Returns true on success.
+ [[nodiscard]] virtual CommandResult MarkSlotUnbootable(int32_t slot) = 0;
+
+ // Set the passed |slot| as the preferred boot slot. Returns whether it
+ // succeeded setting the active slot. If succeeded, on next boot the
+ // bootloader will attempt to load the |slot| marked as active. Note that this
+ // method doesn't change the value of GetCurrentSlot() on the current boot.
+ // Return true if operation succeeded.
+ [[nodiscard]] virtual CommandResult SetActiveBootSlot(int32_t slot) = 0;
+
+ // Check if |slot| is marked boot successfully. Return empty optional if the RPC call failed.
+ [[nodiscard]] virtual std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const = 0;
+
+ // Mark boot as successful. Return an error message if operation failed.
+ [[nodiscard]] virtual CommandResult MarkBootSuccessful() = 0;
+
+ // Added in IBootControl v1.1
+ // Return the current merge status.
+ [[nodiscard]] virtual MergeStatus getSnapshotMergeStatus() const = 0;
+
+ // Set snapshot merge status, return true if succeeded.
+ [[nodiscard]] virtual CommandResult SetSnapshotMergeStatus(MergeStatus status) = 0;
+
+ // Added in IBootControl v1.2
+ // Get the active slot. In other words, the slot which will be used on
+ // next system reboot. This should match the |slot| parameter of last
+ // successful call to |SetActiveBootSlot|.
+ // Return 0xFFFFFFFF if underlying HAL doesn't support this operation.
+ [[nodiscard]] virtual int32_t GetActiveBootSlot() const = 0;
+
+ [[nodiscard]] static std::unique_ptr<BootControlClient> WaitForService();
+};
+
+} // namespace android::hal
+
+#endif
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
new file mode 100644
index 0000000..6aefae8
--- /dev/null
+++ b/boot/aidl/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.boot-service.default",
+ defaults: ["libboot_control_defaults"],
+ relative_install_path: "hw",
+ init_rc: ["boot-default.rc"],
+ vintf_fragments: ["boot-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot-V1-ndk",
+ ],
+ static_libs: [
+ "libboot_control",
+ ],
+ srcs: ["main.cpp", "BootControl.cpp"],
+}
diff --git a/boot/aidl/default/BootControl.cpp b/boot/aidl/default/BootControl.cpp
new file mode 100644
index 0000000..4e3c21b
--- /dev/null
+++ b/boot/aidl/default/BootControl.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BootControl.h"
+#include <cstdint>
+
+#include <android-base/logging.h>
+
+using HIDLMergeStatus = ::android::bootable::BootControl::MergeStatus;
+using ndk::ScopedAStatus;
+
+namespace aidl::android::hardware::boot {
+
+BootControl::BootControl() {
+ CHECK(impl_.Init());
+}
+
+ScopedAStatus BootControl::getActiveBootSlot(int32_t* _aidl_return) {
+ *_aidl_return = impl_.GetActiveBootSlot();
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getCurrentSlot(int32_t* _aidl_return) {
+ *_aidl_return = impl_.GetCurrentSlot();
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getNumberSlots(int32_t* _aidl_return) {
+ *_aidl_return = impl_.GetNumberSlots();
+ return ScopedAStatus::ok();
+}
+
+namespace {
+
+static constexpr MergeStatus ToAIDLMergeStatus(HIDLMergeStatus status) {
+ switch (status) {
+ case HIDLMergeStatus::NONE:
+ return MergeStatus::NONE;
+ case HIDLMergeStatus::UNKNOWN:
+ return MergeStatus::UNKNOWN;
+ case HIDLMergeStatus::SNAPSHOTTED:
+ return MergeStatus::SNAPSHOTTED;
+ case HIDLMergeStatus::MERGING:
+ return MergeStatus::MERGING;
+ case HIDLMergeStatus::CANCELLED:
+ return MergeStatus::CANCELLED;
+ }
+}
+
+static constexpr HIDLMergeStatus ToHIDLMergeStatus(MergeStatus status) {
+ switch (status) {
+ case MergeStatus::NONE:
+ return HIDLMergeStatus::NONE;
+ case MergeStatus::UNKNOWN:
+ return HIDLMergeStatus::UNKNOWN;
+ case MergeStatus::SNAPSHOTTED:
+ return HIDLMergeStatus::SNAPSHOTTED;
+ case MergeStatus::MERGING:
+ return HIDLMergeStatus::MERGING;
+ case MergeStatus::CANCELLED:
+ return HIDLMergeStatus::CANCELLED;
+ }
+}
+
+}
+
+ScopedAStatus BootControl::getSnapshotMergeStatus(MergeStatus* _aidl_return) {
+ *_aidl_return = ToAIDLMergeStatus(impl_.GetSnapshotMergeStatus());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getSuffix(int32_t in_slot, std::string* _aidl_return) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ *_aidl_return = impl_.GetSuffix(in_slot);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotBootable(int32_t in_slot, bool* _aidl_return) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ *_aidl_return = impl_.IsSlotBootable(in_slot);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ *_aidl_return = impl_.IsSlotMarkedSuccessful(in_slot);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::markBootSuccessful() {
+ if (!impl_.MarkBootSuccessful()) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setActiveBootSlot(int32_t in_slot) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ if (!impl_.SetActiveBootSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSlotAsUnbootable(int32_t in_slot) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ if (!impl_.SetSlotAsUnbootable(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSnapshotMergeStatus(MergeStatus in_status) {
+ if (!impl_.SetSnapshotMergeStatus(ToHIDLMergeStatus(in_status))) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/BootControl.h b/boot/aidl/default/BootControl.h
new file mode 100644
index 0000000..54cd32d
--- /dev/null
+++ b/boot/aidl/default/BootControl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/boot/BnBootControl.h>
+#include <libboot_control/libboot_control.h>
+
+namespace aidl::android::hardware::boot {
+
+class BootControl final : public BnBootControl {
+ public:
+ BootControl();
+ ::ndk::ScopedAStatus getActiveBootSlot(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getCurrentSlot(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getNumberSlots(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getSnapshotMergeStatus(
+ ::aidl::android::hardware::boot::MergeStatus* _aidl_return) override;
+ ::ndk::ScopedAStatus getSuffix(int32_t in_slot, std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus isSlotBootable(int32_t in_slot, bool* _aidl_return) override;
+ ::ndk::ScopedAStatus isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) override;
+ ::ndk::ScopedAStatus markBootSuccessful() override;
+ ::ndk::ScopedAStatus setActiveBootSlot(int32_t in_slot) override;
+ ::ndk::ScopedAStatus setSlotAsUnbootable(int32_t in_slot) override;
+ ::ndk::ScopedAStatus setSnapshotMergeStatus(
+ ::aidl::android::hardware::boot::MergeStatus in_status) override;
+
+ private:
+ ::android::bootable::BootControl impl_;
+};
+
+} // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/boot-default.rc b/boot/aidl/default/boot-default.rc
new file mode 100644
index 0000000..589f803
--- /dev/null
+++ b/boot/aidl/default/boot-default.rc
@@ -0,0 +1,5 @@
+service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default
+ class early_hal
+ user root
+ group root
+
diff --git a/boot/aidl/default/boot-default.xml b/boot/aidl/default/boot-default.xml
new file mode 100644
index 0000000..23ccc4e
--- /dev/null
+++ b/boot/aidl/default/boot-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.boot</name>
+ <fqname>IBootControl/default</fqname>
+ </hal>
+</manifest>
diff --git a/boot/aidl/default/main.cpp b/boot/aidl/default/main.cpp
new file mode 100644
index 0000000..70b284e
--- /dev/null
+++ b/boot/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BootControl.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::boot::BootControl;
+using aidl::android::hardware::boot::IBootControl;
+
+int main(int, char* argv[]) {
+ android::base::InitLogging(argv, android::base::KernelLogger);
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<IBootControl> service = ndk::SharedRefBase::make<BootControl>();
+
+ const std::string instance = std::string(BootControl::descriptor) + "/default";
+ auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+ LOG(INFO) << "IBootControl AIDL service running...";
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 2979b11..e006091 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -146,6 +146,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.boot</name>
+ <interface>
+ <name>IBootControl</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.broadcastradio</name>
<version>1.0-1</version>
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
index 6ab83f2..1200115 100644
--- a/confirmationui/support/Android.bp
+++ b/confirmationui/support/Android.bp
@@ -36,7 +36,7 @@
],
export_include_dirs: [
"include",
- ]
+ ],
}
cc_test {
@@ -56,6 +56,5 @@
"libhidlbase",
],
test_suites: ["general-tests"],
- clang: true,
- cflags: [ "-O0" ],
+ cflags: ["-O0"],
}
diff --git a/dumpstate/aidl/Android.bp b/dumpstate/aidl/Android.bp
index 22d836b..4de5da3 100644
--- a/dumpstate/aidl/Android.bp
+++ b/dumpstate/aidl/Android.bp
@@ -33,10 +33,5 @@
java: {
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
index b197eae..3797c69 100644
--- a/gnss/aidl/Android.bp
+++ b/gnss/aidl/Android.bp
@@ -32,11 +32,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index fcc1f98..9e4f7c7 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -19,11 +19,17 @@
#include "GnssMeasurementInterface.h"
#include <aidl/android/hardware/gnss/BnGnss.h>
#include <log/log.h>
+#include "DeviceFileReader.h"
+#include "GnssRawMeasurementParser.h"
+#include "GnssReplayUtils.h"
#include "Utils.h"
namespace aidl::android::hardware::gnss {
using Utils = ::android::hardware::gnss::common::Utils;
+using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils;
+using GnssRawMeasurementParser = ::android::hardware::gnss::common::GnssRawMeasurementParser;
+using DeviceFileReader = ::android::hardware::gnss::common::DeviceFileReader;
std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
@@ -63,9 +69,22 @@
mIsActive = true;
mThread = std::thread([this, enableCorrVecOutputs]() {
while (mIsActive == true) {
- auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
- this->reportMeasurement(measurement);
-
+ std::string rawMeasurementStr = "";
+ if (ReplayUtils::hasGnssDeviceFile() &&
+ ReplayUtils::isGnssRawMeasurement(
+ rawMeasurementStr =
+ DeviceFileReader::Instance().getGnssRawMeasurementData())) {
+ ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(),
+ rawMeasurementStr.c_str());
+ auto measurement =
+ GnssRawMeasurementParser::getMeasurementFromStrs(rawMeasurementStr);
+ if (measurement != nullptr) {
+ this->reportMeasurement(*measurement);
+ }
+ } else {
+ auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
+ this->reportMeasurement(measurement);
+ }
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
}
});
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index a1d3123..dda8a44 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -38,9 +38,14 @@
"v2_1/GnssDebug.cpp",
"v2_1/GnssMeasurement.cpp",
"v2_1/GnssMeasurementCorrections.cpp",
+ "DeviceFileReader.cpp",
+ "FixLocationParser.cpp",
+ "GnssRawMeasurementParser.cpp",
+ "GnssReplayUtils.cpp",
"MockLocation.cpp",
- "Utils.cpp",
"NmeaFixInfo.cpp",
+ "ParseUtils.cpp",
+ "Utils.cpp",
],
export_include_dirs: ["include"],
shared_libs: [
diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp
new file mode 100644
index 0000000..dfc086a
--- /dev/null
+++ b/gnss/common/utils/default/DeviceFileReader.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "DeviceFileReader.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) {
+ char inputBuffer[INPUT_BUFFER_SIZE];
+ std::string deviceFilePath = "";
+ if (command == CMD_GET_LOCATION) {
+ deviceFilePath = ReplayUtils::getFixedLocationPath();
+ } else if (command == CMD_GET_RAWMEASUREMENT) {
+ deviceFilePath = ReplayUtils::getGnssPath();
+ } else {
+ // Invalid command
+ return;
+ }
+
+ int mGnssFd = open(deviceFilePath.c_str(), O_RDWR | O_NONBLOCK);
+
+ if (mGnssFd == -1) {
+ return;
+ }
+
+ int bytes_write = write(mGnssFd, command.c_str(), command.size());
+ if (bytes_write <= 0) {
+ close(mGnssFd);
+ return;
+ }
+
+ struct epoll_event ev, events[1];
+ ev.data.fd = mGnssFd;
+ ev.events = EPOLLIN;
+ int epoll_fd = epoll_create1(0);
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev);
+ int bytes_read = -1;
+ std::string inputStr = "";
+ int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs);
+
+ if (epoll_ret == -1) {
+ close(mGnssFd);
+ return;
+ }
+ while (true) {
+ memset(inputBuffer, 0, INPUT_BUFFER_SIZE);
+ bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE);
+ if (bytes_read <= 0) {
+ break;
+ }
+ s_buffer_ += std::string(inputBuffer, bytes_read);
+ }
+ close(mGnssFd);
+
+ // Trim end of file mark(\n\n\n\n).
+ auto pos = s_buffer_.find("\n\n\n\n");
+ if (pos != std::string::npos) {
+ inputStr = s_buffer_.substr(0, pos);
+ s_buffer_ = s_buffer_.substr(pos + 4);
+ } else {
+ return;
+ }
+
+ // Cache the injected data.
+ if (command == CMD_GET_LOCATION) {
+ // TODO validate data
+ data_[CMD_GET_LOCATION] = inputStr;
+ } else if (command == CMD_GET_RAWMEASUREMENT) {
+ if (ReplayUtils::isGnssRawMeasurement(inputStr)) {
+ data_[CMD_GET_RAWMEASUREMENT] = inputStr;
+ }
+ }
+}
+
+std::string DeviceFileReader::getLocationData() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ getDataFromDeviceFile(CMD_GET_LOCATION, 20);
+ return data_[CMD_GET_LOCATION];
+}
+
+std::string DeviceFileReader::getGnssRawMeasurementData() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ getDataFromDeviceFile(CMD_GET_RAWMEASUREMENT, 20);
+ return data_[CMD_GET_RAWMEASUREMENT];
+}
+
+DeviceFileReader::DeviceFileReader() {}
+
+DeviceFileReader::~DeviceFileReader() {}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/common/utils/default/FixLocationParser.cpp b/gnss/common/utils/default/FixLocationParser.cpp
new file mode 100644
index 0000000..f0177b4
--- /dev/null
+++ b/gnss/common/utils/default/FixLocationParser.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FixLocationParser.h"
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+std::unique_ptr<V2_0::GnssLocation> FixLocationParser::getLocationFromInputStr(
+ const std::string& locationStr) {
+ /*
+ * Fix,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps,
+ * AccuracyMeters,BearingDegrees,UnixTimeMillis,SpeedAccuracyMps,BearingAccuracyDegrees,
+ * elapsedRealtimeNanos
+ */
+ if (locationStr.empty()) {
+ return nullptr;
+ }
+ std::vector<std::string> locationStrRecords;
+ ParseUtils::splitStr(locationStr, LINE_SEPARATOR, locationStrRecords);
+ if (locationStrRecords.empty()) {
+ return nullptr;
+ }
+
+ std::vector<std::string> locationValues;
+ ParseUtils::splitStr(locationStrRecords[0], COMMA_SEPARATOR, locationValues);
+ if (locationValues.size() < 12) {
+ return nullptr;
+ }
+ V2_0::ElapsedRealtime elapsedRealtime = {
+ .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+ V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+ .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
+ // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+ // In an actual implementation provide an estimate of the synchronization uncertainty
+ // or don't set the field.
+ .timeUncertaintyNs = 1020400};
+
+ V1_0::GnssLocation locationV1 = {
+ .gnssLocationFlags = 0xFF,
+ .latitudeDegrees = ParseUtils::tryParseDouble(locationValues[2], 0),
+ .longitudeDegrees = ParseUtils::tryParseDouble(locationValues[3], 0),
+ .altitudeMeters = ParseUtils::tryParseDouble(locationValues[4], 0),
+ .speedMetersPerSec = ParseUtils::tryParsefloat(locationValues[5], 0),
+ .bearingDegrees = ParseUtils::tryParsefloat(locationValues[7], 0),
+ .horizontalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0),
+ .verticalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0),
+ .speedAccuracyMetersPerSecond = ParseUtils::tryParsefloat(locationValues[9], 0),
+ .bearingAccuracyDegrees = ParseUtils::tryParsefloat(locationValues[10], 0),
+ .timestamp = ParseUtils::tryParseLongLong(locationValues[8], 0)};
+
+ V2_0::GnssLocation locationV2 = {.v1_0 = locationV1, .elapsedRealtime = elapsedRealtime};
+ return std::make_unique<V2_0::GnssLocation>(locationV2);
+}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/common/utils/default/GnssRawMeasurementParser.cpp b/gnss/common/utils/default/GnssRawMeasurementParser.cpp
new file mode 100644
index 0000000..c066229
--- /dev/null
+++ b/gnss/common/utils/default/GnssRawMeasurementParser.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GnssRawMeasurementParser.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+using aidl::android::hardware::gnss::ElapsedRealtime;
+using aidl::android::hardware::gnss::GnssClock;
+using aidl::android::hardware::gnss::GnssConstellationType;
+using aidl::android::hardware::gnss::GnssData;
+using aidl::android::hardware::gnss::GnssMeasurement;
+using aidl::android::hardware::gnss::GnssMultipathIndicator;
+using aidl::android::hardware::gnss::GnssSignalType;
+
+using ParseUtils = ::android::hardware::gnss::common::ParseUtils;
+
+std::unordered_map<std::string, int> GnssRawMeasurementParser::getColumnIdNameMappingFromHeader(
+ const std::string& header) {
+ std::vector<std::string> columnNames;
+ std::unordered_map<std::string, int> columnNameIdMapping;
+ std::string s = header;
+ // Trim left spaces
+ s.erase(s.begin(),
+ std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
+ // Trim right spaces
+ s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); })
+ .base(),
+ s.end());
+ // Remove comment symbol, start from `Raw`.
+ s = s.substr(s.find("Raw"));
+
+ ParseUtils::splitStr(s, COMMA_SEPARATOR, columnNames);
+ int columnId = 0;
+ for (auto& name : columnNames) {
+ columnNameIdMapping[name] = columnId++;
+ }
+
+ return columnNameIdMapping;
+}
+
+int GnssRawMeasurementParser::getClockFlags(
+ const std::vector<std::string>& rawMeasurementRecordValues,
+ const std::unordered_map<std::string, int>& columnNameIdMapping) {
+ int clockFlags = 0;
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("LeapSecond")].empty()) {
+ clockFlags |= GnssClock::HAS_LEAP_SECOND;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullBiasNanos")].empty()) {
+ clockFlags |= GnssClock::HAS_FULL_BIAS;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasNanos")].empty()) {
+ clockFlags |= GnssClock::HAS_BIAS;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")].empty()) {
+ clockFlags |= GnssClock::HAS_BIAS_UNCERTAINTY;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")].empty()) {
+ clockFlags |= GnssClock::HAS_DRIFT;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftUncertaintyNanosPerSecond")]
+ .empty()) {
+ clockFlags |= GnssClock::HAS_DRIFT_UNCERTAINTY;
+ }
+ return clockFlags;
+}
+
+int GnssRawMeasurementParser::getElapsedRealtimeFlags(
+ const std::vector<std::string>& rawMeasurementRecordValues,
+ const std::unordered_map<std::string, int>& columnNameIdMapping) {
+ int elapsedRealtimeFlags = ElapsedRealtime::HAS_TIMESTAMP_NS;
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")].empty()) {
+ elapsedRealtimeFlags |= ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS;
+ }
+ return elapsedRealtimeFlags;
+}
+
+int GnssRawMeasurementParser::getRawMeasurementFlags(
+ const std::vector<std::string>& rawMeasurementRecordValues,
+ const std::unordered_map<std::string, int>& columnNameIdMapping) {
+ int rawMeasurementFlags = 0;
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("SnrInDb")].empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_SNR;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierFrequencyHz")].empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_FREQUENCY;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierCycles")].empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_CYCLES;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhase")].empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhaseUncertainty")].empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("AgcDb")].empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasNanos")].empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasUncertaintyNanos")]
+ .empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at("SatelliteInterSignalBiasNanos")]
+ .empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB;
+ }
+ if (!rawMeasurementRecordValues[columnNameIdMapping.at(
+ "SatelliteInterSignalBiasUncertaintyNanos")]
+ .empty()) {
+ rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY;
+ }
+ // HAS_SATELLITE_PVT and HAS_CORRELATION_VECTOR fields currently not in rawmeasurement
+ // output, need add them later.
+ return rawMeasurementFlags;
+}
+
+GnssConstellationType GnssRawMeasurementParser::getGnssConstellationType(int constellationType) {
+ GnssConstellationType gnssConstellationType =
+ aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN;
+
+ switch (constellationType) {
+ case 1:
+ gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GPS;
+ break;
+ case 2:
+ gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::SBAS;
+ break;
+ case 3:
+ gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GLONASS;
+ break;
+ case 4:
+ gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::QZSS;
+ break;
+ case 5:
+ gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::BEIDOU;
+ break;
+ case 6:
+ gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GALILEO;
+ break;
+ default:
+ gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN;
+ }
+
+ return gnssConstellationType;
+}
+
+std::unique_ptr<GnssData> GnssRawMeasurementParser::getMeasurementFromStrs(
+ std::string& rawMeasurementStr) {
+ /*
+ * Raw,utcTimeMillis,TimeNanos,LeapSecond,TimeUncertaintyNanos,FullBiasNanos,BiasNanos,
+ * BiasUncertaintyNanos,DriftNanosPerSecond,DriftUncertaintyNanosPerSecond,
+ * HardwareClockDiscontinuityCount,Svid,TimeOffsetNanos,State,ReceivedSvTimeNanos,
+ * ReceivedSvTimeUncertaintyNanos,Cn0DbHz,PseudorangeRateMetersPerSecond,
+ * PseudorangeRateUncertaintyMetersPerSecond,AccumulatedDeltaRangeState,
+ * AccumulatedDeltaRangeMeters,AccumulatedDeltaRangeUncertaintyMeters,CarrierFrequencyHz,
+ * CarrierCycles,CarrierPhase,CarrierPhaseUncertainty,MultipathIndicator,SnrInDb,
+ * ConstellationType,AgcDb,BasebandCn0DbHz,FullInterSignalBiasNanos,
+ * FullInterSignalBiasUncertaintyNanos,SatelliteInterSignalBiasNanos,
+ * SatelliteInterSignalBiasUncertaintyNanos,CodeType,ChipsetElapsedRealtimeNanos
+ */
+ ALOGD("Parsing %zu bytes rawMeasurementStr.", rawMeasurementStr.size());
+ if (rawMeasurementStr.empty()) {
+ return nullptr;
+ }
+ std::vector<std::string> rawMeasurementStrRecords;
+ ParseUtils::splitStr(rawMeasurementStr, LINE_SEPARATOR, rawMeasurementStrRecords);
+ if (rawMeasurementStrRecords.size() <= 1) {
+ ALOGE("Raw GNSS Measurements parser failed. (No records) ");
+ return nullptr;
+ }
+
+ // Get the column name mapping from the header.
+ std::unordered_map<std::string, int> columnNameIdMapping =
+ getColumnIdNameMappingFromHeader(rawMeasurementStrRecords[0]);
+
+ if (columnNameIdMapping.size() < 37 || !ParseUtils::isValidHeader(columnNameIdMapping)) {
+ ALOGE("Raw GNSS Measurements parser failed. (No header or missing columns.) ");
+ return nullptr;
+ }
+
+ // Set GnssClock from 1st record.
+ std::size_t pointer = 1;
+ std::vector<std::string> firstRecordValues;
+ ParseUtils::splitStr(rawMeasurementStrRecords[pointer], COMMA_SEPARATOR, firstRecordValues);
+ GnssClock clock = {
+ .gnssClockFlags = getClockFlags(firstRecordValues, columnNameIdMapping),
+ .timeNs = ParseUtils::tryParseLongLong(
+ firstRecordValues[columnNameIdMapping.at("TimeNanos")], 0),
+ .fullBiasNs = ParseUtils::tryParseLongLong(
+ firstRecordValues[columnNameIdMapping.at("FullBiasNanos")], 0),
+ .biasNs = ParseUtils::tryParseDouble(
+ firstRecordValues[columnNameIdMapping.at("BiasNanos")], 0),
+ .biasUncertaintyNs = ParseUtils::tryParseDouble(
+ firstRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")], 0),
+ .driftNsps = ParseUtils::tryParseDouble(
+ firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0),
+ .driftUncertaintyNsps = ParseUtils::tryParseDouble(
+ firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0),
+ .hwClockDiscontinuityCount = ParseUtils::tryParseInt(
+ firstRecordValues[columnNameIdMapping.at("HardwareClockDiscontinuityCount")],
+ 0)};
+
+ ElapsedRealtime timestamp = {
+ .flags = getElapsedRealtimeFlags(firstRecordValues, columnNameIdMapping),
+ .timestampNs = ParseUtils::tryParseLongLong(
+ firstRecordValues[columnNameIdMapping.at("ChipsetElapsedRealtimeNanos")]),
+ .timeUncertaintyNs = ParseUtils::tryParseDouble(
+ firstRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")], 0)};
+
+ std::vector<GnssMeasurement> measurementsVec;
+ for (pointer = 1; pointer < rawMeasurementStrRecords.size(); pointer++) {
+ std::vector<std::string> rawMeasurementValues;
+ std::string line = rawMeasurementStrRecords[pointer];
+ ParseUtils::splitStr(line, COMMA_SEPARATOR, rawMeasurementValues);
+ GnssSignalType signalType = {
+ .constellation = getGnssConstellationType(ParseUtils::tryParseInt(
+ rawMeasurementValues[columnNameIdMapping.at("ConstellationType")], 0)),
+ .carrierFrequencyHz = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at("CarrierFrequencyHz")], 0),
+ .codeType = rawMeasurementValues[columnNameIdMapping.at("CodeType")],
+ };
+ GnssMeasurement measurement = {
+ .flags = getRawMeasurementFlags(rawMeasurementValues, columnNameIdMapping),
+ .svid = ParseUtils::tryParseInt(
+ rawMeasurementValues[columnNameIdMapping.at("Svid")], 0),
+ .signalType = signalType,
+ .receivedSvTimeInNs = ParseUtils::tryParseLongLong(
+ rawMeasurementValues[columnNameIdMapping.at("ReceivedSvTimeNanos")], 0),
+ .receivedSvTimeUncertaintyInNs =
+ ParseUtils::tryParseLongLong(rawMeasurementValues[columnNameIdMapping.at(
+ "ReceivedSvTimeUncertaintyNanos")],
+ 0),
+ .antennaCN0DbHz = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at("Cn0DbHz")], 0),
+ .basebandCN0DbHz = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at("BasebandCn0DbHz")], 0),
+ .agcLevelDb = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at("AgcDb")], 0),
+ .pseudorangeRateMps =
+ ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at(
+ "PseudorangeRateMetersPerSecond")],
+ 0),
+ .pseudorangeRateUncertaintyMps = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at(
+ "PseudorangeRateUncertaintyMetersPerSecond")],
+ 0),
+ .accumulatedDeltaRangeState = ParseUtils::tryParseInt(
+ rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeState")],
+ 0),
+ .accumulatedDeltaRangeM = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeMeters")],
+ 0),
+ .accumulatedDeltaRangeUncertaintyM = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at(
+ "AccumulatedDeltaRangeUncertaintyMeters")],
+ 0),
+ .multipathIndicator = GnssMultipathIndicator::UNKNOWN, // Not in GnssLogger yet.
+ .state = ParseUtils::tryParseInt(
+ rawMeasurementValues[columnNameIdMapping.at("State")], 0),
+ .fullInterSignalBiasNs = ParseUtils::tryParseDouble(rawMeasurementValues[31], 0),
+ .fullInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at("FullInterSignalBiasNanos")],
+ 0),
+ .satelliteInterSignalBiasNs =
+ ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at(
+ "SatelliteInterSignalBiasNanos")],
+ 0),
+ .satelliteInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble(
+ rawMeasurementValues[columnNameIdMapping.at(
+ "SatelliteInterSignalBiasUncertaintyNanos")],
+ 0),
+ .satellitePvt = {},
+ .correlationVectors = {}};
+ measurementsVec.push_back(measurement);
+ }
+
+ GnssData gnssData = {
+ .measurements = measurementsVec, .clock = clock, .elapsedRealtime = timestamp};
+ return std::make_unique<GnssData>(gnssData);
+}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp
new file mode 100644
index 0000000..d6769bd
--- /dev/null
+++ b/gnss/common/utils/default/GnssReplayUtils.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GnssReplayUtils.h"
+
+#include <array>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+std::string ReplayUtils::getGnssPath() {
+ std::array<char, PROPERTY_VALUE_MAX> devname_value;
+
+ devname_value.fill(0);
+ if (property_get("debug.location.gnss.devname", devname_value.begin(), NULL) > 0) {
+ return devname_value.begin();
+ }
+
+ devname_value.fill(0);
+ if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) {
+ return devname_value.begin();
+ }
+
+ return GNSS_PATH;
+}
+
+std::string ReplayUtils::getFixedLocationPath() {
+ std::array<char, PROPERTY_VALUE_MAX> devname_value;
+
+ devname_value.fill(0);
+ if (property_get("debug.location.fixedlocation.devname", devname_value.begin(), NULL) > 0) {
+ return devname_value.begin();
+ }
+
+ devname_value.fill(0);
+ if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) {
+ return devname_value.begin();
+ }
+
+ return FIXED_LOCATION_PATH;
+}
+
+bool ReplayUtils::hasGnssDeviceFile() {
+ struct stat sb;
+ return stat(getGnssPath().c_str(), &sb) != -1;
+}
+
+bool ReplayUtils::hasFixedLocationDeviceFile() {
+ struct stat sb;
+ return stat(getFixedLocationPath().c_str(), &sb) != -1;
+}
+
+bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) {
+ // TODO: add more logic check to by pass invalid data.
+ return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos);
+}
+
+bool ReplayUtils::isNMEA(const std::string& inputStr) {
+ return !inputStr.empty() && (inputStr.find("$GPRMC,", 0) != std::string::npos ||
+ inputStr.find("$GPRMA,", 0) != std::string::npos);
+}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/common/utils/default/ParseUtils.cpp b/gnss/common/utils/default/ParseUtils.cpp
new file mode 100644
index 0000000..648edf7
--- /dev/null
+++ b/gnss/common/utils/default/ParseUtils.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ParseUtils.h>
+#include <sstream>
+#include <stdexcept>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+int ParseUtils::tryParseInt(const std::string& s, int defaultVal) {
+ if (s.empty()) {
+ return defaultVal;
+ } else {
+ return std::stoi(s);
+ }
+}
+
+float ParseUtils::tryParsefloat(const std::string& s, float defaultVal) {
+ if (s.empty()) {
+ return defaultVal;
+ } else {
+ return std::stof(s);
+ }
+}
+
+double ParseUtils::tryParseDouble(const std::string& s, double defaultVal) {
+ if (s.empty()) {
+ return defaultVal;
+ } else {
+ return std::stod(s);
+ }
+}
+
+long ParseUtils::tryParseLong(const std::string& s, long defaultVal) {
+ if (s.empty()) {
+ return defaultVal;
+ } else {
+ return std::stol(s);
+ }
+}
+
+long long ParseUtils::tryParseLongLong(const std::string& s, long long defaultVal) {
+ if (s.empty()) {
+ return defaultVal;
+ } else {
+ return std::stoll(s);
+ }
+}
+
+void ParseUtils::splitStr(const std::string& line, const char& delimiter,
+ std::vector<std::string>& out) {
+ std::istringstream iss(line);
+ std::string item;
+ while (std::getline(iss, item, delimiter)) {
+ out.push_back(item);
+ }
+}
+
+bool ParseUtils::isValidHeader(const std::unordered_map<std::string, int>& columnNameIdMapping) {
+ std::vector<std::string> requiredHeaderColumns = {"Raw",
+ "utcTimeMillis",
+ "TimeNanos",
+ "LeapSecond",
+ "TimeUncertaintyNanos",
+ "FullBiasNanos",
+ "BiasNanos",
+ "BiasUncertaintyNanos",
+ "DriftNanosPerSecond",
+ "DriftUncertaintyNanosPerSecond",
+ "HardwareClockDiscontinuityCount",
+ "Svid",
+ "TimeOffsetNanos",
+ "State",
+ "ReceivedSvTimeNanos",
+ "ReceivedSvTimeUncertaintyNanos",
+ "Cn0DbHz",
+ "PseudorangeRateMetersPerSecond",
+ "PseudorangeRateUncertaintyMetersPerSecond",
+ "AccumulatedDeltaRangeState",
+ "AccumulatedDeltaRangeMeters",
+ "AccumulatedDeltaRangeUncertaintyMeters",
+ "CarrierFrequencyHz",
+ "CarrierCycles",
+ "CarrierPhase",
+ "CarrierPhaseUncertainty",
+ "MultipathIndicator",
+ "SnrInDb",
+ "ConstellationType",
+ "AgcDb",
+ "BasebandCn0DbHz",
+ "FullInterSignalBiasNanos",
+ "FullInterSignalBiasUncertaintyNanos",
+ "SatelliteInterSignalBiasNanos",
+ "SatelliteInterSignalBiasUncertaintyNanos",
+ "CodeType",
+ "ChipsetElapsedRealtimeNanos"};
+
+ for (const auto& columnName : requiredHeaderColumns) {
+ if (columnNameIdMapping.find(columnName) == columnNameIdMapping.end()) {
+ ALOGE("Missing column %s in header.", columnName.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h
index 22afee1..489413e 100644
--- a/gnss/common/utils/default/include/Constants.h
+++ b/gnss/common/utils/default/include/Constants.h
@@ -34,6 +34,19 @@
const float kGloG1FreqHz = 1602.0 * 1e6;
const float kIrnssL5FreqHz = 1176.45 * 1e6;
+// Location replay constants
+constexpr char GNSS_PATH[] = "/dev/gnss0";
+constexpr char FIXED_LOCATION_PATH[] = "/dev/gnss1";
+constexpr int INPUT_BUFFER_SIZE = 256;
+constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION";
+constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT";
+constexpr char LINE_SEPARATOR = '\n';
+constexpr char COMMA_SEPARATOR = ',';
+constexpr char GPGA_RECORD_TAG[] = "$GPGGA";
+constexpr char GPRMC_RECORD_TAG[] = "$GPRMC";
+constexpr double TIMESTAMP_EPSILON = 0.001;
+constexpr int MIN_COL_NUM = 13;
+
} // namespace common
} // namespace gnss
} // namespace hardware
diff --git a/gnss/common/utils/default/include/DeviceFileReader.h b/gnss/common/utils/default/include/DeviceFileReader.h
new file mode 100644
index 0000000..c2a5c5f
--- /dev/null
+++ b/gnss/common/utils/default/include/DeviceFileReader.h
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef android_hardware_gnss_common_default_DeviceFileReader_H_
+#define android_hardware_gnss_common_default_DeviceFileReader_H_
+
+#include <log/log.h>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include "Constants.h"
+#include "GnssReplayUtils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+class DeviceFileReader {
+ public:
+ static DeviceFileReader& Instance() {
+ static DeviceFileReader reader;
+ return reader;
+ }
+ std::string getLocationData();
+ std::string getGnssRawMeasurementData();
+ void getDataFromDeviceFile(const std::string& command, int mMinIntervalMs);
+
+ private:
+ DeviceFileReader();
+ ~DeviceFileReader();
+ std::unordered_map<std::string, std::string> data_;
+ std::string s_buffer_;
+ std::mutex mMutex;
+};
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_common_default_DeviceFileReader_H_
\ No newline at end of file
diff --git a/gnss/common/utils/default/include/FixLocationParser.h b/gnss/common/utils/default/include/FixLocationParser.h
new file mode 100644
index 0000000..19748a9
--- /dev/null
+++ b/gnss/common/utils/default/include/FixLocationParser.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_gnss_common_default_FixLocationParser_H_
+#define android_hardware_gnss_common_default_FixLocationParser_H_
+
+#include <android/hardware/gnss/2.0/IGnss.h>
+
+#include <utils/SystemClock.h>
+#include <string>
+#include <vector>
+
+#include <Constants.h>
+#include <Utils.h>
+#include <log/log.h>
+#include "Constants.h"
+#include "ParseUtils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+struct FixLocationParser {
+ public:
+ static std::unique_ptr<V2_0::GnssLocation> getLocationFromInputStr(const std::string& inputStr);
+};
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_common_default_FixLocationParser_H_
diff --git a/gnss/common/utils/default/include/GnssRawMeasurementParser.h b/gnss/common/utils/default/include/GnssRawMeasurementParser.h
new file mode 100644
index 0000000..7d6b4ef
--- /dev/null
+++ b/gnss/common/utils/default/include/GnssRawMeasurementParser.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_gnss_common_default_GnssRawMeasurementParser_H_
+#define android_hardware_gnss_common_default_GnssRawMeasurementParser_H_
+
+#include <aidl/android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include <string>
+#include <unordered_map>
+
+#include "Constants.h"
+#include "ParseUtils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+struct GnssRawMeasurementParser {
+ static std::unique_ptr<aidl::android::hardware::gnss::GnssData> getMeasurementFromStrs(
+ std::string& rawMeasurementStr);
+ static int getClockFlags(const std::vector<std::string>& rawMeasurementRecordValues,
+ const std::unordered_map<std::string, int>& columnNameIdMapping);
+ static int getElapsedRealtimeFlags(
+ const std::vector<std::string>& rawMeasurementRecordValues,
+ const std::unordered_map<std::string, int>& columnNameIdMapping);
+ static int getRawMeasurementFlags(
+ const std::vector<std::string>& rawMeasurementRecordValues,
+ const std::unordered_map<std::string, int>& columnNameIdMapping);
+ static std::unordered_map<std::string, int> getColumnIdNameMappingFromHeader(
+ const std::string& header);
+ static aidl::android::hardware::gnss::GnssConstellationType getGnssConstellationType(
+ int constellationType);
+};
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_common_default_GnssRawMeasurementParser_H_
\ No newline at end of file
diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h
new file mode 100644
index 0000000..d1bbed4
--- /dev/null
+++ b/gnss/common/utils/default/include/GnssReplayUtils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_gnss_common_GnssReplayUtils_H_
+#define android_hardware_gnss_common_GnssReplayUtils_H_
+
+#include <cutils/properties.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <log/log.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <chrono>
+#include <string>
+#include <thread>
+
+#include "Constants.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+struct ReplayUtils {
+ static std::string getGnssPath();
+
+ static std::string getFixedLocationPath();
+
+ static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs);
+
+ static bool hasGnssDeviceFile();
+
+ static bool hasFixedLocationDeviceFile();
+
+ static bool isGnssRawMeasurement(const std::string& inputStr);
+
+ static bool isNMEA(const std::string& inputStr);
+};
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_common_GnssReplayUtils_H_
diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h
index c96eece..5c27045 100644
--- a/gnss/common/utils/default/include/NmeaFixInfo.h
+++ b/gnss/common/utils/default/include/NmeaFixInfo.h
@@ -27,13 +27,6 @@
namespace gnss {
namespace common {
-constexpr char GPGA_RECORD_TAG[] = "$GPGGA";
-constexpr char GPRMC_RECORD_TAG[] = "$GPRMC";
-constexpr char LINE_SEPARATOR = '\n';
-constexpr char COMMA_SEPARATOR = ',';
-constexpr double TIMESTAMP_EPSILON = 0.001;
-constexpr int MIN_COL_NUM = 13;
-
/** Helper class to parse and store the GNSS fix details information. */
class NmeaFixInfo {
private:
diff --git a/gnss/common/utils/default/include/ParseUtils.h b/gnss/common/utils/default/include/ParseUtils.h
new file mode 100644
index 0000000..3a56313
--- /dev/null
+++ b/gnss/common/utils/default/include/ParseUtils.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_gnss_common_default_ParseUtils_H_
+#define android_hardware_gnss_common_default_ParseUtils_H_
+
+#include <log/log.h>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+struct ParseUtils {
+ static int tryParseInt(const std::string& s, int defaultVal = 0);
+ static float tryParsefloat(const std::string& s, float defaultVal = 0.0);
+ static double tryParseDouble(const std::string& s, double defaultVal = 0.0);
+ static long tryParseLong(const std::string& s, long defaultVal = 0);
+ static long long tryParseLongLong(const std::string& s, long long defaultVal = 0);
+ static void splitStr(const std::string& line, const char& delimiter,
+ std::vector<std::string>& out);
+ static bool isValidHeader(const std::unordered_map<std::string, int>& columnNameIdMapping);
+};
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_common_default_ParseUtils_H_
\ No newline at end of file
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
index 48cab99..473e587 100644
--- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -30,13 +30,15 @@
#include <cutils/properties.h>
+#include "DeviceFileReader.h"
+#include "FixLocationParser.h"
#include "GnssAntennaInfo.h"
#include "GnssConfiguration.h"
#include "GnssDebug.h"
#include "GnssMeasurement.h"
#include "GnssMeasurementCorrections.h"
+#include "GnssReplayUtils.h"
#include "MockLocation.h"
-#include "NmeaFixInfo.h"
#include "Utils.h"
namespace android::hardware::gnss::common::implementation {
@@ -159,53 +161,13 @@
template <class T_IGnss>
std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() {
- char inputBuffer[INPUT_BUFFER_SIZE];
- if (!mHardwareModeChecked) {
- // default using gnss0
- const char * gnss_dev_path = GNSS_PATH;
- char devname_value[PROPERTY_VALUE_MAX] = "";
- if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) {
- gnss_dev_path = devname_value;
- ALOGD("using %s instead of the default %s", gnss_dev_path, GNSS_PATH);
- }
-
- mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK);
- if (mGnssFd == -1) {
- ALOGW("Failed to open %s errno: %d", gnss_dev_path, errno);
- }
- mHardwareModeChecked = true;
- }
-
- if (mGnssFd == -1) {
+ mHardwareModeChecked = true;
+ if (!ReplayUtils::hasFixedLocationDeviceFile()) {
return nullptr;
}
-
- int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION));
- if (bytes_write <= 0) {
- return nullptr;
- }
-
- struct epoll_event ev, events[1];
- ev.data.fd = mGnssFd;
- ev.events = EPOLLIN;
- int epoll_fd = epoll_create1(0);
- epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev);
- int bytes_read = -1;
- std::string inputStr = "";
- int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs);
-
- if (epoll_ret == -1) {
- return nullptr;
- }
- while (true) {
- memset(inputBuffer, 0, INPUT_BUFFER_SIZE);
- bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE);
- if (bytes_read <= 0) {
- break;
- }
- inputStr += std::string(inputBuffer, bytes_read);
- }
- return NmeaFixInfo::getLocationFromInputStr(inputStr);
+ std::string inputStr =
+ ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData();
+ return FixLocationParser::getLocationFromInputStr(inputStr);
}
template <class T_IGnss>
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
index 0171dd6..3527cca 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
@@ -25,7 +25,6 @@
name: "libhwc2on1adapter",
vendor: true,
- clang: true,
cflags: [
"-Wall",
"-Werror",
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
index 3965d12..d613ba9 100644
--- a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
@@ -25,7 +25,6 @@
name: "libhwc2onfbadapter",
vendor: true,
- clang: true,
cflags: [
"-Wall",
"-Wextra",
@@ -37,6 +36,9 @@
],
header_libs: ["libhardware_headers"],
- shared_libs: ["liblog", "libsync"],
+ shared_libs: [
+ "liblog",
+ "libsync",
+ ],
export_include_dirs: ["include"],
}
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index f55a6b7..61277ee 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -2001,6 +2001,11 @@
mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
ASSERT_EQ(Error::UNSUPPORTED,
mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+
+ // Keep optional metadata types below and populate the encoded metadata vec
+ // with some arbitrary different metadata because the common gralloc4::decode*()
+ // functions do not distinguish between an empty vec and bad value.
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(Dataspace::SRGB_LINEAR, &vec));
ASSERT_EQ(Error::UNSUPPORTED,
mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
ASSERT_EQ(Error::UNSUPPORTED,
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index 86bca69..4acf38a 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -36,11 +36,6 @@
enabled: true,
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index 8eab997..0d426da 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -159,3 +159,70 @@
init_rc: ["android.hardware.health-service.example_recovery.rc"],
overrides: ["charger.recovery"],
}
+
+// AIDL Fuzz version of libhealth2impl.
+cc_library_static {
+ name: "fuzz_libhealth_aidl_impl",
+ defaults: [
+ "libhealth_aidl_common_defaults",
+ "libhealth_aidl_charger_defaults",
+ ],
+ recovery_available: true,
+ export_include_dirs: ["include"],
+ export_static_lib_headers: [
+ "libbatterymonitor",
+ ],
+ srcs: [
+ "ChargerUtils.cpp",
+ "health-convert.cpp",
+ "HalHealthLoop.cpp",
+ "Health.cpp",
+ "LinkedCallback.cpp",
+ ],
+ target: {
+ recovery: {
+ exclude_srcs: [
+ "ChargerUtils.cpp",
+ ],
+ },
+ },
+}
+
+cc_fuzz {
+ name: "android.hardware.health-service.aidl_fuzzer",
+ defaults: [
+ "libhealth_aidl_impl_user",
+ ],
+ static_libs: [
+ "android.hardware.health-V1-ndk",
+ "libbase",
+ "libbinder_random_parcel",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "fuzz_libhealth_aidl_impl",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: ["fuzzer.cpp"],
+ fuzz_config: {
+ cc: [
+ "hamzeh@google.com",
+ ],
+ },
+}
diff --git a/health/aidl/default/fuzzer.cpp b/health/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..b7c6d39
--- /dev/null
+++ b/health/aidl/default/fuzzer.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <health-impl/Health.h>
+#include <health/utils.h>
+
+using aidl::android::hardware::health::Health;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto config = std::make_unique<healthd_config>();
+ ::android::hardware::health::InitHealthdConfig(config.get());
+ auto binder = ndk::SharedRefBase::make<Health>("default", std::move(config));
+
+ fuzzService(binder->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/health/storage/aidl/Android.bp b/health/storage/aidl/Android.bp
index 4cd9263..c614efb 100644
--- a/health/storage/aidl/Android.bp
+++ b/health/storage/aidl/Android.bp
@@ -33,11 +33,6 @@
java: {
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index e3b8191..907a6b6 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -23,9 +23,6 @@
platform_apis: true,
},
ndk: {
- vndk: {
- enabled: true,
- },
apps_enabled: false,
},
},
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 942e4d7..dc010d6 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -59,16 +59,3 @@
],
require_root: true,
}
-
-java_test_host {
- name: "IdentityCredentialImplementedTest",
- libs: [
- "tradefed",
- "vts-core-tradefed-harness",
- ],
- srcs: ["src/**/*.java"],
- test_suites: [
- "vts",
- ],
- test_config: "IdentityCredentialImplementedTest.xml",
-}
diff --git a/identity/aidl/vts/AndroidTest.xml b/identity/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..67132b0
--- /dev/null
+++ b/identity/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs VtsHalIdentityTargetTest.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push"
+ value="VtsHalIdentityTargetTest->/data/local/tmp/VtsHalIdentityTargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalIdentityTargetTest" />
+ <option name="native-test-timeout" value="300000"/>
+ </test>
+</configuration>
diff --git a/identity/aidl/vts/IdentityCredentialImplementedTest.xml b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
deleted file mode 100644
index 1d76a74..0000000
--- a/identity/aidl/vts/IdentityCredentialImplementedTest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Runs IdentityCredentialImplementedTest">
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
-
- <test class="com.android.tradefed.testtype.HostTest" >
- <option name="jar" value="IdentityCredentialImplementedTest.jar" />
- </test>
-</configuration>
diff --git a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
deleted file mode 100644
index 19568af..0000000
--- a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.
- */
-package com.android.tests.security.identity;
-
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.platform.test.annotations.RequiresDevice;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class IdentityCredentialImplementedTest extends BaseHostJUnit4Test {
- // Returns the ro.vendor.api_level or 0 if not set.
- //
- // Throws NumberFormatException if ill-formatted.
- //
- // Throws DeviceNotAvailableException if device is not available.
- //
- private int getVendorApiLevel() throws NumberFormatException, DeviceNotAvailableException {
- String vendorApiLevelString =
- getDevice().executeShellCommand("getprop ro.vendor.api_level").trim();
- if (vendorApiLevelString.isEmpty()) {
- return 0;
- }
- return Integer.parseInt(vendorApiLevelString);
- }
-
- // As of Android 13 (API level 32), Identity Credential is required at feature version 202201
- // or newer.
- //
- @RequiresDevice
- @Test
- public void testIdentityCredentialIsImplemented() throws Exception {
- int vendorApiLevel = getVendorApiLevel();
- assumeTrue(vendorApiLevel >= 32);
-
- final String minimumFeatureVersionNeeded = "202201";
-
- String result = getDevice().executeShellCommand(
- "pm has-feature android.hardware.identity_credential "
- + minimumFeatureVersionNeeded);
- if (!result.trim().equals("true")) {
- fail("Identity Credential feature version " + minimumFeatureVersionNeeded
- + " required but not found");
- }
- }
-}
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 dd6b0f7..fb5048a 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -27,6 +27,7 @@
#include <openssl/mem.h>
#include <openssl/x509.h>
+#include <android-base/properties.h>
#include <cutils/properties.h>
#include <keymasterV4_0/attestation_record.h>
@@ -386,6 +387,31 @@
return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
}
+int get_vsr_api_level() {
+ int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+ if (vendor_api_level != -1) {
+ return vendor_api_level;
+ }
+
+ // Android S and older devices do not define ro.vendor.api_level
+ vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
+ if (vendor_api_level == -1) {
+ vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
+ }
+
+ int product_api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+ if (product_api_level == -1) {
+ product_api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+ EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
+ }
+
+ // VSR API level is the minimum of vendor_api_level and product_api_level.
+ if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
+ return product_api_level;
+ }
+ return vendor_api_level;
+}
+
bool is_gsi() {
char property_value[PROPERTY_VALUE_MAX] = {};
EXPECT_NE(property_get("ro.product.system.name", property_value, ""), 0);
@@ -3105,6 +3131,49 @@
}
/*
+ * EncryptionOperationsTest.AesCbcZeroInputSuccessb
+ *
+ * Verifies that keymaster generates correct output on zero-input with
+ * NonePadding mode
+ */
+TEST_P(EncryptionOperationsTest, AesCbcZeroInputSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE, PaddingMode::PKCS7)));
+
+ // Zero input message
+ string message = "";
+ for (auto padding : {PaddingMode::NONE, PaddingMode::PKCS7}) {
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(padding);
+ AuthorizationSet out_params;
+ string ciphertext1 = EncryptMessage(message, params, &out_params);
+ HidlBuf iv1 = CopyIv(out_params);
+ if (padding == PaddingMode::NONE)
+ EXPECT_EQ(message.size(), ciphertext1.size()) << "PaddingMode: " << padding;
+ else
+ EXPECT_EQ(message.size(), ciphertext1.size() - 16) << "PaddingMode: " << padding;
+
+ out_params.Clear();
+
+ string ciphertext2 = EncryptMessage(message, params, &out_params);
+ HidlBuf iv2 = CopyIv(out_params);
+ if (padding == PaddingMode::NONE)
+ EXPECT_EQ(message.size(), ciphertext2.size()) << "PaddingMode: " << padding;
+ else
+ EXPECT_EQ(message.size(), ciphertext2.size() - 16) << "PaddingMode: " << padding;
+
+ // IVs should be random
+ EXPECT_NE(iv1, iv2) << "PaddingMode: " << padding;
+
+ params.push_back(TAG_NONCE, iv1);
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext) << "PaddingMode: " << padding;
+ }
+}
+
+/*
* EncryptionOperationsTest.AesCallerNonce
*
* Verifies that AES caller-provided nonces work correctly.
@@ -4790,6 +4859,18 @@
INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest);
+using VsrRequirementTest = KeymasterHidlTest;
+
+TEST_P(VsrRequirementTest, Vsr13Test) {
+ int vsr_api_level = get_vsr_api_level();
+ if (vsr_api_level < 33) {
+ GTEST_SKIP() << "Applies only to VSR API level 33, this device is: " << vsr_api_level;
+ }
+ FAIL() << "VSR 13+ requires KeyMint version 2";
+}
+
+INSTANTIATE_KEYMASTER_HIDL_TEST(VsrRequirementTest);
+
} // namespace test
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index c4b6740..0fb6e4c 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: [
"1",
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
index c8973f3..e714212 100644
--- a/light/aidl/Android.bp
+++ b/light/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp
index daa10fd..d98fef0 100644
--- a/neuralnetworks/1.0/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.0/utils/src/Conversions.cpp
@@ -110,8 +110,9 @@
return NN_ERROR() << "Unable to convert invalid ashmem memory object with "
<< memory.handle()->numInts << " numInts, but expected 0";
}
+ auto fd = NN_TRY(nn::dupFd(memory.handle()->data[0]));
auto handle = nn::Memory::Ashmem{
- .fd = NN_TRY(nn::dupFd(memory.handle()->data[0])),
+ .fd = std::move(fd),
.size = static_cast<size_t>(memory.size()),
};
return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
@@ -137,12 +138,13 @@
}
if (memory.name() != "hardware_buffer_blob") {
- auto handle = nn::Memory::Unknown{
- .handle = NN_TRY(unknownHandleFromNativeHandle(memory.handle())),
+ auto handle = NN_TRY(unknownHandleFromNativeHandle(memory.handle()));
+ auto unknown = nn::Memory::Unknown{
+ .handle = std::move(handle),
.size = static_cast<size_t>(memory.size()),
.name = memory.name(),
};
- return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
+ return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(unknown)});
}
#ifdef __ANDROID__
@@ -245,19 +247,23 @@
}
GeneralResult<Operand> unvalidatedConvert(const hal::V1_0::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
+ .type = type,
.dimensions = operand.dimensions,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
+ .lifetime = lifetime,
+ .location = location,
};
}
GeneralResult<Operation> unvalidatedConvert(const hal::V1_0::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -298,26 +304,30 @@
}
}
+ auto operands = NN_TRY(unvalidatedConvert(model.operands));
auto main = Model::Subgraph{
- .operands = NN_TRY(unvalidatedConvert(model.operands)),
+ .operands = std::move(operands),
.operations = std::move(operations),
.inputIndexes = model.inputIndexes,
.outputIndexes = model.outputIndexes,
};
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
return Model{
.main = std::move(main),
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
};
}
GeneralResult<Request::Argument> unvalidatedConvert(const hal::V1_0::RequestArgument& argument) {
const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE
: Request::Argument::LifeTime::POOL;
+ const auto location = NN_TRY(unvalidatedConvert(argument.location));
return Request::Argument{
.lifetime = lifetime,
- .location = NN_TRY(unvalidatedConvert(argument.location)),
+ .location = location,
.dimensions = argument.dimensions,
};
}
@@ -328,9 +338,11 @@
pools.reserve(memories.size());
std::move(memories.begin(), memories.end(), std::back_inserter(pools));
+ auto inputs = NN_TRY(unvalidatedConvert(request.inputs));
+ auto outputs = NN_TRY(unvalidatedConvert(request.outputs));
return Request{
- .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
- .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
.pools = std::move(pools),
};
}
@@ -500,11 +512,13 @@
}
nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
+ const auto float32Performance = NN_TRY(unvalidatedConvert(
+ capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32)));
+ const auto quantized8Performance = NN_TRY(unvalidatedConvert(
+ capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM)));
return Capabilities{
- .float32Performance = NN_TRY(unvalidatedConvert(
- capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
- .quantized8Performance = NN_TRY(unvalidatedConvert(
- capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
+ .float32Performance = float32Performance,
+ .quantized8Performance = quantized8Performance,
};
}
@@ -517,20 +531,24 @@
}
nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
+ .type = type,
.dimensions = operand.dimensions,
.numberOfConsumers = 0,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
+ .lifetime = lifetime,
+ .location = location,
};
}
nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -572,13 +590,16 @@
operands[i].numberOfConsumers = numberOfConsumers[i];
}
+ auto operations = NN_TRY(unvalidatedConvert(model.main.operations));
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
return Model{
.operands = std::move(operands),
- .operations = NN_TRY(unvalidatedConvert(model.main.operations)),
+ .operations = std::move(operations),
.inputIndexes = model.main.inputIndexes,
.outputIndexes = model.main.outputIndexes,
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
};
}
@@ -589,9 +610,10 @@
<< "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
+ const auto location = NN_TRY(unvalidatedConvert(requestArgument.location));
return RequestArgument{
.hasNoValue = hasNoValue,
- .location = NN_TRY(unvalidatedConvert(requestArgument.location)),
+ .location = location,
.dimensions = requestArgument.dimensions,
};
}
@@ -606,10 +628,13 @@
<< "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
+ auto inputs = NN_TRY(unvalidatedConvert(request.inputs));
+ auto outputs = NN_TRY(unvalidatedConvert(request.outputs));
+ auto pools = NN_TRY(unvalidatedConvert(request.pools));
return Request{
- .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
- .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
- .pools = NN_TRY(unvalidatedConvert(request.pools)),
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
+ .pools = std::move(pools),
};
}
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 29b31d2..a41f37f 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -90,7 +90,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.1/utils/src/Conversions.cpp b/neuralnetworks/1.1/utils/src/Conversions.cpp
index 5bdbe31..887c8ec 100644
--- a/neuralnetworks/1.1/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.1/utils/src/Conversions.cpp
@@ -88,8 +88,9 @@
}
GeneralResult<Operation> unvalidatedConvert(const hal::V1_1::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -110,17 +111,20 @@
}
}
+ auto operands = NN_TRY(unvalidatedConvert(model.operands));
auto main = Model::Subgraph{
- .operands = NN_TRY(unvalidatedConvert(model.operands)),
+ .operands = std::move(operands),
.operations = std::move(operations),
.inputIndexes = model.inputIndexes,
.outputIndexes = model.outputIndexes,
};
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
return Model{
.main = std::move(main),
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
};
}
@@ -195,19 +199,23 @@
}
nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
+ const auto float32Performance = NN_TRY(unvalidatedConvert(
+ capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32)));
+ const auto quanitized8Performance = NN_TRY(unvalidatedConvert(
+ capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM)));
+ const auto relaxedFloat32toFloat16Performance =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
return Capabilities{
- .float32Performance = NN_TRY(unvalidatedConvert(
- capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
- .quantized8Performance = NN_TRY(unvalidatedConvert(
- capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
- .relaxedFloat32toFloat16Performance = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+ .float32Performance = float32Performance,
+ .quantized8Performance = quanitized8Performance,
+ .relaxedFloat32toFloat16Performance = relaxedFloat32toFloat16Performance,
};
}
nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -229,13 +237,16 @@
operands[i].numberOfConsumers = numberOfConsumers[i];
}
+ auto operations = NN_TRY(unvalidatedConvert(model.main.operations));
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
return Model{
.operands = std::move(operands),
- .operations = NN_TRY(unvalidatedConvert(model.main.operations)),
+ .operations = std::move(operations),
.inputIndexes = model.main.inputIndexes,
.outputIndexes = model.main.outputIndexes,
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
};
}
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index e9d4b76..7c1c118 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -58,7 +58,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index 62ec2ed..78d71cf 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -131,15 +131,18 @@
GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) {
+ const auto type = NN_TRY(unvalidatedConvert(operandPerformance.type));
+ const auto info = NN_TRY(unvalidatedConvert(operandPerformance.info));
return Capabilities::OperandPerformance{
- .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
- .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
+ .type = type,
+ .info = info,
};
}
GeneralResult<Operation> unvalidatedConvert(const hal::V1_2::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -154,14 +157,18 @@
}
GeneralResult<Operand> unvalidatedConvert(const hal::V1_2::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
+ auto extraParams = NN_TRY(unvalidatedConvert(operand.extraParams));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
+ .type = type,
.dimensions = operand.dimensions,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
- .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
+ .lifetime = lifetime,
+ .location = location,
+ .extraParams = std::move(extraParams),
};
}
@@ -196,19 +203,23 @@
}
}
+ auto operands = NN_TRY(unvalidatedConvert(model.operands));
auto main = Model::Subgraph{
- .operands = NN_TRY(unvalidatedConvert(model.operands)),
+ .operands = std::move(operands),
.operations = std::move(operations),
.inputIndexes = model.inputIndexes,
.outputIndexes = model.outputIndexes,
};
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
+ auto extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix));
return Model{
.main = std::move(main),
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = std::move(extensionNameToPrefix),
};
}
@@ -248,9 +259,10 @@
}
GeneralResult<Extension> unvalidatedConvert(const hal::V1_2::Extension& extension) {
+ auto operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes));
return Extension{
.name = extension.name,
- .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)),
+ .operandTypes = std::move(operandTypes),
};
}
@@ -406,35 +418,41 @@
}
nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
- std::vector<nn::Capabilities::OperandPerformance> operandPerformance;
- operandPerformance.reserve(capabilities.operandPerformance.asVector().size());
+ std::vector<nn::Capabilities::OperandPerformance> filteredOperandPerformances;
+ filteredOperandPerformances.reserve(capabilities.operandPerformance.asVector().size());
std::copy_if(capabilities.operandPerformance.asVector().begin(),
capabilities.operandPerformance.asVector().end(),
- std::back_inserter(operandPerformance),
+ std::back_inserter(filteredOperandPerformances),
[](const nn::Capabilities::OperandPerformance& operandPerformance) {
return compliantVersion(operandPerformance.type).has_value();
});
+ const auto relaxedFloat32toFloat16PerformanceScalar =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+ const auto relaxedFloat32toFloat16PerformanceTensor =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+ auto operandPerformance = NN_TRY(unvalidatedConvert(filteredOperandPerformances));
return Capabilities{
- .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
- .operandPerformance = NN_TRY(unvalidatedConvert(operandPerformance)),
+ .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
+ .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16PerformanceTensor,
+ .operandPerformance = std::move(operandPerformance),
};
}
nn::GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const nn::Capabilities::OperandPerformance& operandPerformance) {
+ const auto type = NN_TRY(unvalidatedConvert(operandPerformance.type));
+ const auto info = NN_TRY(unvalidatedConvert(operandPerformance.info));
return Capabilities::OperandPerformance{
- .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
- .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
+ .type = type,
+ .info = info,
};
}
nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -449,15 +467,19 @@
}
nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
+ auto extraParams = NN_TRY(unvalidatedConvert(operand.extraParams));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
+ .type = type,
.dimensions = operand.dimensions,
.numberOfConsumers = 0,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
- .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
+ .lifetime = lifetime,
+ .location = location,
+ .extraParams = std::move(extraParams),
};
}
@@ -482,15 +504,19 @@
operands[i].numberOfConsumers = numberOfConsumers[i];
}
+ auto operations = NN_TRY(unvalidatedConvert(model.main.operations));
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
+ auto extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix));
return Model{
.operands = std::move(operands),
- .operations = NN_TRY(unvalidatedConvert(model.main.operations)),
+ .operations = std::move(operations),
.inputIndexes = model.main.inputIndexes,
.outputIndexes = model.main.outputIndexes,
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = std::move(extensionNameToPrefix),
};
}
@@ -524,9 +550,10 @@
}
nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension) {
+ auto operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes));
return Extension{
.name = extension.name,
- .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)),
+ .operandTypes = std::move(operandTypes),
};
}
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 2177924..7e4b5bb 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -85,7 +85,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 3d783d9..fe38e61 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -1262,7 +1262,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index 09e9d80..4eeb414 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -133,28 +133,35 @@
auto table =
NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
+ const auto relaxedFloat32toFloat16PerformanceScalar =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+ const auto relaxedFloat32toFloat16PerformanceTensor =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+ const auto ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance));
+ const auto whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance));
return Capabilities{
- .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+ .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
+ .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16PerformanceTensor,
.operandPerformance = std::move(table),
- .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
- .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
+ .ifPerformance = ifPerformance,
+ .whilePerformance = whilePerformance,
};
}
GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
+ const auto type = NN_TRY(unvalidatedConvert(operandPerformance.type));
+ const auto info = NN_TRY(unvalidatedConvert(operandPerformance.info));
return Capabilities::OperandPerformance{
- .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
- .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
+ .type = type,
+ .info = info,
};
}
GeneralResult<Operation> unvalidatedConvert(const hal::V1_3::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -166,25 +173,34 @@
}
GeneralResult<Operand> unvalidatedConvert(const hal::V1_3::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
+ auto extraParams = NN_TRY(unvalidatedConvert(operand.extraParams));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
+ .type = type,
.dimensions = operand.dimensions,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
- .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
+ .lifetime = lifetime,
+ .location = location,
+ .extraParams = std::move(extraParams),
};
}
GeneralResult<Model> unvalidatedConvert(const hal::V1_3::Model& model) {
+ auto main = NN_TRY(unvalidatedConvert(model.main));
+ auto referenced = NN_TRY(unvalidatedConvert(model.referenced));
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
+ auto extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix));
return Model{
- .main = NN_TRY(unvalidatedConvert(model.main)),
- .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .main = std::move(main),
+ .referenced = std::move(referenced),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = std::move(extensionNameToPrefix),
};
}
@@ -204,8 +220,9 @@
}
}
+ auto operands = NN_TRY(unvalidatedConvert(subgraph.operands));
return Model::Subgraph{
- .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
+ .operands = std::move(operands),
.operations = std::move(operations),
.inputIndexes = subgraph.inputIndexes,
.outputIndexes = subgraph.outputIndexes,
@@ -225,10 +242,13 @@
}
GeneralResult<Request> unvalidatedConvert(const hal::V1_3::Request& request) {
+ auto inputs = NN_TRY(unvalidatedConvert(request.inputs));
+ auto outputs = NN_TRY(unvalidatedConvert(request.outputs));
+ auto pools = NN_TRY(unvalidatedConvert(request.pools));
return Request{
- .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
- .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
- .pools = NN_TRY(unvalidatedConvert(request.pools)),
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
+ .pools = std::move(pools),
};
}
@@ -463,37 +483,45 @@
}
nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
- std::vector<nn::Capabilities::OperandPerformance> operandPerformance;
- operandPerformance.reserve(capabilities.operandPerformance.asVector().size());
+ std::vector<nn::Capabilities::OperandPerformance> filteredOperandPerformances;
+ filteredOperandPerformances.reserve(capabilities.operandPerformance.asVector().size());
std::copy_if(capabilities.operandPerformance.asVector().begin(),
capabilities.operandPerformance.asVector().end(),
- std::back_inserter(operandPerformance),
+ std::back_inserter(filteredOperandPerformances),
[](const nn::Capabilities::OperandPerformance& operandPerformance) {
return compliantVersion(operandPerformance.type).has_value();
});
+ const auto relaxedFloat32toFloat16PerformanceScalar =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+ const auto relaxedFloat32toFloat16PerformanceTensor =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+ auto operandPerformance = NN_TRY(unvalidatedConvert(filteredOperandPerformances));
+ const auto ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance));
+ const auto whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance));
return Capabilities{
- .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
- .operandPerformance = NN_TRY(unvalidatedConvert(operandPerformance)),
- .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
- .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
+ .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
+ .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16PerformanceTensor,
+ .operandPerformance = std::move(operandPerformance),
+ .ifPerformance = ifPerformance,
+ .whilePerformance = whilePerformance,
};
}
nn::GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const nn::Capabilities::OperandPerformance& operandPerformance) {
+ const auto type = NN_TRY(unvalidatedConvert(operandPerformance.type));
+ const auto info = NN_TRY(unvalidatedConvert(operandPerformance.info));
return Capabilities::OperandPerformance{
- .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
- .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
+ .type = type,
+ .info = info,
};
}
nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
+ .type = type,
.inputs = operation.inputs,
.outputs = operation.outputs,
};
@@ -509,15 +537,19 @@
}
nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
+ auto extraParams = NN_TRY(unvalidatedConvert(operand.extraParams));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
+ .type = type,
.dimensions = operand.dimensions,
.numberOfConsumers = 0,
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
- .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
+ .lifetime = lifetime,
+ .location = location,
+ .extraParams = std::move(extraParams),
};
}
@@ -527,13 +559,18 @@
<< "Model cannot be unvalidatedConverted because it contains pointer-based memory";
}
+ auto main = NN_TRY(unvalidatedConvert(model.main));
+ auto referenced = NN_TRY(unvalidatedConvert(model.referenced));
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
+ auto extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix));
return Model{
- .main = NN_TRY(unvalidatedConvert(model.main)),
- .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .main = std::move(main),
+ .referenced = std::move(referenced),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = std::move(extensionNameToPrefix),
};
}
@@ -548,9 +585,10 @@
operands[i].numberOfConsumers = numberOfConsumers[i];
}
+ auto operations = NN_TRY(unvalidatedConvert(subgraph.operations));
return Subgraph{
.operands = std::move(operands),
- .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
+ .operations = std::move(operations),
.inputIndexes = subgraph.inputIndexes,
.outputIndexes = subgraph.outputIndexes,
};
@@ -574,10 +612,13 @@
<< "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
+ auto inputs = NN_TRY(unvalidatedConvert(request.inputs));
+ auto outputs = NN_TRY(unvalidatedConvert(request.outputs));
+ auto pools = NN_TRY(unvalidatedConvert(request.pools));
return Request{
- .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
- .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
- .pools = NN_TRY(unvalidatedConvert(request.pools)),
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
+ .pools = std::move(pools),
};
}
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 9fa0f0a..07071cc 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -92,7 +92,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index a2013ec..f2cfa3f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -1253,7 +1253,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index d296828..3218206 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -17,54 +17,10 @@
},
{
"name": "neuralnetworks_utils_hal_aidl_test"
- },
- {
- "name": "VtsHalNeuralnetworksV1_0TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
- },
- {
- "name": "VtsHalNeuralnetworksV1_1TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
}
],
"presubmit-large": [
{
- "name": "VtsHalNeuralnetworksV1_2TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
- },
- {
- "name": "VtsHalNeuralnetworksV1_3TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
- },
- {
"name": "VtsHalNeuralnetworksTargetTest",
"options": [
{
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index 081e3d7..47c72b4 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -177,22 +177,28 @@
auto table =
NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
+ const auto relaxedFloat32toFloat16PerformanceScalar =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+ const auto relaxedFloat32toFloat16PerformanceTensor =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+ const auto ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance));
+ const auto whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance));
return Capabilities{
- .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+ .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
+ .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16PerformanceTensor,
.operandPerformance = std::move(table),
- .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
- .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
+ .ifPerformance = ifPerformance,
+ .whilePerformance = whilePerformance,
};
}
GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const aidl_hal::OperandPerformance& operandPerformance) {
+ const auto type = NN_TRY(unvalidatedConvert(operandPerformance.type));
+ const auto info = NN_TRY(unvalidatedConvert(operandPerformance.info));
return Capabilities::OperandPerformance{
- .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
- .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
+ .type = type,
+ .info = info,
};
}
@@ -228,10 +234,13 @@
}
GeneralResult<Operation> unvalidatedConvert(const aidl_hal::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
+ auto inputs = NN_TRY(toUnsigned(operation.inputs));
+ auto outputs = NN_TRY(toUnsigned(operation.outputs));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
- .inputs = NN_TRY(toUnsigned(operation.inputs)),
- .outputs = NN_TRY(toUnsigned(operation.outputs)),
+ .type = type,
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
};
}
@@ -241,14 +250,19 @@
}
GeneralResult<Operand> unvalidatedConvert(const aidl_hal::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ auto dimensions = NN_TRY(toUnsigned(operand.dimensions));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
+ auto extraParams = NN_TRY(unvalidatedConvert(operand.extraParams));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
- .dimensions = NN_TRY(toUnsigned(operand.dimensions)),
+ .type = type,
+ .dimensions = std::move(dimensions),
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
- .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
+ .lifetime = lifetime,
+ .location = location,
+ .extraParams = std::move(extraParams),
};
}
@@ -280,22 +294,31 @@
}
GeneralResult<Model> unvalidatedConvert(const aidl_hal::Model& model) {
+ auto main = NN_TRY(unvalidatedConvert(model.main));
+ auto referenced = NN_TRY(unvalidatedConvert(model.referenced));
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
+ auto extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix));
return Model{
- .main = NN_TRY(unvalidatedConvert(model.main)),
- .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .main = std::move(main),
+ .referenced = std::move(referenced),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = std::move(extensionNameToPrefix),
};
}
GeneralResult<Model::Subgraph> unvalidatedConvert(const aidl_hal::Subgraph& subgraph) {
+ auto operands = NN_TRY(unvalidatedConvert(subgraph.operands));
+ auto operations = NN_TRY(unvalidatedConvert(subgraph.operations));
+ auto inputIndexes = NN_TRY(toUnsigned(subgraph.inputIndexes));
+ auto outputIndexes = NN_TRY(toUnsigned(subgraph.outputIndexes));
return Model::Subgraph{
- .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
- .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
- .inputIndexes = NN_TRY(toUnsigned(subgraph.inputIndexes)),
- .outputIndexes = NN_TRY(toUnsigned(subgraph.outputIndexes)),
+ .operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = std::move(inputIndexes),
+ .outputIndexes = std::move(outputIndexes),
};
}
@@ -308,9 +331,10 @@
}
GeneralResult<Extension> unvalidatedConvert(const aidl_hal::Extension& extension) {
+ auto operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes));
return Extension{
.name = extension.name,
- .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)),
+ .operandTypes = std::move(operandTypes),
};
}
@@ -326,8 +350,9 @@
}
GeneralResult<OutputShape> unvalidatedConvert(const aidl_hal::OutputShape& outputShape) {
+ auto dimensions = NN_TRY(toUnsigned(outputShape.dimensions));
return OutputShape{
- .dimensions = NN_TRY(toUnsigned(outputShape.dimensions)),
+ .dimensions = std::move(dimensions),
.isSufficient = outputShape.isSufficient,
};
}
@@ -346,8 +371,9 @@
return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
}
+ auto fd = NN_TRY(dupFd(ashmem.fd.get()));
auto handle = Memory::Ashmem{
- .fd = NN_TRY(dupFd(ashmem.fd.get())),
+ .fd = std::move(fd),
.size = static_cast<size_t>(ashmem.size),
};
return std::make_shared<const Memory>(Memory{.handle = std::move(handle)});
@@ -426,7 +452,8 @@
}
GeneralResult<BufferDesc> unvalidatedConvert(const aidl_hal::BufferDesc& bufferDesc) {
- return BufferDesc{.dimensions = NN_TRY(toUnsigned(bufferDesc.dimensions))};
+ auto dimensions = NN_TRY(toUnsigned(bufferDesc.dimensions));
+ return BufferDesc{.dimensions = std::move(dimensions)};
}
GeneralResult<BufferRole> unvalidatedConvert(const aidl_hal::BufferRole& bufferRole) {
@@ -440,20 +467,25 @@
}
GeneralResult<Request> unvalidatedConvert(const aidl_hal::Request& request) {
+ auto inputs = NN_TRY(unvalidatedConvert(request.inputs));
+ auto outputs = NN_TRY(unvalidatedConvert(request.outputs));
+ auto pools = NN_TRY(unvalidatedConvert(request.pools));
return Request{
- .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
- .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
- .pools = NN_TRY(unvalidatedConvert(request.pools)),
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
+ .pools = std::move(pools),
};
}
GeneralResult<Request::Argument> unvalidatedConvert(const aidl_hal::RequestArgument& argument) {
const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE
: Request::Argument::LifeTime::POOL;
+ const auto location = NN_TRY(unvalidatedConvert(argument.location));
+ auto dimensions = NN_TRY(toUnsigned(argument.dimensions));
return Request::Argument{
.lifetime = lifetime,
- .location = NN_TRY(unvalidatedConvert(argument.location)),
- .dimensions = NN_TRY(toUnsigned(argument.dimensions)),
+ .location = location,
+ .dimensions = std::move(dimensions),
};
}
@@ -720,8 +752,9 @@
nn::GeneralResult<OperandPerformance> unvalidatedConvert(
const nn::Capabilities::OperandPerformance& operandPerformance) {
- return OperandPerformance{.type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
- .info = NN_TRY(unvalidatedConvert(operandPerformance.info))};
+ const auto type = NN_TRY(unvalidatedConvert(operandPerformance.type));
+ const auto info = NN_TRY(unvalidatedConvert(operandPerformance.info));
+ return OperandPerformance{.type = type, .info = info};
}
nn::GeneralResult<std::vector<OperandPerformance>> unvalidatedConvert(
@@ -788,7 +821,8 @@
}
nn::GeneralResult<BufferDesc> unvalidatedConvert(const nn::BufferDesc& bufferDesc) {
- return BufferDesc{.dimensions = NN_TRY(toSigned(bufferDesc.dimensions))};
+ auto dimensions = NN_TRY(toSigned(bufferDesc.dimensions));
+ return BufferDesc{.dimensions = std::move(dimensions)};
}
nn::GeneralResult<BufferRole> unvalidatedConvert(const nn::BufferRole& bufferRole) {
@@ -847,7 +881,8 @@
}
nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape) {
- return OutputShape{.dimensions = NN_TRY(toSigned(outputShape.dimensions)),
+ auto dimensions = NN_TRY(toSigned(outputShape.dimensions));
+ return OutputShape{.dimensions = std::move(dimensions),
.isSufficient = outputShape.isSufficient};
}
@@ -915,14 +950,19 @@
}
nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
+ const auto type = NN_TRY(unvalidatedConvert(operand.type));
+ auto dimensions = NN_TRY(toSigned(operand.dimensions));
+ const auto lifetime = NN_TRY(unvalidatedConvert(operand.lifetime));
+ const auto location = NN_TRY(unvalidatedConvert(operand.location));
+ auto extraParams = NN_TRY(unvalidatedConvert(operand.extraParams));
return Operand{
- .type = NN_TRY(unvalidatedConvert(operand.type)),
- .dimensions = NN_TRY(toSigned(operand.dimensions)),
+ .type = type,
+ .dimensions = std::move(dimensions),
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
- .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
- .location = NN_TRY(unvalidatedConvert(operand.location)),
- .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
+ .lifetime = lifetime,
+ .location = location,
+ .extraParams = std::move(extraParams),
};
}
@@ -934,19 +974,26 @@
}
nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
+ const auto type = NN_TRY(unvalidatedConvert(operation.type));
+ auto inputs = NN_TRY(toSigned(operation.inputs));
+ auto outputs = NN_TRY(toSigned(operation.outputs));
return Operation{
- .type = NN_TRY(unvalidatedConvert(operation.type)),
- .inputs = NN_TRY(toSigned(operation.inputs)),
- .outputs = NN_TRY(toSigned(operation.outputs)),
+ .type = type,
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
};
}
nn::GeneralResult<Subgraph> unvalidatedConvert(const nn::Model::Subgraph& subgraph) {
+ auto operands = NN_TRY(unvalidatedConvert(subgraph.operands));
+ auto operations = NN_TRY(unvalidatedConvert(subgraph.operations));
+ auto inputIndexes = NN_TRY(toSigned(subgraph.inputIndexes));
+ auto outputIndexes = NN_TRY(toSigned(subgraph.outputIndexes));
return Subgraph{
- .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
- .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
- .inputIndexes = NN_TRY(toSigned(subgraph.inputIndexes)),
- .outputIndexes = NN_TRY(toSigned(subgraph.outputIndexes)),
+ .operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = std::move(inputIndexes),
+ .outputIndexes = std::move(outputIndexes),
};
}
@@ -969,13 +1016,18 @@
<< "Model cannot be unvalidatedConverted because it contains pointer-based memory";
}
+ auto main = NN_TRY(unvalidatedConvert(model.main));
+ auto referenced = NN_TRY(unvalidatedConvert(model.referenced));
+ auto operandValues = NN_TRY(unvalidatedConvert(model.operandValues));
+ auto pools = NN_TRY(unvalidatedConvert(model.pools));
+ auto extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix));
return Model{
- .main = NN_TRY(unvalidatedConvert(model.main)),
- .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
- .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
- .pools = NN_TRY(unvalidatedConvert(model.pools)),
+ .main = std::move(main),
+ .referenced = std::move(referenced),
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
- .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
+ .extensionNameToPrefix = std::move(extensionNameToPrefix),
};
}
@@ -989,10 +1041,13 @@
<< "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
+ auto inputs = NN_TRY(unvalidatedConvert(request.inputs));
+ auto outputs = NN_TRY(unvalidatedConvert(request.outputs));
+ auto pools = NN_TRY(unvalidatedConvert(request.pools));
return Request{
- .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
- .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
- .pools = NN_TRY(unvalidatedConvert(request.pools)),
+ .inputs = std::move(inputs),
+ .outputs = std::move(outputs),
+ .pools = std::move(pools),
};
}
@@ -1003,10 +1058,12 @@
<< "Request cannot be unvalidatedConverted because it contains pointer-based memory";
}
const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
+ const auto location = NN_TRY(unvalidatedConvert(requestArgument.location));
+ auto dimensions = NN_TRY(toSigned(requestArgument.dimensions));
return RequestArgument{
.hasNoValue = hasNoValue,
- .location = NN_TRY(unvalidatedConvert(requestArgument.location)),
- .dimensions = NN_TRY(toSigned(requestArgument.dimensions)),
+ .location = location,
+ .dimensions = std::move(dimensions),
};
}
@@ -1033,9 +1090,11 @@
}
nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
+ const auto timeOnDeviceNs = NN_TRY(unvalidatedConvert(timing.timeOnDevice));
+ const auto timeInDriverNs = NN_TRY(unvalidatedConvert(timing.timeInDriver));
return Timing{
- .timeOnDeviceNs = NN_TRY(unvalidatedConvert(timing.timeOnDevice)),
- .timeInDriverNs = NN_TRY(unvalidatedConvert(timing.timeInDriver)),
+ .timeOnDeviceNs = timeOnDeviceNs,
+ .timeInDriverNs = timeInDriverNs,
};
}
@@ -1064,20 +1123,25 @@
}
nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
+ const auto relaxedFloat32toFloat16PerformanceTensor =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+ const auto relaxedFloat32toFloat16PerformanceScalar =
+ NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+ auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
+ const auto ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance));
+ const auto whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance));
return Capabilities{
- .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
- .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
- unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
- .operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance)),
- .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
- .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
+ .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16PerformanceTensor,
+ .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
+ .operandPerformance = std::move(operandPerformance),
+ .ifPerformance = ifPerformance,
+ .whilePerformance = whilePerformance,
};
}
nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension) {
- return Extension{.name = extension.name,
- .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes))};
+ auto operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes));
+ return Extension{.name = extension.name, .operandTypes = std::move(operandTypes)};
}
#ifdef NN_AIDL_V4_OR_ABOVE
nn::GeneralResult<TokenValuePair> unvalidatedConvert(const nn::TokenValuePair& tokenValuePair) {
diff --git a/neuralnetworks/aidl/utils/src/Utils.cpp b/neuralnetworks/aidl/utils/src/Utils.cpp
index 76a0b07..f9b4f6e 100644
--- a/neuralnetworks/aidl/utils/src/Utils.cpp
+++ b/neuralnetworks/aidl/utils/src/Utils.cpp
@@ -51,8 +51,9 @@
}
nn::GeneralResult<common::NativeHandle> clone(const common::NativeHandle& handle) {
+ auto fds = NN_TRY(cloneVec(handle.fds));
return common::NativeHandle{
- .fds = NN_TRY(cloneVec(handle.fds)),
+ .fds = std::move(fds),
.ints = handle.ints,
};
}
@@ -63,29 +64,32 @@
switch (memory.getTag()) {
case Memory::Tag::ashmem: {
const auto& ashmem = memory.get<Memory::Tag::ashmem>();
+ auto fd = NN_TRY(clone(ashmem.fd));
auto handle = common::Ashmem{
- .fd = NN_TRY(clone(ashmem.fd)),
+ .fd = std::move(fd),
.size = ashmem.size,
};
return Memory::make<Memory::Tag::ashmem>(std::move(handle));
}
case Memory::Tag::mappableFile: {
const auto& memFd = memory.get<Memory::Tag::mappableFile>();
+ auto fd = NN_TRY(clone(memFd.fd));
auto handle = common::MappableFile{
.length = memFd.length,
.prot = memFd.prot,
- .fd = NN_TRY(clone(memFd.fd)),
+ .fd = std::move(fd),
.offset = memFd.offset,
};
return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
}
case Memory::Tag::hardwareBuffer: {
const auto& hardwareBuffer = memory.get<Memory::Tag::hardwareBuffer>();
- auto handle = graphics::common::HardwareBuffer{
+ auto handle = NN_TRY(clone(hardwareBuffer.handle));
+ auto ahwbHandle = graphics::common::HardwareBuffer{
.description = hardwareBuffer.description,
- .handle = NN_TRY(clone(hardwareBuffer.handle)),
+ .handle = std::move(handle),
};
- return Memory::make<Memory::Tag::hardwareBuffer>(std::move(handle));
+ return Memory::make<Memory::Tag::hardwareBuffer>(std::move(ahwbHandle));
}
}
return (NN_ERROR() << "Unrecognized Memory::Tag: " << underlyingType(memory.getTag()))
@@ -109,19 +113,21 @@
}
nn::GeneralResult<Request> clone(const Request& request) {
+ auto pools = NN_TRY(clone(request.pools));
return Request{
.inputs = request.inputs,
.outputs = request.outputs,
- .pools = NN_TRY(clone(request.pools)),
+ .pools = std::move(pools),
};
}
nn::GeneralResult<Model> clone(const Model& model) {
+ auto pools = NN_TRY(clone(model.pools));
return Model{
.main = model.main,
.referenced = model.referenced,
.operandValues = model.operandValues,
- .pools = NN_TRY(clone(model.pools)),
+ .pools = std::move(pools),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
.extensionNameToPrefix = model.extensionNameToPrefix,
};
diff --git a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
index 7451f7e..da0fe64 100644
--- a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
@@ -1068,7 +1068,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
index 30365f6..a2422b1 100644
--- a/nfc/aidl/Android.bp
+++ b/nfc/aidl/Android.bp
@@ -34,10 +34,5 @@
sdk_version: "module_current",
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
diff --git a/oemlock/aidl/Android.bp b/oemlock/aidl/Android.bp
index d1930f9..1c19bb1 100644
--- a/oemlock/aidl/Android.bp
+++ b/oemlock/aidl/Android.bp
@@ -16,11 +16,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index c722795..63a40ed 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -35,11 +35,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: [
"1",
diff --git a/power/stats/aidl/Android.bp b/power/stats/aidl/Android.bp
index 48d3c51..b1b2515 100644
--- a/power/stats/aidl/Android.bp
+++ b/power/stats/aidl/Android.bp
@@ -32,11 +32,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
cpp: {
enabled: true,
},
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index e1808af..cfd6ebf 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -20,11 +20,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
@@ -42,11 +37,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
@@ -64,11 +54,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
@@ -86,11 +71,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
@@ -108,11 +88,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
@@ -130,11 +105,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
@@ -155,11 +125,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
@@ -177,10 +142,5 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index e1d508d..0bae374 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -592,6 +592,89 @@
}
/*
+ * Test IRadioNetwork.setSignalStrengthReportingCriteria() for multi-RANs per request
+ */
+TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_multiRansPerRequest) {
+ SignalThresholdInfo signalThresholdInfoGeran;
+ signalThresholdInfoGeran.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSSI;
+ signalThresholdInfoGeran.hysteresisMs = 5000;
+ signalThresholdInfoGeran.hysteresisDb = 2;
+ signalThresholdInfoGeran.thresholds = {-109, -103, -97, -89};
+ signalThresholdInfoGeran.isEnabled = true;
+ signalThresholdInfoGeran.ran = AccessNetwork::GERAN;
+
+ SignalThresholdInfo signalThresholdInfoUtran;
+ signalThresholdInfoUtran.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSCP;
+ signalThresholdInfoUtran.hysteresisMs = 5000;
+ signalThresholdInfoUtran.hysteresisDb = 2;
+ signalThresholdInfoUtran.thresholds = {-110, -97, -73, -49, -25};
+ signalThresholdInfoUtran.isEnabled = true;
+ signalThresholdInfoUtran.ran = AccessNetwork::UTRAN;
+
+ SignalThresholdInfo signalThresholdInfoEutran;
+ signalThresholdInfoEutran.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSRP;
+ signalThresholdInfoEutran.hysteresisMs = 5000;
+ signalThresholdInfoEutran.hysteresisDb = 2;
+ signalThresholdInfoEutran.thresholds = {-128, -108, -88, -68};
+ signalThresholdInfoEutran.isEnabled = true;
+ signalThresholdInfoEutran.ran = AccessNetwork::EUTRAN;
+
+ SignalThresholdInfo signalThresholdInfoCdma2000;
+ signalThresholdInfoCdma2000.signalMeasurement =
+ SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSSI;
+ signalThresholdInfoCdma2000.hysteresisMs = 5000;
+ signalThresholdInfoCdma2000.hysteresisDb = 2;
+ signalThresholdInfoCdma2000.thresholds = {-105, -90, -75, -65};
+ signalThresholdInfoCdma2000.isEnabled = true;
+ signalThresholdInfoCdma2000.ran = AccessNetwork::CDMA2000;
+
+ SignalThresholdInfo signalThresholdInfoNgran;
+ signalThresholdInfoNgran.signalMeasurement =
+ SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_SSRSRP;
+ signalThresholdInfoNgran.hysteresisMs = 5000;
+ signalThresholdInfoNgran.hysteresisDb = 0;
+ signalThresholdInfoNgran.thresholds = {-105, -90, -75, -65};
+ signalThresholdInfoNgran.isEnabled = true;
+ signalThresholdInfoNgran.ran = AccessNetwork::NGRAN;
+
+ const static std::vector<SignalThresholdInfo> candidateSignalThresholdInfos = {
+ signalThresholdInfoGeran, signalThresholdInfoUtran, signalThresholdInfoEutran,
+ signalThresholdInfoCdma2000, signalThresholdInfoNgran};
+
+ std::vector<SignalThresholdInfo> supportedSignalThresholdInfos;
+ for (size_t i = 0; i < candidateSignalThresholdInfos.size(); i++) {
+ serial = GetRandomSerialNumber();
+ ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(
+ serial, {candidateSignalThresholdInfos[i]});
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+ supportedSignalThresholdInfos.push_back(signalThresholdInfoGeran);
+ } else {
+ // Refer to IRadioNetworkResponse#setSignalStrengthReportingCriteriaResponse
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE}));
+ }
+ }
+
+ ASSERT_FALSE(supportedSignalThresholdInfos.empty());
+
+ serial = GetRandomSerialNumber();
+ ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(
+ serial, supportedSignalThresholdInfos);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ALOGI("setSignalStrengthReportingCriteria_multiRansPerRequest, rspInfo.error = %s\n",
+ toString(radioRsp_network->rspInfo.error).c_str());
+
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
* Test IRadioNetwork.setLinkCapacityReportingCriteria() invalid hysteresisDlKbps
*/
TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisDlKbps) {
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
index c764f86..39aaa07 100644
--- a/rebootescrow/aidl/Android.bp
+++ b/rebootescrow/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/security/OWNERS b/security/OWNERS
index 54d820a..4142fc1 100644
--- a/security/OWNERS
+++ b/security/OWNERS
@@ -1,3 +1,6 @@
+# Please assign all bugs related to /hardware/interfaces/security to the team alias,
+# android-hardware-security@google.com. This will get them auto-assigned to the on-call triage
+# engineer, ensuring quickest response.
drysdale@google.com
jbires@google.com
jdanis@google.com
diff --git a/security/dice/aidl/Android.bp b/security/dice/aidl/Android.bp
index 8c31e26..48c3e7e 100644
--- a/security/dice/aidl/Android.bp
+++ b/security/dice/aidl/Android.bp
@@ -34,9 +34,6 @@
platform_apis: false,
},
ndk: {
- vndk: {
- enabled: true,
- },
apps_enabled: false,
apex_available: [
"//apex_available:platform",
diff --git a/security/keymint/RKP_CHANGELOG.md b/security/keymint/RKP_CHANGELOG.md
new file mode 100644
index 0000000..67d68d4
--- /dev/null
+++ b/security/keymint/RKP_CHANGELOG.md
@@ -0,0 +1,18 @@
+# Remote Provisioning Changelog
+
+This document provides an exact description of which changes have occurred in the
+`IRemotelyProvisionedComponent` HAL interface in each Android release.
+
+## Releases
+* **Android S (12):** IRemotelyProvisionedComponent v1
+* **Android T (13):** IRemotelyProvisionedComponent v2
+
+## IRemotelyProvisionedComponent 1 -> 2
+* DeviceInfo
+ * Most entries are no longer optional.
+ * `att_id_state` is now `fused`. `fused` is used to indicate if SecureBoot is enabled.
+ * `version` is now `2`.
+ * `board` has been removed.
+ * `device` has been added.
+* RpcHardwareInfo
+ * `uniqueId` String added as a field in order to differentiate IRPC instances on device.
\ No newline at end of file
diff --git a/security/keymint/RKP_README.md b/security/keymint/RKP_README.md
new file mode 100644
index 0000000..89a2598
--- /dev/null
+++ b/security/keymint/RKP_README.md
@@ -0,0 +1,374 @@
+# Remote Provisioning HAL
+
+## Objective
+
+Design a HAL to support over-the-air provisioning of certificates for asymmetric
+keys. The HAL must interact effectively with Keystore (and other daemons) and
+protect device privacy and security.
+
+Note that this API is designed for KeyMint, but with the intention that it
+should be usable for other HALs that require certificate provisioning.
+Throughout this document we'll refer to the Keystore and KeyMint (formerly
+called Keymaster) components, but only for concreteness and convenience; those
+labels could be replaced with the names of any system and secure area
+components, respectively, that need certificates provisioned.
+
+## Key design decisions
+
+### General approach
+
+To more securely and reliably get keys and certificates to Android devices, we
+need to create a system where no party outside of the device's secure components
+is responsible for managing private keys. The strategy we've chosen is to
+deliver certificates over the air, using an asymmetric key pair created
+on-device in the factory as a root of trust to create an authenticated, secure
+channel. In this document we refer to this device-unique asymmetric key pair as
+Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device
+Key Certificate containing DK\_pub is denoted DKC.
+
+In order for the provisioning service to use DK (or a key authenticated by DK),
+it must know whether a given DK\_pub is known and trusted. To prove trust, we
+ask device OEMs to use one of two mechanisms:
+
+1. (Preferred, recommended) The device OEM extracts DK\_pub from each device it
+ manufactures and uploads the public keys to a backend server.
+
+1. The device OEM signs the DK\_pub to produce DKC and stores it on the device.
+ This has the advantage that they don't need to upload a DK\_pub for every
+ device immediately, but the disadvantage that they have to manage their
+ private signing keys, which means they have to have HSMs, configure and
+ secure them correctly, etc. Some backend providers may also require that the
+ OEM passes a factory security audit, and additionally promises to upload the
+ keys eventually as well.
+
+Note that in the full elaboration of this plan, DK\_pub is not the key used to
+establish a secure channel. Instead, DK\_pub is just the first public key in a
+chain of public keys which ends with the KeyMint public key, KM\_pub. All keys
+in the chain are device-unique and are joined in a certificate chain called the
+_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote
+provisioning project it is a chain of certificates corresponding to boot phases.
+We speak of the BCC even for phase 1, though in phase 1 it contains only a
+single self-signed DKC. This is described in more depth in the Phases section
+below.
+
+The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have
+additional DKCs, from the SoC vendor, the device OEM, or both. Those are not
+part of the BCC but included as optional fields in the certificate request
+structure.
+
+The format of the the DK and BCC is specified within [Open Profile for DICE]
+(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md). To
+map phrases within this document to their equivalent terminology in the DICE
+specification, read the terms as follows: the DK corresponds to the UDS-derived
+key pair, DKC corresponds to the UDS certificate, and the BCC entries between
+DK\_pub and KM\_pub correspond to a chain of CDI certificates.
+
+Note: In addition to allowing 32 byte hash values for fields in the BCC payload,
+this spec additionally constrains some of the choices allowed in open-DICE.
+Specifically, these include which entries are required and which are optional in
+the BCC payload, and which algorithms are acceptable for use.
+
+### Phases
+
+RKP will be deployed in three phases, in terms of managing the root of trust
+binding between the device and the backend. To briefly describe them:
+
+* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are
+ the same key and the certificate is self-signed.
+* Phase 2: This is identical to phase 1, except it leverages the hardware root
+ of trust process described by DICE. Instead of trust being rooted in the TEE,
+ it is now rooted in the ROM by key material blown into fuses which are only
+ accessible to the ROM code.
+* Phase 3: This is identical to Phase 2, except the SoC vendor also does the
+ public key extraction or certification in their facilities, along with the OEM
+ doing it in the factory. This tightens up the "supply chain" and aims to make
+ key upload management more secure.
+
+### Privacy considerations
+
+Because DK and the DKCs are unique, immutable, unspoofable hardware-bound
+identifiers for the device, we must limit access to them to the absolute minimum
+possible. We do this in two ways:
+
+1. We require KeyMint (which knows the BCC and either knows or at least has the
+ability to use KM\_priv) to refuse to ever divulge the BCC or additional
+signatures in plaintext. Instead, KeyMint requires the caller to provide an
+_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before
+returning it. When provisioning production keys, the EEK must be signed by an
+approved authority whose public key is embedded in KeyMint. When certifying test
+keys, KeyMint will accept any EEK without checking the signature, but will
+encrypt and return a test BCC, rather than the real one. The result is that
+only an entity in possession of an Trusted EEK (TEEK) private key can discover
+the plaintext of the production BCC.
+1. Having thus limited access to the public keys to the trusted party only, we
+need to prevent the entity from abusing this unique device identifier. The
+approach and mechanisms for doing that are beyond the scope of this document
+(they must be addressed in the server design), but generally involve taking care
+to ensure that we do not create any links between user IDs, IP addresses or
+issued certificates and the device pubkey.
+
+Although the details of the mechanisms for preventing the entity from abusing
+the BCC are, as stated, beyond the scope of this document, there is a subtle
+design decision here made specifically to enable abuse prevention. Specifically
+the `CertificateRequest` message sent to the server is (in
+[CDDL](https://tools.ietf.org/html/rfc8610)):
+
+```
+cddl
+CertificateRequest = [
+ DeviceInfo,
+ challenge : bstr,
+ ProtectedData,
+ MacedKeysToSign
+]
+```
+
+The public keys to be attested by the server are in `MacedKeysToSign`, which is
+a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The
+MAC key is signed by DK\_pub.
+
+This structure allows the backend component that has access to EEK\_priv to
+decrypt `ProtectedData`, validate that the request is from an authorized device,
+check that the request is fresh and verify and extract the MAC key. That backend
+component never sees any data related to the keys to be signed, but can provide
+the MAC key to another backend component that can verify `MacedKeysToSign` and
+proceed to generate the certificates.
+
+In this way, we can partition the provisioning server into one component that
+knows the device identity, as represented by DK\_pub, but never sees the keys to
+be certified or certificates generated, and another component that sees the keys
+to be certified and certificates generated but does not know the device
+identity.
+
+### Key and cryptographic message formatting
+
+For simplicity of generation and parsing, compactness of wire representation,
+and flexibility and standardization, we've settled on using the CBOR Object
+Signing and Encryption (COSE) standard, defined in [RFC
+8152](https://tools.ietf.org/html/rfc8152). COSE provides compact and reasonably
+simple, yet easily-extensible, wire formats for:
+
+* Keys,
+* MACed messages,
+* Signed messages, and
+* Encrypted messages
+
+COSE enables easy layering of these message formats, such as using a COSE\_Sign
+structure to contain a COSE\_Key with a public key in it. We call this a
+"certificate".
+
+Due to the complexity of the standard, we'll spell out the COSE structures
+completely in this document and in the HAL and other documentation, so that
+although implementors will need to understand CBOR and the CBOR Data Definition
+Language ([CDDL, defined in RFC 8610](https://tools.ietf.org/html/rfc8610)),
+they shouldn't need to understand COSE.
+
+Note, however, that the certificate chains returned from the provisioning server
+are standard X.509 certificates.
+
+### Algorithm choices
+
+This document uses:
+
+* ECDSA P-256 for attestation signing keys;
+* Remote provisioning protocol signing keys:
+ * Ed25519 / P-256
+* ECDH keys:
+ * X25519 / P-256
+* AES-GCM for all encryption;
+* SHA-256 for all message digesting;
+* HMAC-SHA-256 for all MACing; and
+* HKDF-SHA-256 for all key derivation.
+
+We believe that Curve25519 offers the best tradeoff in terms of security,
+efficiency and global trustworthiness, and that it is now sufficiently
+widely-used and widely-implemented to make it a practical choice.
+
+However, since Secure Elements (SE) do not currently offer support for curve
+25519, we are allowing implementations to instead make use of EC P-256 for
+signing and ECDH. To put it simply, the device unique key pair will be a P-256
+key pair for ECDSA instead of Ed25519, and the ProtectedData COSE\_Encrypt
+message will have its payload encrypted with P-256 ECDH key exchange instead of
+X25519.
+
+The CDDL in the rest of the document will use the '/' operator to show areas
+where either curve 25519 or P-256 may be used. Since there is no easy way to
+bind choices across different CDDL groups, it is important that the implementor
+stays consistent in which type is chosen. E.g. taking ES256 as the choice for
+algorithm implies the implementor should also choose the P256 public key group
+further down in the COSE structure.
+
+### Testability
+
+It's critical that the remote provisioning implementation be testable, to
+minimize the probability that broken devices are sold to end users. To support
+testing, the remote provisioning HAL methods take a `testMode` argument. Keys
+created in test mode are tagged to indicate this. The provisioning server will
+check for the test mode tag and issue test certificates that do not chain back
+to a trusted public key. In test mode, any EEK will be accepted, enabling
+testing tools to use EEKs for which they have the private key so they can
+validate the content of certificate requests. The BCC included in the
+`CertificateRequest` must contain freshly-generated keys, not the real BCC keys.
+
+Keystore (or similar) will need to be able to handle both testMode keys and
+production keys and keep them distinct, generating test certificate requests
+when asked with a test EEK and production certificate requests when asked with a
+production EEK. Likewise, the interface used to instruct Keystore to create keys
+will need to be able to specify whether test or production keys are desired.
+
+## Design
+
+### Certificate provisioning flow
+
+TODO(jbires): Replace this with a `.png` containing a sequence diagram. The
+provisioning flow looks something like this:
+
+Provisioner -> Keystore: Prepare N keys
+Keystore -> KeyMint: generateKeyPair
+KeyMint -> KeyMint: Generate key pair
+KeyMint --> Keystore: key\_blob,pubkey
+Keystore -> Keystore: Store key\_blob,pubkey
+Provisioner -> Server: Get TEEK
+Server --> Provisioner: TEEK
+Provisioner -> Keystore: genCertReq(N, TEEK)
+Keystore -> KeyMint: genCertReq(pubkeys, TEEK)
+KeyMint -> KeyMint: Sign pubkeys & encrypt BCC
+KeyMint --> Keystore: signature, encrypted BCC
+Keystore -> Keystore: Construct cert\_request
+Keystore --> Provisioner: cert\_request
+Provisioner --> Server: cert\_request
+Server -> Server: Validate cert\_request
+Server -> Server: Generate certificates
+Server --> Provisioner: certificates
+Provisioner -> Keystore: certificates
+Keystore -> Keystore: Store certificates
+
+The actors in the above diagram are:
+
+* **Server** is the backend certificate provisioning server. It has access to
+ the uploaded device public keys and is responsible for providing encryption
+ keys, decrypting and validating requests, and generating certificates in
+ response to requests.
+* **Provisioner** is an application that is responsible for communicating with
+ the server and all of the system components that require key certificates
+ from the server. It also implements the policy that defines how many key
+ pairs each client should keep in their pool.
+* **Keystore** is the [Android keystore
+ daemon](https://developer.android.com/training/articles/keystore) (or, more
+ generally, whatever system component manages communications with a
+ particular secure aread component).
+* **KeyMint** is the secure area component that manages cryptographic keys and
+ performs attestations (or perhaps some other secure area component).
+
+### `BCC`
+
+The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains
+DK\_pub as well as other often device-unique certificates. The BCC is
+represented as a COSE\_Key containing DK\_pub followed by an array of
+COSE\_Sign1 "certificates" containing public keys and optional additional
+information, ordered from root to leaf, with each certificate signing the next.
+The first certificate in the array is signed by DK\_pub, the last certificate
+has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1
+there is only one entry; DK\_pub and KM\_pub are the same key and the
+certificate is self-signed.
+
+Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC
+8392](https://tools.ietf.org/html/rfc8392) with additional fields as described
+in the Open Profile for DICE. Of these additional fields, only the
+_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the
+KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the
+Open Profile for DICE are expected for other entries (each of which corresponds
+to a particular firmware component or boot stage). The CWT fields _iss_ and
+_sub_ identify the issuer and subject of the certificate and are consistent
+along the BCC entries; the issuer of a given entry matches the subject of the
+previous entry.
+
+The BCC is designed to be constructed using the Open Profile for DICE. In this
+case the DK key pair is derived from the UDS as described by that profile and
+all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub.
+The KM key pair is not part of the derived DICE chain. It is generated (not
+derived) by the KeyMint module, certified by the last key in the DICE chain, and
+added as the leaf BCC entry. The key usage field in this leaf certificate must
+indicate the key is not used to sign certificates. If a UDS certificate is
+available on the device it should appear in the certificate request as the leaf
+of a DKCertChain in AdditionalDKSignatures (see
+[CertificateRequest](#certificaterequest)).
+
+The Open Profile for DICE allows for an arbitrary configuration descriptor. For
+BCC entries, this configuration descriptor is a CBOR map with the following
+optional fields. If no fields are relevant, an empty map should be encoded.
+Additional implementation-specific fields may be added using key values not in
+the range \[-70000, -70999\] (these are reserved for future additions here).
+
+```
+| Name | Key | Value type | Meaning |
+| ----------------- | ------ | ---------- | ----------------------------------|
+| Component name | -70002 | tstr | Name of firmware component / boot |
+: : : : stage :
+| Component version | -70003 | int | Version of firmware component / |
+: : : : boot stage :
+| Resettable | -70004 | null | If present, key changes on factory|
+: : : : reset :
+```
+
+Please see
+[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+for a full CDDL definition of the BCC.
+
+### `CertificateRequest`
+
+The full CBOR message that will be sent to the server to request certificates
+is:
+
+```cddl
+CertificateRequest = [
+ DeviceInfo,
+ challenge : bstr, // Provided by the server
+ ProtectedData, // See ProtectedData.aidl
+ MacedKeysToSign // See IRemotelyProvisionedComponent.aidl
+]
+
+DeviceInfo = [
+ VerifiedDeviceInfo, // See DeviceInfo.aidl
+ UnverifiedDeviceInfo
+]
+
+// Unverified info is anything provided by the HLOS. Subject to change out of
+// step with the HAL.
+UnverifiedDeviceInfo = {
+ ? "fingerprint" : tstr,
+}
+
+```
+
+It will be the responsibility of Keystore and the Provisioner to construct the
+`CertificateRequest`. The HAL provides a method to generate the elements that
+need to be constructed on the secure side, which are the tag field of
+`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of
+`ProtectedData`.
+
+### HAL
+
+The remote provisioning HAL provides a simple interface that can be implemented
+by multiple secure components that require remote provisioning. It would be
+slightly simpler to extend the KeyMint API, but that approach would only serve
+the needs of KeyMint, this is more general.
+
+NOTE the data structures defined in this HAL may look a little bloated and
+complex. This is because the COSE data structures are fully spelled-out; we
+could make it much more compact by not re-specifying the standardized elements
+and instead just referencing the standard, but it seems better to fully specify
+them. If the apparent complexity seems daunting, consider what the same would
+look like if traditional ASN.1 DER-based structures from X.509 and related
+standards were used and also fully elaborated.
+
+Please see the related HAL documentation directly in the source code at the
+following links:
+
+* [IRemotelyProvisionedComponent
+ HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
+* [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+* [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
+* [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
+* [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
+
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index c9ee1b3..73c7b97 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -22,9 +22,6 @@
platform_apis: true,
},
ndk: {
- vndk: {
- enabled: true,
- },
apps_enabled: false,
},
rust: {
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index da02d54..2caa4d5 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -196,12 +196,12 @@
* derive a key that is used to encrypt the private/secret key material.
*
* The root of trust consists of a bitstring that must be derived from the public key used by
- * Verified Boot to verify the signature on the boot image and from the lock state of the
- * device. If the public key is changed to allow a different system image to be used or if the
- * lock state is changed, then all of the IKeyMintDevice-protected keys created by the previous
- * system state must be unusable, unless the previous state is restored. The goal is to increase
- * the value of the software-enforced key access controls by making it impossible for an attacker-
- * installed operating system to use IKeyMintDevice keys.
+ * Verified Boot to verify the signature on the boot image, from the lock state and from the
+ * Verified Boot state of the device. If the public key is changed to allow a different system
+ * image to be used or if the lock state is changed, then all of the IKeyMintDevice-protected keys
+ * created by the previous system state must be unusable, unless the previous state is restored.
+ * The goal is to increase the value of the software-enforced key access controls by making it
+ * impossible for an attacker-installed operating system to use IKeyMintDevice keys.
*
* == Version Binding ==
*
@@ -336,6 +336,17 @@
* Only Tag::KEY_SIZE is required to generate an 3DES key, and its value must be 168. If
* omitted, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE.
*
+ * == HMAC Keys ==
+ *
+ * Tag::KEY_SIZE must be provided to generate an HMAC key, and its value must be >= 64 and a
+ * multiple of 8. All devices must support key sizes up to 512 bits, but StrongBox devices must
+ * not support key sizes larger than 512 bits. If omitted or invalid, generateKey() must return
+ * ErrorCode::UNSUPPORTED_KEY_SIZE.
+ *
+ * Tag::MIN_MAC_LENGTH must be provided, and must be a multiple of 8 in the range 64 to 512
+ * bits (inclusive). If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH; if
+ * invalid, generateKey must return ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH.
+ *
* @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
* provided in params. See above for detailed specifications of which tags are required
* for which types of keys.
@@ -661,19 +672,19 @@
* structure, because it cannot add the DigestInfo structure. Instead, the IKeyMintDevice
* must construct 0x00 || 0x01 || PS || 0x00 || M, where M is the provided message and PS is a
* random padding string at least eight bytes in length. The size of the RSA key has to be at
- * least 11 bytes larger than the message, otherwise begin() must return
+ * least 11 bytes larger than the message, otherwise finish() must return
* ErrorCode::INVALID_INPUT_LENGTH.
*
* o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest.
*
- * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the padding values
+ * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the digest values
* in the key authorizations, and which may not be Digest::NONE. begin() must return
* ErrorCode::INCOMPATIBLE_DIGEST if this is not the case. In addition, the size of the RSA
- * key must be at least 2 + D bytes larger than the output size of the digest, where D is the
- * size of the digest, in bytes. Otherwise begin() must return
- * ErrorCode::INCOMPATIBLE_DIGEST. The salt size must be D.
+ * key must be at least (D + S + 9) bits, where D is the size of the digest (in bits) and
+ * S is the size of the salt (in bits). The salt size S must equal D, so the RSA key must
+ * be at least (2*D + 9) bits. Otherwise begin() must return ErrorCode::INCOMPATIBLE_DIGEST.
*
- * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the padding values
+ * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the digest values
* in the key authorizations, and which may not be Digest::NONE. begin() must return
* ErrorCode::INCOMPATIBLE_DIGEST if this is not the case. RSA_OAEP padding also requires an
* MGF1 digest, specified with Tag::RSA_OAEP_MGF_DIGEST, which must match one of the MGF1
@@ -683,9 +694,9 @@
*
* -- EC Keys --
*
- * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
- * means that the key authorizations must contain the specified values. If not, begin() must
- * return ErrorCode::INCOMPATIBLE_DIGEST.
+ * Private key operations (KeyPurpose::SIGN) need authorization of digest, which means that the
+ * key authorizations must contain the specified values. If not, begin() must return
+ * ErrorCode::INCOMPATIBLE_DIGEST.
*
* -- AES Keys --
*
@@ -873,7 +884,7 @@
* The returned data is an encoded COSE_Mac0 structure, denoted MacedRootOfTrust in the
* following CDDL schema. Note that K_mac is the shared HMAC key used for auth tokens, etc.:
*
- * MacedRootOfTrust = [ ; COSE_Mac0 (untagged)
+ * MacedRootOfTrust = #6.17 [ ; COSE_Mac0 (tagged)
* protected: bstr .cbor {
* 1 : 5, ; Algorithm : HMAC-256
* },
@@ -891,7 +902,7 @@
* payload : bstr .cbor RootOfTrust,
* ]
*
- * RootOfTrust = [
+ * RootOfTrust = #6.40001 [ ; Tag 40001 indicates RoT v1.
* verifiedBootKey : bstr .size 32,
* deviceLocked : bool,
* verifiedBootState : &VerifiedBootState,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index fd103ef..32e71a7 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -23,7 +23,7 @@
@VintfStability
@Backing(type="int")
enum KeyPurpose {
- /* Usable with RSA, 3DES and AES keys. */
+ /* Usable with 3DES and AES keys. */
ENCRYPT = 0,
/* Usable with RSA, 3DES and AES keys. */
@@ -32,7 +32,7 @@
/* Usable with RSA, EC and HMAC keys. */
SIGN = 2,
- /* Usable with RSA, EC and HMAC keys. */
+ /* Usable with HMAC keys. */
VERIFY = 3,
/* 4 is reserved */
diff --git a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
index e71a9c9..6ff4b29 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
@@ -26,7 +26,7 @@
@VintfStability
@Backing(type="int")
enum PaddingMode {
- NONE = 1, /* deprecated */
+ NONE = 1,
RSA_OAEP = 2,
RSA_PSS = 3,
RSA_PKCS1_1_5_ENCRYPT = 4,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
index 6db58f2..8b3875b 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -100,15 +100,13 @@
* SignerName = tstr
*
* DKCertChain = [
- * 2* Certificate // Root -> ... -> Leaf. "Root" is the vendor self-signed
+ * 2* X509Certificate // Root -> ... -> Leaf. "Root" is the vendor self-signed
* // cert, "Leaf" contains DK_pub. There may also be
* // intermediate certificates between Root and Leaf.
* ]
*
- * // Certificates may be either:
- * // 1. COSE_Sign1, with payload containing PubKeyEd25519 or PubKeyECDSA256
- * // 2. a bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or edDSA)
- * Certificate = COSE_Sign1 / bstr
+ * // A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or edDSA)
+ * X509Certificate = bstr
*
* // The SignedMac, which authenticates the MAC key that is used to authenticate the
* // keysToSign.
diff --git a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 3a4c233..0cb33ce 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -59,13 +59,17 @@
* client should NOT interpret the content of the identifier in any way. The client can only
* compare identifiers to determine if two IRemotelyProvisionedComponents share the same
* implementation. Each IRemotelyProvisionedComponent implementation must have a distinct
- * identifier from all other implementations on the same device.
+ * identifier from all other implementations, and it must be consistent across all devices.
+ * It's critical that this identifier not be usable to uniquely identify a specific device.
*
* This identifier must be consistent across reboots, as it is used to store and track
* provisioned keys in a persistent, on-device database.
*
* uniqueId may not be empty, and must not be any longer than 32 characters.
*
+ * A recommended construction for this value is "[Vendor] [Component Name] [Major Version]",
+ * e.g. "Google Trusty KeyMint 1".
+ *
* This field was added in API version 2.
*
*/
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index b28ebcb..871a1ac 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -186,10 +186,16 @@
* Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
* encryption/decryption with OAEP padding. Possible values are defined by the Digest enum.
*
- * This tag is repeatable for key generation/import. RSA cipher operations with OAEP padding
- * must specify an MGF1 digest in the params argument of begin(). If this tag is missing or the
- * specified digest is not in the MGF1 digests associated with the key then begin operation must
- * fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST.
+ * This tag is repeatable for key generation/import.
+ *
+ * If the caller specifies an MGF1 digest in the params argument of begin(), that digest must be
+ * present as an RSA_OAEP_MGF_DIGEST value in the key characteristics (or the begin() operation
+ * must fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST).
+ *
+ * If the caller does not specify an MGF1 digest in the params argument of begin(), a default
+ * MGF1 digest of SHA1 is used. If the key characteristics have any explicitly specified values
+ * for RSA_OAEP_MGF_DIGEST, then SHA1 must be included (or the begin() operation must fail with
+ * ErrorCode::INCOMPATIBLE_MGF_DIGEST).
*
* Must be hardware-enforced.
*/
@@ -504,7 +510,9 @@
* that is necessary during all uses of the key. In particular, calls to exportKey() and
* getKeyCharacteristics() must provide the same value to the clientId parameter, and calls to
* begin() must provide this tag and the same associated data as part of the inParams set. If
- * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+ * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB. Note
+ * that a key with a zero-length APPLICATION_ID cannot have its key characteristics retrieved
+ * using getKeyCharacteristics() due to a historical limitation of the API.
*
* The content of this tag must be bound to the key cryptographically, meaning it must not be
* possible for an adversary who has access to all of the secure world secrets but does not have
@@ -525,7 +533,9 @@
* that is necessary during all uses of the key. In particular, calls to begin() and
* exportKey() must provide the same value to the appData parameter, and calls to begin must
* provide this tag and the same associated data as part of the inParams set. If the correct
- * data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+ * data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB. Note that a key
+ * with a zero-length APPLICATION_DATA cannot have its key characteristics retrieved using
+ * getKeyCharacteristics() due to a historical limitation of the API.
*
* The content of this tag must be bound to the key cryptographically, meaning it must not be
* possible for an adversary who has access to all of the secure world secrets but does not have
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 5cdea93..ca517ac 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "keymint_1_attest_key_test"
#include <cutils/log.h>
+#include <cutils/properties.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/openssl_utils.h>
@@ -33,7 +34,33 @@
} // namespace
-using AttestKeyTest = KeyMintAidlTestBase;
+class AttestKeyTest : public KeyMintAidlTestBase {
+ protected:
+ ErrorCode GenerateAttestKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key,
+ vector<uint8_t>* key_blob,
+ vector<KeyCharacteristics>* key_characteristics,
+ vector<Certificate>* cert_chain) {
+ // The original specification for KeyMint v1 required ATTEST_KEY not be combined
+ // with any other key purpose, but the original VTS tests incorrectly did exactly that.
+ // This means that a device that launched prior to Android T (API level 33) may
+ // accept or even require KeyPurpose::SIGN too.
+ if (property_get_int32("ro.board.first_api_level", 0) < 33) {
+ AuthorizationSet key_desc_plus_sign = key_desc;
+ key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
+
+ auto result = GenerateKey(key_desc_plus_sign, attest_key, key_blob, key_characteristics,
+ cert_chain);
+ if (result == ErrorCode::OK) {
+ return result;
+ }
+ // If the key generation failed, it may be because the device is (correctly)
+ // rejecting the combination of ATTEST_KEY+SIGN. Fall through to try again with
+ // just ATTEST_KEY.
+ }
+ return GenerateKey(key_desc, attest_key, key_blob, key_characteristics, cert_chain);
+ }
+};
/*
* AttestKeyTest.AllRsaSizes
@@ -49,12 +76,13 @@
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
vector<Certificate> attest_key_cert_chain;
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .RsaKey(size, 65537)
- .AttestKey()
- .SetDefaultValidity(),
- {} /* attestation signing key */, &attest_key.keyBlob,
- &attest_key_characteristics, &attest_key_cert_chain));
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateAttestKey(AuthorizationSetBuilder()
+ .RsaKey(size, 65537)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
ASSERT_GT(attest_key_cert_chain.size(), 0);
EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -227,17 +255,17 @@
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
vector<Certificate> attest_key_cert_chain;
- auto result = GenerateKey(AuthorizationSetBuilder()
- .RsaKey(2048, 65537)
- .AttestKey()
- .AttestationChallenge(challenge)
- .AttestationApplicationId(app_id)
- .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
- .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .SetDefaultValidity(),
- {} /* attestation signing key */, &attest_key.keyBlob,
- &attest_key_characteristics, &attest_key_cert_chain);
+ auto result = GenerateAttestKey(AuthorizationSetBuilder()
+ .RsaKey(2048, 65537)
+ .AttestKey()
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain);
// Strongbox may not support factory provisioned attestation key.
if (SecLevel() == SecurityLevel::STRONGBOX) {
if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -331,17 +359,17 @@
attest_key_opt = attest_key;
}
- auto result = GenerateKey(AuthorizationSetBuilder()
- .RsaKey(2048, 65537)
- .AttestKey()
- .AttestationChallenge("foo")
- .AttestationApplicationId("bar")
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
- .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
- .SetDefaultValidity(),
- attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
- &cert_chain_list[i]);
+ auto result = GenerateAttestKey(AuthorizationSetBuilder()
+ .RsaKey(2048, 65537)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i],
+ &attested_key_characteristics, &cert_chain_list[i]);
// Strongbox may not support factory provisioned attestation key.
if (SecLevel() == SecurityLevel::STRONGBOX) {
if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -408,17 +436,17 @@
attest_key_opt = attest_key;
}
- auto result = GenerateKey(AuthorizationSetBuilder()
- .EcdsaKey(EcCurve::P_256)
- .AttestKey()
- .AttestationChallenge("foo")
- .AttestationApplicationId("bar")
- .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
- .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .SetDefaultValidity(),
- attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
- &cert_chain_list[i]);
+ auto result = GenerateAttestKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::P_256)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i],
+ &attested_key_characteristics, &cert_chain_list[i]);
// Strongbox may not support factory provisioned attestation key.
if (SecLevel() == SecurityLevel::STRONGBOX) {
if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -513,29 +541,29 @@
}
ErrorCode result;
if ((i & 0x1) == 1) {
- result = GenerateKey(AuthorizationSetBuilder()
- .EcdsaKey(EcCurve::P_256)
- .AttestKey()
- .AttestationChallenge("foo")
- .AttestationApplicationId("bar")
- .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
- .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .SetDefaultValidity(),
- attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
- &cert_chain_list[i]);
+ result = GenerateAttestKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::P_256)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i],
+ &attested_key_characteristics, &cert_chain_list[i]);
} else {
- result = GenerateKey(AuthorizationSetBuilder()
- .RsaKey(2048, 65537)
- .AttestKey()
- .AttestationChallenge("foo")
- .AttestationApplicationId("bar")
- .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
- .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .SetDefaultValidity(),
- attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
- &cert_chain_list[i]);
+ result = GenerateAttestKey(AuthorizationSetBuilder()
+ .RsaKey(2048, 65537)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i],
+ &attested_key_characteristics, &cert_chain_list[i]);
}
// Strongbox may not support factory provisioned attestation key.
if (SecLevel() == SecurityLevel::STRONGBOX) {
@@ -581,12 +609,13 @@
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
vector<Certificate> attest_key_cert_chain;
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .RsaKey(size, 65537)
- .AttestKey()
- .SetDefaultValidity(),
- {} /* attestation signing key */, &attest_key.keyBlob,
- &attest_key_characteristics, &attest_key_cert_chain));
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateAttestKey(AuthorizationSetBuilder()
+ .RsaKey(size, 65537)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
EXPECT_EQ(attest_key_cert_chain.size(), 1);
EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
@@ -630,7 +659,7 @@
vector<Certificate> attest_key_cert_chain;
ASSERT_EQ(
ErrorCode::OK,
- GenerateKey(
+ GenerateAttestKey(
AuthorizationSetBuilder().EcdsaKey(curve).AttestKey().SetDefaultValidity(),
{} /* attestation signing key */, &attest_key.keyBlob,
&attest_key_characteristics, &attest_key_cert_chain));
@@ -743,16 +772,22 @@
}
TEST_P(AttestKeyTest, EcdsaAttestationID) {
+ if (is_gsi_image()) {
+ // GSI sets up a standard set of device identifiers that may not match
+ // the device identifiers held by the device.
+ GTEST_SKIP() << "Test not applicable under GSI";
+ }
// Create attestation key.
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
vector<Certificate> attest_key_cert_chain;
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .EcdsaKey(EcCurve::P_256)
- .AttestKey()
- .SetDefaultValidity(),
- {} /* attestation signing key */, &attest_key.keyBlob,
- &attest_key_characteristics, &attest_key_cert_chain));
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateAttestKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::P_256)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
ASSERT_GT(attest_key_cert_chain.size(), 0);
EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -811,12 +846,13 @@
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
vector<Certificate> attest_key_cert_chain;
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .EcdsaKey(EcCurve::P_256)
- .AttestKey()
- .SetDefaultValidity(),
- {} /* attestation signing key */, &attest_key.keyBlob,
- &attest_key_characteristics, &attest_key_cert_chain));
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateAttestKey(AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::P_256)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
ASSERT_GT(attest_key_cert_chain.size(), 0);
EXPECT_EQ(attest_key_cert_chain.size(), 1);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 943c692..46db4f0 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -17,6 +17,7 @@
#include "KeyMintAidlTestBase.h"
#include <chrono>
+#include <fstream>
#include <unordered_set>
#include <vector>
@@ -30,7 +31,6 @@
#include <remote_prov/remote_prov_utils.h>
#include <keymaster/cppcose/cppcose.h>
-#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/keymint_utils.h>
#include <keymint_support/openssl_utils.h>
@@ -1460,6 +1460,36 @@
OPENSSL_free(cert_issuer);
}
+int get_vsr_api_level() {
+ int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+ if (vendor_api_level != -1) {
+ return vendor_api_level;
+ }
+
+ // Android S and older devices do not define ro.vendor.api_level
+ vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
+ if (vendor_api_level == -1) {
+ vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
+ }
+
+ int product_api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+ if (product_api_level == -1) {
+ product_api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+ EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
+ }
+
+ // VSR API level is the minimum of vendor_api_level and product_api_level.
+ if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
+ return product_api_level;
+ }
+ return vendor_api_level;
+}
+
+bool is_gsi_image() {
+ std::ifstream ifs("/system/system_ext/etc/init/init.gsi.rc");
+ return ifs.good();
+}
+
vector<uint8_t> build_serial_blob(const uint64_t serial_int) {
BIGNUM_Ptr serial(BN_new());
EXPECT_TRUE(BN_set_u64(serial.get(), serial_int));
@@ -1491,6 +1521,60 @@
verify_subject(cert.get(), subject, self_signed);
}
+void verify_root_of_trust(const vector<uint8_t>& verified_boot_key, bool device_locked,
+ VerifiedBoot verified_boot_state,
+ const vector<uint8_t>& verified_boot_hash) {
+ char property_value[PROPERTY_VALUE_MAX] = {};
+
+ if (avb_verification_enabled()) {
+ EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
+ string prop_string(property_value);
+ EXPECT_EQ(prop_string.size(), 64);
+ EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
+
+ EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
+ if (!strcmp(property_value, "unlocked")) {
+ EXPECT_FALSE(device_locked);
+ } else {
+ EXPECT_TRUE(device_locked);
+ }
+
+ // Check that the device is locked if not debuggable, e.g., user build
+ // images in CTS. For VTS, debuggable images are used to allow adb root
+ // and the device is unlocked.
+ if (!property_get_bool("ro.debuggable", false)) {
+ EXPECT_TRUE(device_locked);
+ } else {
+ EXPECT_FALSE(device_locked);
+ }
+ }
+
+ // Verified boot key should be all 0's if the boot state is not verified or self signed
+ std::string empty_boot_key(32, '\0');
+ std::string verified_boot_key_str((const char*)verified_boot_key.data(),
+ verified_boot_key.size());
+ EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
+ if (!strcmp(property_value, "green")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "yellow")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "orange")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "red")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
+ } else {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ }
+}
+
bool verify_attestation_record(int32_t aidl_version, //
const string& challenge, //
const string& app_id, //
@@ -1545,8 +1629,6 @@
EXPECT_EQ(security_level, att_keymint_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
-
- char property_value[PROPERTY_VALUE_MAX] = {};
// TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
// keymint implementation will report YYYYMM dates instead of YYYYMMDD
// for the BOOT_PATCH_LEVEL.
@@ -1606,54 +1688,7 @@
error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
&verified_boot_state, &device_locked, &verified_boot_hash);
EXPECT_EQ(ErrorCode::OK, error);
-
- if (avb_verification_enabled()) {
- EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
- string prop_string(property_value);
- EXPECT_EQ(prop_string.size(), 64);
- EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
-
- EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
- if (!strcmp(property_value, "unlocked")) {
- EXPECT_FALSE(device_locked);
- } else {
- EXPECT_TRUE(device_locked);
- }
-
- // Check that the device is locked if not debuggable, e.g., user build
- // images in CTS. For VTS, debuggable images are used to allow adb root
- // and the device is unlocked.
- if (!property_get_bool("ro.debuggable", false)) {
- EXPECT_TRUE(device_locked);
- } else {
- EXPECT_FALSE(device_locked);
- }
- }
-
- // Verified boot key should be all 0's if the boot state is not verified or self signed
- std::string empty_boot_key(32, '\0');
- std::string verified_boot_key_str((const char*)verified_boot_key.data(),
- verified_boot_key.size());
- EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
- if (!strcmp(property_value, "green")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "yellow")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "orange")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "red")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
- } else {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- }
+ verify_root_of_trust(verified_boot_key, device_locked, verified_boot_state, verified_boot_hash);
att_sw_enforced.Sort();
expected_sw_enforced.Sort();
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 7279c95..8f9df24 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -31,6 +31,7 @@
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
+#include <keymint_support/attestation_record.h>
#include <keymint_support/authorization_set.h>
#include <keymint_support/openssl_utils.h>
@@ -354,13 +355,22 @@
}
}
+// Return the VSR API level for this device.
+int get_vsr_api_level();
+
+// Indicate whether the test is running on a GSI image.
+bool is_gsi_image();
+
vector<uint8_t> build_serial_blob(const uint64_t serial_int);
void verify_subject(const X509* cert, const string& subject, bool self_signed);
void verify_serial(X509* cert, const uint64_t expected_serial);
void verify_subject_and_serial(const Certificate& certificate, //
const uint64_t expected_serial, //
const string& subject, bool self_signed);
-
+void verify_root_of_trust(const vector<uint8_t>& verified_boot_key, //
+ bool device_locked, //
+ VerifiedBoot verified_boot_state, //
+ const vector<uint8_t>& verified_boot_hash);
bool verify_attestation_record(int aidl_version, //
const string& challenge, //
const string& app_id, //
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7ec68e3..7c398d3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1103,9 +1103,9 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_GT(cert_chain_.size(), 0);
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -1179,6 +1179,7 @@
EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
// The signature over the attested key should correspond to the P256 public key.
+ ASSERT_GT(cert_chain_.size(), 0);
X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
ASSERT_TRUE(key_cert.get());
EVP_PKEY_Ptr signing_pubkey;
@@ -1266,9 +1267,9 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_GT(cert_chain_.size(), 0);
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -1318,9 +1319,9 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_EQ(cert_chain_.size(), 1);
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- ASSERT_EQ(cert_chain_.size(), 1);
CheckedDeleteKey(&key_blob);
}
@@ -1399,6 +1400,7 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_GT(cert_chain_.size(), 0);
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_EQ(cert_chain_.size(), 1);
@@ -1950,6 +1952,11 @@
* attestation extension.
*/
TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
+ if (is_gsi_image()) {
+ // GSI sets up a standard set of device identifiers that may not match
+ // the device identifiers held by the device.
+ GTEST_SKIP() << "Test not applicable under GSI";
+ }
auto challenge = "hello";
auto app_id = "foo";
auto subject = "cert subj 2";
@@ -2224,8 +2231,8 @@
EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
ASSERT_EQ(cert_chain_.size(), 1);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -2444,6 +2451,29 @@
}
/*
+ * NewKeyGenerationTest.EcdsaMissingCurve
+ *
+ * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V2.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaMissingCurve) {
+ if (AidlVersion() < 2) {
+ /*
+ * The KeyMint V1 spec required that EC_CURVE be specified for EC keys.
+ * However, this was not checked at the time so we can only be strict about checking this
+ * for implementations of KeyMint version 2 and above.
+ */
+ GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v2";
+ }
+ /* If EC_CURVE not provided, generateKey
+ * must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE.
+ */
+ auto result = GenerateKey(
+ AuthorizationSetBuilder().EcdsaKey(256).Digest(Digest::NONE).SetDefaultValidity());
+ ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
+ result == ErrorCode::UNSUPPORTED_EC_CURVE);
+}
+
+/*
* NewKeyGenerationTest.EcdsaMismatchKeySize
*
* Verifies that specifying mismatched key size and curve for EC key generation returns
@@ -5809,6 +5839,49 @@
}
/*
+ * EncryptionOperationsTest.AesCbcZeroInputSuccessb
+ *
+ * Verifies that keymaster generates correct output on zero-input with
+ * NonePadding mode
+ */
+TEST_P(EncryptionOperationsTest, AesCbcZeroInputSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE, PaddingMode::PKCS7)));
+
+ // Zero input message
+ string message = "";
+ for (auto padding : {PaddingMode::NONE, PaddingMode::PKCS7}) {
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(padding);
+ AuthorizationSet out_params;
+ string ciphertext1 = EncryptMessage(message, params, &out_params);
+ vector<uint8_t> iv1 = CopyIv(out_params);
+ if (padding == PaddingMode::NONE)
+ EXPECT_EQ(message.size(), ciphertext1.size()) << "PaddingMode: " << padding;
+ else
+ EXPECT_EQ(message.size(), ciphertext1.size() - 16) << "PaddingMode: " << padding;
+
+ out_params.Clear();
+
+ string ciphertext2 = EncryptMessage(message, params, &out_params);
+ vector<uint8_t> iv2 = CopyIv(out_params);
+ if (padding == PaddingMode::NONE)
+ EXPECT_EQ(message.size(), ciphertext2.size()) << "PaddingMode: " << padding;
+ else
+ EXPECT_EQ(message.size(), ciphertext2.size() - 16) << "PaddingMode: " << padding;
+
+ // IVs should be random
+ EXPECT_NE(iv1, iv2) << "PaddingMode: " << padding;
+
+ params.push_back(TAG_NONCE, iv1);
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext) << "PaddingMode: " << padding;
+ }
+}
+
+/*
* EncryptionOperationsTest.AesCallerNonce
*
* Verifies that AES caller-provided nonces work correctly.
@@ -6175,7 +6248,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
string ciphertext;
AuthorizationSet finish_out_params;
ASSERT_EQ(ErrorCode::OK, UpdateAad(aad));
@@ -6218,7 +6291,7 @@
.Authorization(TAG_MAC_LENGTH, tag_bits);
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
// No data, AAD only.
EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
@@ -6234,7 +6307,7 @@
begin_params.push_back(begin_out_params);
// Decrypt
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foofoo"));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Finish(ciphertext, &plaintext));
@@ -6261,7 +6334,7 @@
.Authorization(TAG_MAC_LENGTH, 128);
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
string ciphertext;
@@ -6295,7 +6368,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string ciphertext;
EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6304,7 +6377,7 @@
begin_params.push_back(begin_out_params);
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("barfoo"));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6331,7 +6404,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string ciphertext;
AuthorizationSet finish_out_params;
@@ -6341,7 +6414,7 @@
begin_params.push_back(TAG_NONCE, AidlBuf("123456789012"));
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6373,7 +6446,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
string ciphertext;
EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6385,7 +6458,7 @@
params.push_back(begin_out_params);
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6498,7 +6571,7 @@
for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
++ciphertext[ciphertext.size() / 2];
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
ErrorCode error = Finish(&plaintext);
@@ -6770,7 +6843,7 @@
auto begin_params =
AuthorizationSetBuilder().BlockMode(blockMode).Padding(PaddingMode::NONE);
AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
string ciphertext;
EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
@@ -6849,7 +6922,7 @@
for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
SCOPED_TRACE(testing::Message() << "i = " << i);
++ciphertext[ciphertext.size() / 2];
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
ErrorCode error = Finish(&plaintext);
@@ -6881,7 +6954,7 @@
AuthorizationSet input_params =
AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
string ciphertext;
for (size_t i = 0; i < message.size(); i += increment)
@@ -6895,7 +6968,7 @@
input_params.push_back(TAG_PADDING, PaddingMode::NONE);
output_params.Clear();
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
string plaintext;
for (size_t i = 0; i < ciphertext.size(); i += increment)
EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
@@ -7012,7 +7085,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
}
}
@@ -7059,7 +7132,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
}
}
@@ -7105,7 +7178,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
}
}
@@ -7152,7 +7225,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
}
}
@@ -7465,7 +7538,7 @@
EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j]))
<< "Aboort failed for i = " << j << std::endl;
}
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
AbortIfNeeded();
}
@@ -7490,7 +7563,7 @@
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
AuthorizationSet out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
string plain_message = std::string(1 << msg_size, 'x');
string encrypted_message;
@@ -7501,7 +7574,7 @@
<< "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));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
string decrypted_message;
rc = Finish(encrypted_message, &decrypted_message);
@@ -7537,7 +7610,6 @@
uint8_t privKeyData[32];
uint8_t pubKeyData[32];
X25519_keypair(pubKeyData, privKeyData);
- *localPublicKey = vector<uint8_t>(pubKeyData, pubKeyData + 32);
*localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new_raw_private_key(
EVP_PKEY_X25519, nullptr, privKeyData, sizeof(privKeyData)));
} else {
@@ -7549,16 +7621,15 @@
ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1);
*localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new());
ASSERT_EQ(EVP_PKEY_set1_EC_KEY(localPrivKey->get(), ecKey.get()), 1);
-
- // Get encoded form of the public part of the locally generated key...
- unsigned char* p = nullptr;
- int localPublicKeySize = i2d_PUBKEY(localPrivKey->get(), &p);
- ASSERT_GT(localPublicKeySize, 0);
- *localPublicKey =
- vector<uint8_t>(reinterpret_cast<const uint8_t*>(p),
- reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
- OPENSSL_free(p);
}
+
+ // Get encoded form of the public part of the locally generated key...
+ unsigned char* p = nullptr;
+ int localPublicKeySize = i2d_PUBKEY(localPrivKey->get(), &p);
+ ASSERT_GT(localPublicKeySize, 0);
+ *localPublicKey = vector<uint8_t>(reinterpret_cast<const uint8_t*>(p),
+ reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
+ OPENSSL_free(p);
}
void GenerateKeyMintEcKey(EcCurve curve, EVP_PKEY_Ptr* kmPubKey) {
@@ -7653,6 +7724,9 @@
//
for (auto curve : ValidCurves()) {
for (auto localCurve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message()
+ << "local-curve-" << localCurve << "-keymint-curve-" << curve);
+
// Generate EC key locally (with access to private key material)
EVP_PKEY_Ptr localPrivKey;
vector<uint8_t> localPublicKey;
@@ -7666,7 +7740,7 @@
if (curve != localCurve) {
// If the keys are using different curves KeyMint should fail with
// ErrorCode:INVALID_ARGUMENT. Check that.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
string ZabFromKeyMintStr;
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
Finish(string(localPublicKey.begin(), localPublicKey.end()),
@@ -7806,7 +7880,7 @@
vector<uint8_t> encodedPublicKey;
GenerateLocalEcKey(localCurve, &privKey, &encodedPublicKey);
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
string ZabFromKeyMintStr;
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
@@ -8002,6 +8076,18 @@
INSTANTIATE_KEYMINT_AIDL_TEST(UnlockedDeviceRequiredTest);
+using VsrRequirementTest = KeyMintAidlTestBase;
+
+TEST_P(VsrRequirementTest, Vsr13Test) {
+ int vsr_api_level = get_vsr_api_level();
+ if (vsr_api_level < 33) {
+ GTEST_SKIP() << "Applies only to VSR API level 33, this device is: " << vsr_api_level;
+ }
+ EXPECT_GE(AidlVersion(), 2) << "VSR 13+ requires KeyMint version 2";
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(VsrRequirementTest);
+
} // namespace aidl::android::hardware::security::keymint::test
int main(int argc, char** argv) {
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index 6f13867..c9a156d 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -36,6 +36,8 @@
using std::shared_ptr;
using std::vector;
+constexpr int kRoTVersion1 = 40001;
+
class SecureElementProvisioningTest : public testing::Test {
protected:
static void SetUpTestSuite() {
@@ -57,6 +59,92 @@
}
}
+ void validateMacedRootOfTrust(const vector<uint8_t>& rootOfTrust) {
+ SCOPED_TRACE(testing::Message() << "RoT: " << bin2hex(rootOfTrust));
+
+ const auto [macItem, macEndPos, macErrMsg] = cppbor::parse(rootOfTrust);
+ ASSERT_TRUE(macItem) << "Root of trust parsing failed: " << macErrMsg;
+ ASSERT_EQ(macItem->semanticTagCount(), 1);
+ ASSERT_EQ(macItem->semanticTag(0), cppcose::kCoseMac0SemanticTag);
+ ASSERT_TRUE(macItem->asArray());
+ ASSERT_EQ(macItem->asArray()->size(), cppcose::kCoseMac0EntryCount);
+
+ const auto& protectedItem = macItem->asArray()->get(cppcose::kCoseMac0ProtectedParams);
+ ASSERT_TRUE(protectedItem);
+ ASSERT_TRUE(protectedItem->asBstr());
+ const auto [protMap, protEndPos, protErrMsg] = cppbor::parse(protectedItem->asBstr());
+ ASSERT_TRUE(protMap);
+ ASSERT_TRUE(protMap->asMap());
+ ASSERT_EQ(protMap->asMap()->size(), 1);
+
+ const auto& algorithm = protMap->asMap()->get(cppcose::ALGORITHM);
+ ASSERT_TRUE(algorithm);
+ ASSERT_TRUE(algorithm->asInt());
+ ASSERT_EQ(algorithm->asInt()->value(), cppcose::HMAC_256);
+
+ const auto& unprotItem = macItem->asArray()->get(cppcose::kCoseMac0UnprotectedParams);
+ ASSERT_TRUE(unprotItem);
+ ASSERT_TRUE(unprotItem->asMap());
+ ASSERT_EQ(unprotItem->asMap()->size(), 0);
+
+ const auto& payload = macItem->asArray()->get(cppcose::kCoseMac0Payload);
+ ASSERT_TRUE(payload);
+ ASSERT_TRUE(payload->asBstr());
+ validateRootOfTrust(payload->asBstr()->value());
+
+ const auto& tag = macItem->asArray()->get(cppcose::kCoseMac0Tag);
+ ASSERT_TRUE(tag);
+ ASSERT_TRUE(tag->asBstr());
+ ASSERT_EQ(tag->asBstr()->value().size(), 32);
+ // Cannot validate tag correctness. Only the secure side has the necessary key.
+ }
+
+ void validateRootOfTrust(const vector<uint8_t>& payload) {
+ SCOPED_TRACE(testing::Message() << "RoT payload: " << bin2hex(payload));
+
+ const auto [rot, rotPos, rotErrMsg] = cppbor::parse(payload);
+ ASSERT_TRUE(rot);
+ ASSERT_EQ(rot->semanticTagCount(), 1);
+ ASSERT_EQ(rot->semanticTag(), kRoTVersion1);
+ ASSERT_TRUE(rot->asArray());
+ ASSERT_EQ(rot->asArray()->size(), 5);
+
+ size_t pos = 0;
+
+ const auto& vbKey = rot->asArray()->get(pos++);
+ ASSERT_TRUE(vbKey);
+ ASSERT_TRUE(vbKey->asBstr());
+
+ const auto& deviceLocked = rot->asArray()->get(pos++);
+ ASSERT_TRUE(deviceLocked);
+ ASSERT_TRUE(deviceLocked->asBool());
+
+ const auto& verifiedBootState = rot->asArray()->get(pos++);
+ ASSERT_TRUE(verifiedBootState);
+ ASSERT_TRUE(verifiedBootState->asInt());
+
+ const auto& verifiedBootHash = rot->asArray()->get(pos++);
+ ASSERT_TRUE(verifiedBootHash);
+ ASSERT_TRUE(verifiedBootHash->asBstr());
+
+ const auto& bootPatchLevel = rot->asArray()->get(pos++);
+ ASSERT_TRUE(bootPatchLevel);
+ ASSERT_TRUE(bootPatchLevel->asInt());
+
+ verify_root_of_trust(vbKey->asBstr()->value(), deviceLocked->asBool()->value(),
+ static_cast<VerifiedBoot>(verifiedBootState->asInt()->value()),
+ verifiedBootHash->asBstr()->value());
+ }
+
+ int32_t AidlVersion(shared_ptr<IKeyMintDevice> keymint) {
+ int32_t version = 0;
+ auto status = keymint->getInterfaceVersion(&version);
+ if (!status.isOk()) {
+ ADD_FAILURE() << "Failed to determine interface version";
+ }
+ return version;
+ }
+
static map<SecurityLevel, shared_ptr<IKeyMintDevice>> keymints_;
};
@@ -73,50 +161,44 @@
}
TEST_F(SecureElementProvisioningTest, TeeOnly) {
- if (keymints_.empty()) {
- GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+ if (keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT) == 0) {
+ GTEST_SKIP() << "Test not applicable to device with no TEE KeyMint device";
}
- ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
- ASSERT_NE(tee, nullptr);
+ // Execute the test only for KeyMint version >= 2.
+ if (AidlVersion(tee) < 2) {
+ GTEST_SKIP() << "Test not applicable to TEE KeyMint device before v2";
+ }
array<uint8_t, 16> challenge1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
array<uint8_t, 16> challenge2 = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
vector<uint8_t> rootOfTrust1;
Status result = tee->getRootOfTrust(challenge1, &rootOfTrust1);
-
- // TODO: Remove the next line to require TEEs to succeed.
- if (!result.isOk()) return;
-
- ASSERT_TRUE(result.isOk());
-
- // TODO: Parse and validate rootOfTrust1 here
+ ASSERT_TRUE(result.isOk()) << "getRootOfTrust returned " << result.getServiceSpecificError();
+ validateMacedRootOfTrust(rootOfTrust1);
vector<uint8_t> rootOfTrust2;
result = tee->getRootOfTrust(challenge2, &rootOfTrust2);
ASSERT_TRUE(result.isOk());
-
- // TODO: Parse and validate rootOfTrust2 here
-
+ validateMacedRootOfTrust(rootOfTrust2);
ASSERT_NE(rootOfTrust1, rootOfTrust2);
vector<uint8_t> rootOfTrust3;
result = tee->getRootOfTrust(challenge1, &rootOfTrust3);
ASSERT_TRUE(result.isOk());
-
ASSERT_EQ(rootOfTrust1, rootOfTrust3);
-
- // TODO: Parse and validate rootOfTrust3 here
}
TEST_F(SecureElementProvisioningTest, TeeDoesNotImplementStrongBoxMethods) {
- if (keymints_.empty()) {
- GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+ if (keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT) == 0) {
+ GTEST_SKIP() << "Test not applicable to device with no TEE KeyMint device";
}
- ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
- ASSERT_NE(tee, nullptr);
+ // Execute the test only for KeyMint version >= 2.
+ if (AidlVersion(tee) < 2) {
+ GTEST_SKIP() << "Test not applicable to TEE KeyMint device before v2";
+ }
array<uint8_t, 16> challenge;
Status result = tee->getRootOfTrustChallenge(&challenge);
@@ -135,9 +217,11 @@
// Need a StrongBox to provision.
GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
}
-
+ // Execute the test only for KeyMint version >= 2.
auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
- ASSERT_NE(sb, nullptr);
+ if (AidlVersion(sb) < 2) {
+ GTEST_SKIP() << "Test not applicable to StrongBox KeyMint device before v2";
+ }
vector<uint8_t> rootOfTrust;
Status result = sb->getRootOfTrust({}, &rootOfTrust);
@@ -151,14 +235,19 @@
// Need a StrongBox to provision.
GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
}
-
- ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
- auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
- ASSERT_NE(tee, nullptr);
-
- ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+ // Execute the test only for KeyMint version >= 2.
auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
- ASSERT_NE(sb, nullptr);
+ if (AidlVersion(sb) < 2) {
+ GTEST_SKIP() << "Test not applicable to StrongBox KeyMint device before v2";
+ }
+
+ if (keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT) == 0) {
+ GTEST_SKIP() << "Test not applicable to device with no TEE KeyMint device";
+ }
+ auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+ if (AidlVersion(tee) < 2) {
+ GTEST_SKIP() << "Test not applicable to TEE KeyMint device before v2";
+ }
array<uint8_t, 16> challenge;
Status result = sb->getRootOfTrustChallenge(&challenge);
@@ -185,10 +274,11 @@
// Need a StrongBox to provision.
GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
}
-
- ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+ // Execute the test only for KeyMint version >= 2.
auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
- ASSERT_NE(sb, nullptr);
+ if (AidlVersion(sb) < 2) {
+ GTEST_SKIP() << "Test not applicable to StrongBox KeyMint device before v2";
+ }
array<uint8_t, 16> challenge1;
Status result = sb->getRootOfTrustChallenge(&challenge1);
@@ -208,14 +298,20 @@
// Need a StrongBox to provision.
GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
}
-
- ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
- auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
- ASSERT_NE(tee, nullptr);
-
- ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+ // Execute the test only for KeyMint version >= 2.
auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
- ASSERT_NE(sb, nullptr);
+ if (AidlVersion(sb) < 2) {
+ GTEST_SKIP() << "Test not applicable to StrongBox KeyMint device before v2";
+ }
+
+ if (keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT) == 0) {
+ GTEST_SKIP() << "Test not applicable to device with no TEE KeyMint device";
+ }
+ // Execute the test only for KeyMint version >= 2.
+ auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+ if (AidlVersion(tee) < 2) {
+ GTEST_SKIP() << "Test not applicable to TEE KeyMint device before v2";
+ }
array<uint8_t, 16> challenge;
Status result = sb->getRootOfTrustChallenge(&challenge);
@@ -225,7 +321,7 @@
result = tee->getRootOfTrust(challenge, &rootOfTrust);
ASSERT_TRUE(result.isOk());
- // TODO: Verify COSE_Mac0 structure and content here.
+ validateMacedRootOfTrust(rootOfTrust);
result = sb->sendRootOfTrust(rootOfTrust);
ASSERT_TRUE(result.isOk());
@@ -240,14 +336,20 @@
// Need a StrongBox to provision.
GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
}
-
- ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
- auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
- ASSERT_NE(tee, nullptr);
-
- ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+ // Execute the test only for KeyMint version >= 2.
auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
- ASSERT_NE(sb, nullptr);
+ if (AidlVersion(sb) < 2) {
+ GTEST_SKIP() << "Test not applicable to StrongBox KeyMint device before v2";
+ }
+
+ if (keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT) == 0) {
+ GTEST_SKIP() << "Test not applicable to device with no TEE KeyMint device";
+ }
+ // Execute the test only for KeyMint version >= 2.
+ auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+ if (AidlVersion(tee) < 2) {
+ GTEST_SKIP() << "Test not applicable to TEE KeyMint device before v2";
+ }
array<uint8_t, 16> challenge;
Status result = sb->getRootOfTrustChallenge(&challenge);
@@ -263,6 +365,8 @@
result = tee->getRootOfTrust(challenge, &rootOfTrust);
ASSERT_TRUE(result.isOk());
+ validateMacedRootOfTrust(rootOfTrust);
+
vector<uint8_t> corruptedRootOfTrust = rootOfTrust;
corruptedRootOfTrust[corruptedRootOfTrust.size() / 2]++;
result = sb->sendRootOfTrust(corruptedRootOfTrust);
diff --git a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
index 54b6fdc..5bbae4c 100644
--- a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -142,6 +142,25 @@
return Digest::NONE;
}
+ optional<EcCurve> getCurveFromLength(int keySize) {
+ switch (keySize) {
+ case 224:
+ return EcCurve::P_224;
+ break;
+ case 256:
+ return EcCurve::P_256;
+ break;
+ case 384:
+ return EcCurve::P_384;
+ break;
+ case 521:
+ return EcCurve::P_521;
+ break;
+ default:
+ return {};
+ }
+ }
+
bool GenerateKey(string transform, int keySize, bool sign = false) {
if (transform == key_transform_) {
return true;
@@ -184,6 +203,12 @@
}
if (algorithm == Algorithm::EC) {
authSet.SetDefaultValidity();
+ std::optional<EcCurve> curve = getCurveFromLength(keySize);
+ if (!curve) {
+ std::cerr << "Error: invalid EC-Curve from size " << keySize << std::endl;
+ return false;
+ }
+ authSet.Authorization(TAG_EC_CURVE, curve.value());
}
error_ = GenerateKey(authSet);
return error_ == ErrorCode::OK;
diff --git a/security/secureclock/aidl/Android.bp b/security/secureclock/aidl/Android.bp
index 00a6ba3..853ad89 100644
--- a/security/secureclock/aidl/Android.bp
+++ b/security/secureclock/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
rust: {
enabled: true,
apex_available: [
diff --git a/security/sharedsecret/aidl/Android.bp b/security/sharedsecret/aidl/Android.bp
index f1fce74..fe77c10 100644
--- a/security/sharedsecret/aidl/Android.bp
+++ b/security/sharedsecret/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
rust: {
enabled: true,
},
diff --git a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
index 8144699..b72f0de 100644
--- a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
+++ b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
@@ -33,9 +33,9 @@
byte[] seed;
/**
- * A 32-byte value which is guaranteed to be different each time
- * getSharedSecretParameters() is called. Probabilistic uniqueness (i.e. random) is acceptable,
- * though a stronger uniqueness guarantee (e.g. counter) is recommended where possible.
+ * A 32-byte value which is guaranteed to be different each time getSharedSecretParameters() is
+ * called after a restart. Probabilistic uniqueness (i.e. random) is acceptable, though a
+ * stronger uniqueness guarantee (e.g. counter) is recommended where possible.
*/
byte[] nonce;
}
diff --git a/usb/aidl/Android.bp b/usb/aidl/Android.bp
index f71cacb..f01b44e 100644
--- a/usb/aidl/Android.bp
+++ b/usb/aidl/Android.bp
@@ -33,10 +33,5 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index d4d5857..86ef027 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -19,11 +19,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: [
"1",
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index a8ae777..791d7e8 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -196,7 +196,7 @@
active.startFrequency = frequencyHz;
active.endAmplitude = (getAmplitudeMin() + getAmplitudeMax()) / 2;
active.endFrequency = frequencyHz;
- active.duration = 1000;
+ vibrator->getPwlePrimitiveDurationMax(&(active.duration));
return active;
}
@@ -332,6 +332,7 @@
sleep(1);
EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
sleep(1);
+ EXPECT_TRUE(vibrator->off().isOk());
}
}
@@ -417,6 +418,9 @@
if (isPrimitiveSupported) {
EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
+ if (primitive != CompositePrimitive::NOOP) {
+ ASSERT_GT(duration, 0) << toString(primitive) << " " << duration;
+ }
} else {
EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
}
@@ -756,7 +760,9 @@
std::future<void> completionFuture{completionPromise.get_future()};
sp<CompletionCallback> callback =
new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
- uint32_t durationMs = 2100; // Sum of 2 active and 1 braking below
+ int32_t segmentDurationMaxMs;
+ vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
+ uint32_t durationMs = segmentDurationMaxMs * 2 + 100; // Sum of 2 active and 1 braking below
//TODO(b/187207798): revert back to conservative timeout values once
//latencies have been fixed
std::chrono::milliseconds timeout{durationMs * 4};
@@ -860,7 +866,7 @@
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
ActivePwle active = composeValidActivePwle(vibrator, capabilities);
- int segmentDurationMaxMs;
+ int32_t segmentDurationMaxMs;
vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
active.duration = segmentDurationMaxMs + 10; // Segment duration greater than allowed
diff --git a/weaver/aidl/Android.bp b/weaver/aidl/Android.bp
index 8b4306f..caa92aa 100644
--- a/weaver/aidl/Android.bp
+++ b/weaver/aidl/Android.bp
@@ -16,11 +16,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp
index fcd06ff..c48a4ec 100644
--- a/wifi/hostapd/aidl/Android.bp
+++ b/wifi/hostapd/aidl/Android.bp
@@ -37,10 +37,5 @@
],
min_sdk_version: "30",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
index eabbf1b..da3ff3a 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
@@ -38,11 +38,12 @@
: public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
public:
virtual void SetUp() override {
- // Stop Wi-Fi
- ASSERT_TRUE(stopWifiFramework()); // stop & wait for wifi to shutdown.
-
wifi_instance_name_ = std::get<0>(GetParam());
supplicant_instance_name_ = std::get<1>(GetParam());
+
+ // Stop & wait for wifi to shutdown.
+ ASSERT_TRUE(stopWifiFramework(wifi_instance_name_));
+
std::system("/system/bin/start");
ASSERT_TRUE(waitForFrameworkReady());
isP2pOn_ =
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 086166a..6760663 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -28,26 +28,42 @@
using ::android::sp;
using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::joinRpcThreadpool;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using ::android::hardware::joinRpcThreadpool;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hardware::wifi::V1_0::ChipModeId;
-using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
using ::android::hardware::wifi::supplicant::V1_0::ISupplicantIface;
using ::android::hardware::wifi::supplicant::V1_0::ISupplicantNetwork;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
-using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
-using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
using ::android::wifi_system::InterfaceTool;
using ::android::wifi_system::SupplicantManager;
namespace {
+
+bool waitForWifiHalStop(const std::string& wifi_instance_name) {
+ sp<IWifi> wifi = getWifi(wifi_instance_name);
+ int count = 50; /* wait at most 5 seconds for completion */
+ while (count-- > 0) {
+ if (wifi != nullptr && !wifi->isStarted()) {
+ return true;
+ }
+ usleep(100000);
+ wifi = getWifi(wifi_instance_name);
+ }
+ LOG(ERROR) << "Wifi HAL was not stopped";
+ return false;
+}
+
bool waitForSupplicantState(bool is_running) {
SupplicantManager supplicant_manager;
int count = 50; /* wait at most 5 seconds for completion */
@@ -113,10 +129,10 @@
return waitForSupplicantStart(); // wait for wifi to start.
}
-bool stopWifiFramework() {
+bool stopWifiFramework(const std::string& wifi_instance_name) {
std::system("svc wifi disable");
std::system("cmd wifi set-scan-always-available disabled");
- return waitForSupplicantStop(); // wait for wifi to shutdown.
+ return waitForSupplicantStop() && waitForWifiHalStop(wifi_instance_name);
}
void stopSupplicant() { stopSupplicant(""); }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 7228623..2198d7c 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -33,7 +33,7 @@
bool startWifiFramework();
// Used to stop the android wifi framework before every test.
-bool stopWifiFramework();
+bool stopWifiFramework(const std::string& wifi_instance_name);
void stopSupplicant(const std::string& wifi_instance_name);
// Used to configure the chip, driver and start wpa_supplicant before every
@@ -77,12 +77,13 @@
: public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
public:
virtual void SetUp() override {
- // Stop Wi-Fi
- ASSERT_TRUE(stopWifiFramework()); // stop & wait for wifi to shutdown.
-
- // should always be v1.0 wifi
- wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+ wifi_v1_0_instance_name_ =
+ std::get<0>(GetParam()); // should always be v1.0 wifi
supplicant_instance_name_ = std::get<1>(GetParam());
+
+ // Stop & wait for wifi to shutdown.
+ ASSERT_TRUE(stopWifiFramework(wifi_v1_0_instance_name_));
+
std::system("/system/bin/start");
ASSERT_TRUE(waitForFrameworkReady());
isP2pOn_ =
diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp
index d00dd21..06367ba 100644
--- a/wifi/supplicant/aidl/Android.bp
+++ b/wifi/supplicant/aidl/Android.bp
@@ -37,10 +37,5 @@
],
min_sdk_version: "30",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
index 17e0394..31042a2 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
@@ -78,7 +78,7 @@
void stopSupplicantService() { stopSupplicant(getWifiInstanceName()); }
void initializeService() {
- ASSERT_TRUE(stopWifiFramework());
+ ASSERT_TRUE(stopWifiFramework(getWifiInstanceName()));
std::system("/system/bin/start");
ASSERT_TRUE(waitForFrameworkReady());
stopSupplicantService();