[automerger skipped] Effect AIDL: remove placeholder effect from default implementation am: f84adb0fad -s ours
am skip reason: Merged-In Icf15e349a2ad36eeefa1e3eb46428c04ae164ad1 with SHA-1 7a0eb7b7a7 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/hardware/interfaces/+/26519773
Change-Id: I0c4a63505e6ba574229ce983fbedd245792feefe
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
index 01db90e..1814b59 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -116,6 +116,7 @@
enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_HD;
enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_CELT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DEFAULT;
enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DSD;
enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS;
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index c2b8c5d..177af16 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -302,6 +302,7 @@
TODO: generate from hidl to avoid manual sync. -->
<xs:simpleType name="audioFormat">
<xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_FORMAT_DEFAULT" />
<xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
<xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
<xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 94aa4dc..6bbdb1a 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -1169,9 +1169,12 @@
if (in_requested.ext.getTag() != AudioPortExt::Tag::unspecified) {
if (in_requested.ext.getTag() == out_suggested->ext.getTag()) {
if (out_suggested->ext.getTag() == AudioPortExt::Tag::mix) {
- // 'AudioMixPortExt.handle' is set by the client, copy from in_requested
- out_suggested->ext.get<AudioPortExt::Tag::mix>().handle =
- in_requested.ext.get<AudioPortExt::Tag::mix>().handle;
+ // 'AudioMixPortExt.handle' and '.usecase' are set by the client,
+ // copy from in_requested.
+ const auto& src = in_requested.ext.get<AudioPortExt::Tag::mix>();
+ auto& dst = out_suggested->ext.get<AudioPortExt::Tag::mix>();
+ dst.handle = src.handle;
+ dst.usecase = src.usecase;
}
} else {
LOG(WARNING) << __func__ << ": requested ext tag "
diff --git a/audio/aidl/default/apex/com.android.hardware.audio/Android.bp b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
index ee7e46e..ee92512 100644
--- a/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
+++ b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
@@ -46,5 +46,6 @@
prebuilts: [
"android.hardware.audio.service-aidl.example.rc",
"android.hardware.audio.service-aidl.xml",
+ "android.hardware.bluetooth.audio.xml",
],
}
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index 7100431..54b82d3 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -23,6 +23,7 @@
#include <aidl/Vintf.h>
#include <android/binder_auto_utils.h>
+#include <system/audio_effects/aidl_effects_utils.h>
#include "AudioHalBinderServiceUtil.h"
#include "TestUtils.h"
@@ -35,21 +36,6 @@
class EffectFactoryHelper {
public:
- explicit EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
-
- void ConnectToFactoryService() {
- mEffectFactory = IFactory::fromBinder(binderUtil.connectToService(mServiceName));
- ASSERT_NE(mEffectFactory, nullptr);
- }
-
- void RestartFactoryService() {
- ASSERT_NE(mEffectFactory, nullptr);
- mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
- ASSERT_NE(mEffectFactory, nullptr);
- }
-
- std::shared_ptr<IFactory> GetFactory() const { return mEffectFactory; }
-
static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> getAllEffectDescriptors(
std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
AudioHalBinderServiceUtil util;
@@ -74,8 +60,13 @@
return result;
}
- private:
- std::shared_ptr<IFactory> mEffectFactory;
- std::string mServiceName;
- AudioHalBinderServiceUtil binderUtil;
+ static int getHalVersion(const std::shared_ptr<IFactory>& factory) {
+ int version = 0;
+ return (factory && factory->getInterfaceVersion(&version).isOk()) ? version : 0;
+ }
+
+ static bool isReopenSupported(const std::shared_ptr<IFactory>& factory) {
+ return EffectFactoryHelper::getHalVersion(factory) >=
+ aidl::android::hardware::audio::effect::kReopenSupportedVersion;
+ }
};
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index 4e86ec3..21df163 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -56,10 +56,7 @@
/// Effect factory testing.
class EffectFactoryTest : public testing::TestWithParam<std::string> {
public:
- void SetUp() override {
- mFactoryHelper = std::make_unique<EffectFactoryHelper>(GetParam());
- connectAndGetFactory();
- }
+ void SetUp() override { connectAndGetFactory(); }
void TearDown() override {
for (auto& effect : mEffects) {
@@ -68,13 +65,14 @@
}
}
- std::unique_ptr<EffectFactoryHelper> mFactoryHelper;
+ std::string kServiceName = GetParam();
std::shared_ptr<IFactory> mEffectFactory;
std::vector<std::shared_ptr<IEffect>> mEffects;
const Descriptor::Identity kNullId = {.uuid = getEffectUuidNull()};
const Descriptor::Identity kZeroId = {.uuid = getEffectUuidZero()};
const Descriptor kNullDesc = {.common.id = kNullId};
const Descriptor kZeroDesc = {.common.id = kZeroId};
+ AudioHalBinderServiceUtil mBinderUtil;
template <typename Functor>
void ForEachId(const std::vector<Descriptor::Identity> ids, Functor functor) {
@@ -117,8 +115,7 @@
}
}
void connectAndGetFactory() {
- ASSERT_NO_FATAL_FAILURE(mFactoryHelper->ConnectToFactoryService());
- mEffectFactory = mFactoryHelper->GetFactory();
+ mEffectFactory = IFactory::fromBinder(mBinderUtil.connectToService(kServiceName));
ASSERT_NE(mEffectFactory, nullptr);
}
};
@@ -128,7 +125,9 @@
}
TEST_P(EffectFactoryTest, CanBeRestarted) {
- ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
+ ASSERT_NE(mEffectFactory, nullptr);
+ mEffectFactory = IFactory::fromBinder(mBinderUtil.restartService());
+ ASSERT_NE(mEffectFactory, nullptr);
}
/**
@@ -250,7 +249,8 @@
EXPECT_NE(descs.size(), 0UL);
creatAndDestroyDescs(descs);
- mFactoryHelper->RestartFactoryService();
+ mEffectFactory = IFactory::fromBinder(mBinderUtil.restartService());
+ ASSERT_NE(mEffectFactory, nullptr);
connectAndGetFactory();
creatAndDestroyDescs(descs);
@@ -263,7 +263,8 @@
EXPECT_NE(descs.size(), 0UL);
std::vector<std::shared_ptr<IEffect>> effects = createWithDescs(descs);
- ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
+ mEffectFactory = IFactory::fromBinder(mBinderUtil.restartService());
+ ASSERT_NE(mEffectFactory, nullptr);
connectAndGetFactory();
destroyEffects(effects, EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 5479825..4693f10 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -42,6 +42,7 @@
using aidl::android::hardware::audio::effect::Flags;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kReopenSupportedVersion;
using aidl::android::hardware::audio::effect::Parameter;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioDeviceDescription;
@@ -613,6 +614,10 @@
* verify reopen sequence.
*/
TEST_P(AudioEffectDataPathTest, SetCommonParameterAndReopen) {
+ if (!EffectFactoryHelper::isReopenSupported(mFactory)) {
+ GTEST_SKIP() << "Skipping test as effect does not support reopen";
+ }
+
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
@@ -732,6 +737,10 @@
// Send data to effects and expect it to be consumed after effect reopen (IO AudioConfig change).
// Effects exposing bypass flags or operating in offload mode will be skipped.
TEST_P(AudioEffectDataPathTest, ConsumeDataAfterReopen) {
+ if (!EffectFactoryHelper::isReopenSupported(mFactory)) {
+ GTEST_SKIP() << "Skipping test as effect does not support reopen";
+ }
+
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 4846bfb..f021f7b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -449,7 +449,8 @@
{.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_FRONT_ROW},
+ VehicleAreaConfig{.areaId = HVAC_REAR_ROW}}},
.initialValue = {.int32Values = {0}}},
{.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
index f58e09a..e866f70 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h
@@ -50,6 +50,9 @@
VehicleAreaWheel::LEFT_REAR | VehicleAreaWheel::RIGHT_REAR);
constexpr int SEAT_1_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT);
constexpr int SEAT_1_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT);
+constexpr int HVAC_FRONT_ROW = (int)(VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT);
+constexpr int HVAC_REAR_ROW = (int)(VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
+ VehicleAreaSeat::ROW_2_RIGHT);
constexpr int HVAC_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_2_LEFT |
VehicleAreaSeat::ROW_2_CENTER);
constexpr int HVAC_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT | VehicleAreaSeat::ROW_2_RIGHT);
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index ea1437e..57af04c 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -104,6 +104,8 @@
{"HVAC_ALL", HVAC_ALL},
{"HVAC_LEFT", HVAC_LEFT},
{"HVAC_RIGHT", HVAC_RIGHT},
+ {"HVAC_FRONT_ROW", HVAC_FRONT_ROW},
+ {"HVAC_REAR_ROW", HVAC_REAR_ROW},
{"WINDOW_1_LEFT", WINDOW_1_LEFT},
{"WINDOW_1_RIGHT", WINDOW_1_RIGHT},
{"WINDOW_2_LEFT", WINDOW_2_LEFT},
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 0a859af..2d1e9ab 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -2033,19 +2033,10 @@
},
"areas": [
{
- "areaId": "Constants::SEAT_1_LEFT"
+ "areaId": "Constants::HVAC_FRONT_ROW"
},
{
- "areaId": "Constants::SEAT_1_RIGHT"
- },
- {
- "areaId": "Constants::SEAT_2_LEFT"
- },
- {
- "areaId": "Constants::SEAT_2_RIGHT"
- },
- {
- "areaId": "Constants::SEAT_2_CENTER"
+ "areaId": "Constants::HVAC_REAR_ROW"
}
]
},
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index 78b61f7..f2327e1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -97,6 +97,8 @@
constexpr int HVAC_LEFT = SEAT_1_LEFT | SEAT_2_LEFT | SEAT_2_CENTER;
constexpr int HVAC_RIGHT = SEAT_1_RIGHT | SEAT_2_RIGHT;
constexpr int HVAC_ALL = HVAC_LEFT | HVAC_RIGHT;
+constexpr int HVAC_FRONT_ROW = SEAT_1_LEFT | SEAT_1_RIGHT;
+constexpr int HVAC_REAR_ROW = SEAT_2_LEFT | SEAT_2_CENTER | SEAT_2_RIGHT;
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 6a2a695..97efdf6 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -153,10 +153,9 @@
propValue->status = oldStatus;
}
+ // areaId and propId must be the same between valueToUpdate and propValue.
valueUpdated = (valueToUpdate->value != propValue->value ||
- valueToUpdate->status != propValue->status ||
- valueToUpdate->prop != propValue->prop ||
- valueToUpdate->areaId != propValue->areaId);
+ valueToUpdate->status != propValue->status);
} else if (!updateStatus) {
propValue->status = VehiclePropertyStatus::AVAILABLE;
}
diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp
index 69db1b3..af6bf86 100644
--- a/bluetooth/audio/aidl/default/Android.bp
+++ b/bluetooth/audio/aidl/default/Android.bp
@@ -40,3 +40,10 @@
"libbluetooth_audio_session_aidl",
],
}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth.audio.xml",
+ src: "bluetooth_audio.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
index 584640b..dc36ac0 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -39,6 +39,9 @@
static const std::string kLeAudioOffloadProviderName =
"LE_AUDIO_OFFLOAD_HARDWARE_OFFLOAD_PROVIDER";
+static const std::string kHfpOffloadProviderName =
+ "HFP_OFFLOAD_HARDWARE_OFFLOAD_PROVIDER";
+
BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
@@ -170,6 +173,7 @@
provider_info.name = a2dp_offload_codec_factory_.name;
for (auto codec : a2dp_offload_codec_factory_.codecs)
provider_info.codecInfos.push_back(codec->info);
+ return ndk::ScopedAStatus::ok();
}
if (session_type ==
@@ -184,12 +188,23 @@
auto& provider_info = _aidl_return->emplace();
provider_info.name = kLeAudioOffloadProviderName;
provider_info.codecInfos = db_codec_info;
- *_aidl_return = provider_info;
return ndk::ScopedAStatus::ok();
}
}
- return ndk::ScopedAStatus::ok();
+ if (session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH) {
+ std::vector<CodecInfo> db_codec_info =
+ BluetoothAudioCodecs::GetHfpOffloadCodecInfo();
+ if (!db_codec_info.empty()) {
+ auto& provider_info = _aidl_return->emplace();
+ provider_info.name = kHfpOffloadProviderName;
+ provider_info.codecInfos = db_codec_info;
+ return ndk::ScopedAStatus::ok();
+ }
+ }
+
+ // Unsupported for other sessions
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
} // namespace audio
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index 789e8a1..c313fb7 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -1944,6 +1944,7 @@
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
+ GetProviderInfoHelper(SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
OpenProviderHelper(SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
// Can open or empty capability
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index c0817f5..cecf8f0 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -42,6 +42,7 @@
"aidl_session/BluetoothAudioSession.cpp",
"aidl_session/HidlToAidlMiddleware.cpp",
"aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+ "aidl_session/BluetoothHfpCodecsProvider.cpp",
"aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp",
],
export_include_dirs: ["aidl_session/"],
@@ -68,9 +69,13 @@
static_libs: [
"btaudiohal_flags_c_lib",
],
- generated_sources: ["le_audio_codec_capabilities"],
+ generated_sources: [
+ "le_audio_codec_capabilities",
+ "hfp_codec_capabilities",
+ ],
generated_headers: [
"le_audio_codec_capabilities",
+ "hfp_codec_capabilities",
"AIDLLeAudioSetConfigSchemas_h",
],
required: [
@@ -78,6 +83,7 @@
"aidl_audio_set_configurations_json",
"aidl_audio_set_scenarios_bfbs",
"aidl_audio_set_scenarios_json",
+ "hfp_codec_capabilities_xml",
],
}
@@ -106,6 +112,35 @@
generated_headers: ["le_audio_codec_capabilities"],
}
+cc_test {
+ name: "BluetoothHfpCodecsProviderTest",
+ defaults: [
+ "latest_android_hardware_audio_common_ndk_static",
+ "latest_android_hardware_bluetooth_audio_ndk_static",
+ "latest_android_media_audio_common_types_ndk_static",
+ ],
+ srcs: [
+ "aidl_session/BluetoothHfpCodecsProvider.cpp",
+ "aidl_session/BluetoothHfpCodecsProviderTest.cpp",
+ ],
+ header_libs: [
+ "libxsdc-utils",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libxml2",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ test_options: {
+ unit_test: false,
+ },
+ generated_sources: ["hfp_codec_capabilities"],
+ generated_headers: ["hfp_codec_capabilities"],
+}
+
xsd_config {
name: "le_audio_codec_capabilities",
srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
@@ -114,6 +149,14 @@
root_elements: ["leAudioOffloadSetting"],
}
+xsd_config {
+ name: "hfp_codec_capabilities",
+ srcs: ["hfp_codec_capabilities/hfp_codec_capabilities.xsd"],
+ package_name: "aidl.android.hardware.bluetooth.audio.hfp.setting",
+ api_dir: "hfp_codec_capabilities/schema",
+ root_elements: ["hfpOffloadSetting"],
+}
+
genrule {
name: "AIDLLeAudioSetConfigSchemas_h",
tools: [
@@ -177,6 +220,14 @@
}
prebuilt_etc {
+ name: "hfp_codec_capabilities_xml",
+ src: "hfp_codec_capabilities/hfp_codec_capabilities.xml",
+ filename: "hfp_codec_capabilities.xml",
+ sub_dir: "aidl/hfp",
+ vendor: true,
+}
+
+prebuilt_etc {
name: "aidl_audio_set_configurations_bfbs",
src: ":AIDLLeAudioSetConfigsSchema_bfbs",
filename: "aidl_audio_set_configurations.bfbs",
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index d37825a..c25b102 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -32,6 +32,7 @@
#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
#include <android-base/logging.h>
+#include "BluetoothHfpCodecsProvider.h"
#include "BluetoothLeAudioAseConfigurationSettingProvider.h"
#include "BluetoothLeAudioCodecsProvider.h"
@@ -100,6 +101,7 @@
std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
std::unordered_map<SessionType, std::vector<CodecInfo>>
kDefaultOffloadLeAudioCodecInfoMap;
+std::vector<CodecInfo> kDefaultOffloadHfpCodecInfo;
template <class T>
bool BluetoothAudioCodecs::ContainedInVector(
@@ -439,6 +441,17 @@
return codec_info_map_iter->second;
}
+std::vector<CodecInfo> BluetoothAudioCodecs::GetHfpOffloadCodecInfo() {
+ if (kDefaultOffloadHfpCodecInfo.empty()) {
+ auto hfp_offload_setting =
+ BluetoothHfpCodecsProvider::ParseFromHfpOffloadSettingFile();
+ // Load file into list
+ kDefaultOffloadHfpCodecInfo =
+ BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(hfp_offload_setting);
+ }
+ return kDefaultOffloadHfpCodecInfo;
+}
+
std::vector<LeAudioAseConfigurationSetting>
BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings() {
return AudioSetConfigurationProviderJson::
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
index 057b9a7..0a1f708 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -57,6 +57,8 @@
static std::vector<LeAudioAseConfigurationSetting>
GetLeAudioAseConfigurationSettings();
+ static std::vector<CodecInfo> GetHfpOffloadCodecInfo();
+
private:
template <typename T>
struct identity {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp
new file mode 100644
index 0000000..d61ec5a
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2024 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 "BluetoothHfpCodecsProvider.h"
+
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using hfp::setting::CodecType;
+using hfp::setting::PathConfiguration;
+
+static const char* kHfpCodecCapabilitiesFile =
+ "/vendor/etc/aidl/hfp/hfp_codec_capabilities.xml";
+
+std::optional<HfpOffloadSetting>
+BluetoothHfpCodecsProvider::ParseFromHfpOffloadSettingFile() {
+ auto hfp_offload_setting =
+ hfp::setting::readHfpOffloadSetting(kHfpCodecCapabilitiesFile);
+ if (!hfp_offload_setting.has_value()) {
+ LOG(ERROR) << __func__ << ": Failed to read " << kHfpCodecCapabilitiesFile;
+ }
+ return hfp_offload_setting;
+}
+
+std::vector<CodecInfo> BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(
+ const std::optional<HfpOffloadSetting>& hfp_offload_setting) {
+ std::vector<CodecInfo> result;
+ if (!hfp_offload_setting.has_value()) return result;
+
+ // Convert path configuration into map
+ // Currently transport configuration is unused
+ if (!hfp_offload_setting.value().hasPathConfiguration() ||
+ hfp_offload_setting.value().getPathConfiguration().empty()) {
+ LOG(WARNING) << __func__ << ": path configurations is empty";
+ return result;
+ }
+ auto path_configurations = hfp_offload_setting.value().getPathConfiguration();
+ std::unordered_map<std::string, PathConfiguration> path_config_map;
+ for (const auto& path_cfg : path_configurations)
+ if (path_cfg.hasName() && path_cfg.hasDataPath())
+ path_config_map.insert(make_pair(path_cfg.getName(), path_cfg));
+
+ for (const auto& cfg : hfp_offload_setting.value().getConfiguration()) {
+ auto input_path_cfg = path_config_map.find(cfg.getInputPathConfiguration());
+ auto output_path_cfg =
+ path_config_map.find(cfg.getOutputPathConfiguration());
+ if (input_path_cfg == path_config_map.end()) {
+ LOG(WARNING) << __func__ << ": Input path configuration not found: "
+ << cfg.getInputPathConfiguration();
+ continue;
+ }
+
+ if (output_path_cfg == path_config_map.end()) {
+ LOG(WARNING) << __func__ << ": Output path configuration not found: "
+ << cfg.getOutputPathConfiguration();
+ continue;
+ }
+
+ CodecInfo codec_info;
+
+ switch (cfg.getCodec()) {
+ case CodecType::LC3:
+ codec_info.id = CodecId::Core::LC3;
+ break;
+ case CodecType::MSBC:
+ codec_info.id = CodecId::Core::MSBC;
+ break;
+ case CodecType::CVSD:
+ codec_info.id = CodecId::Core::CVSD;
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": Unknown codec from " << cfg.getName();
+ codec_info.id = CodecId::Vendor();
+ break;
+ }
+ codec_info.name = cfg.getName();
+
+ codec_info.transport =
+ CodecInfo::Transport::make<CodecInfo::Transport::Tag::hfp>();
+
+ auto& transport =
+ codec_info.transport.get<CodecInfo::Transport::Tag::hfp>();
+ transport.useControllerCodec = cfg.getUseControllerCodec();
+ transport.inputDataPath = input_path_cfg->second.getDataPath();
+ transport.outputDataPath = output_path_cfg->second.getDataPath();
+
+ result.push_back(codec_info);
+ }
+ LOG(INFO) << __func__ << ": Has " << result.size() << " codec info";
+ return result;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h
new file mode 100644
index 0000000..642ee02
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+
+#include <vector>
+
+#include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl_android_hardware_bluetooth_audio_hfp_setting.h"
+#include "aidl_android_hardware_bluetooth_audio_hfp_setting_enums.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using hfp::setting::HfpOffloadSetting;
+
+class BluetoothHfpCodecsProvider {
+ public:
+ static std::optional<HfpOffloadSetting> ParseFromHfpOffloadSettingFile();
+
+ static std::vector<CodecInfo> GetHfpAudioCodecInfo(
+ const std::optional<HfpOffloadSetting>& hfp_offload_setting);
+};
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp
new file mode 100644
index 0000000..b08c3eb
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2024 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 <gtest/gtest.h>
+
+#include <optional>
+#include <tuple>
+
+#include "BluetoothHfpCodecsProvider.h"
+#include "gtest/gtest.h"
+
+using aidl::android::hardware::bluetooth::audio::BluetoothHfpCodecsProvider;
+using aidl::android::hardware::bluetooth::audio::CodecInfo;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::CodecType;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::Configuration;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::
+ HfpOffloadSetting;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::
+ PathConfiguration;
+using aidl::android::hardware::bluetooth::audio::hfp::setting::
+ TransportConfiguration;
+
+typedef std::tuple<std::vector<PathConfiguration>,
+ std::vector<TransportConfiguration>,
+ std::vector<Configuration>>
+ HfpOffloadSettingTuple;
+
+// Define valid components for each list
+// PathConfiguration
+static const PathConfiguration kValidPathConfigurationCVSD("CVSD_IO", 16000,
+ CodecType::CVSD, 16,
+ 2, 0, 1, 0);
+static const PathConfiguration kInvalidPathConfigurationNULL(std::nullopt,
+ 16000,
+ CodecType::CVSD,
+ 16, 2, 0, 1, 0);
+static const PathConfiguration kInvalidPathConfigurationNoPath(
+ "CVSD_NULL", 16000, CodecType::CVSD, 16, 2, 0, std::nullopt, 0);
+
+// Configuration
+static const Configuration kValidConfigurationCVSD("CVSD", CodecType::CVSD,
+ 65535, 7, 0, true, "CVSD_IO",
+ "CVSD_IO", std::nullopt,
+ std::nullopt);
+static const Configuration kInvalidConfigurationCVSDNoPath(
+ "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_NULL", "CVSD_NULL",
+ std::nullopt, std::nullopt);
+static const Configuration kInvalidConfigurationCVSDNotFound(
+ "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_N", "CVSD_N",
+ std::nullopt, std::nullopt);
+
+class BluetoothHfpCodecsProviderTest : public ::testing::Test {
+ public:
+ static std::vector<HfpOffloadSettingTuple> CreateTestCases(
+ const std::vector<std::vector<PathConfiguration>> path_configs_list,
+ const std::vector<std::vector<TransportConfiguration>>
+ transport_configs_list,
+ const std::vector<std::vector<Configuration>> configs_list) {
+ std::vector<HfpOffloadSettingTuple> test_cases;
+ for (const auto& path_configs : path_configs_list) {
+ for (const auto& transport_configs : transport_configs_list) {
+ for (const auto& configs : configs_list)
+ test_cases.push_back(
+ CreateTestCase(path_configs, transport_configs, configs));
+ }
+ }
+ return test_cases;
+ }
+
+ protected:
+ std::vector<CodecInfo> RunTestCase(HfpOffloadSettingTuple test_case) {
+ auto& [path_configuration_list, transport_configuration_list,
+ configuration_list] = test_case;
+ HfpOffloadSetting hfp_offload_setting(path_configuration_list,
+ transport_configuration_list,
+ configuration_list);
+ auto capabilities =
+ BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(hfp_offload_setting);
+ return capabilities;
+ }
+
+ private:
+ static inline HfpOffloadSettingTuple CreateTestCase(
+ const std::vector<PathConfiguration> path_config_list,
+ const std::vector<TransportConfiguration> transport_config_list,
+ const std::vector<Configuration> config_list) {
+ return std::make_tuple(path_config_list, transport_config_list,
+ config_list);
+ }
+};
+
+class GetHfpCodecInfoTest : public BluetoothHfpCodecsProviderTest {
+ public:
+ static std::vector<std::vector<PathConfiguration>>
+ GetInvalidPathConfigurationLists() {
+ std::vector<std::vector<PathConfiguration>> result;
+ result.push_back({kInvalidPathConfigurationNULL});
+ result.push_back({kInvalidPathConfigurationNoPath});
+ result.push_back({});
+ return result;
+ }
+
+ static std::vector<std::vector<Configuration>>
+ GetInvalidConfigurationLists() {
+ std::vector<std::vector<Configuration>> result;
+ result.push_back({kInvalidConfigurationCVSDNotFound});
+ result.push_back({kInvalidConfigurationCVSDNoPath});
+ result.push_back({});
+ return result;
+ }
+};
+
+TEST_F(GetHfpCodecInfoTest, InvalidPathConfiguration) {
+ auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases(
+ GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}},
+ {{kValidConfigurationCVSD}});
+ for (auto& test_case : test_cases) {
+ auto hfp_codec_capabilities = RunTestCase(test_case);
+ ASSERT_TRUE(hfp_codec_capabilities.empty());
+ }
+}
+
+TEST_F(GetHfpCodecInfoTest, InvalidConfigurationName) {
+ auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases(
+ GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}},
+ {GetHfpCodecInfoTest::GetInvalidConfigurationLists()});
+ for (auto& test_case : test_cases) {
+ auto hfp_codec_capabilities = RunTestCase(test_case);
+ ASSERT_TRUE(hfp_codec_capabilities.empty());
+ }
+}
+
+TEST_F(GetHfpCodecInfoTest, ValidConfiguration) {
+ auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases(
+ {{kValidPathConfigurationCVSD}}, {{}}, {{kValidConfigurationCVSD}});
+ for (auto& test_case : test_cases) {
+ auto hfp_codec_capabilities = RunTestCase(test_case);
+ ASSERT_FALSE(hfp_codec_capabilities.empty());
+ }
+}
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xml b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xml
new file mode 100644
index 0000000..c94843f
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!---
+ This is an example to configure HFP hardware offload supported capability settings
+ There are 3 list in this file. Add element into each list as needed.
+
+ pathConfiguration: input / output path configuration
+ transportConfiguration: transmit / receive configuration
+
+ configuration:
+ For each configuration, there are attributes:
+ - name
+ - codec
+ - useControllerCodec
+ - maxLatencyMs
+ - packetTypes
+ - retransmissionEffort
+ - input and output path configuration (reference by name)
+ - transmit and receive configuration (reference by name)
+-->
+<hfpOffloadSetting>
+
+ <pathConfiguration name="CVSD_IO" bandwidth="16000" codec="CVSD" codedDataSize="16" pcmDataFormat="2" pcmPayloadMsbPosition="0" dataPath="1" transportUnitSize="0" />
+ <pathConfiguration name="MSBC_IO" bandwidth="32000" codec="MSBC" codedDataSize="16" pcmDataFormat="2" pcmPayloadMsbPosition="0" dataPath="1" transportUnitSize="0" />
+ <pathConfiguration name="LC3_IO" bandwidth="64000" codec="MSBC" codedDataSize="16" pcmDataFormat="2" pcmPayloadMsbPosition="0" dataPath="1" transportUnitSize="0" />
+
+ <transportConfiguration name="CVSD_TXRX" bandwidth="8000" codec="CVSD" codedFrameSize="60" />
+ <transportConfiguration name="MSBC_TXRX" bandwidth="8000" codec="MSBC" codedFrameSize="60" />
+ <transportConfiguration name="LC3_TXRX" bandwidth="8000" codec="LC3" codedFrameSize="60" />
+
+ <configuration name="CVSD_D1_controller" codec="CVSD" maxLatencyMs="65535" packetTypes="7" retransmissionEffort="0" useControllerCodec="true" inputPathConfiguration="CVSD_IO" outputPathConfiguration="CVSD_IO" inputTransportConfiguration="CVSD_TXRX" outTransportConfiguration="CVSD_TXRX" />
+ <configuration name="CVSD_S3_controller" codec="CVSD" maxLatencyMs="10" packetTypes="959" retransmissionEffort="1" useControllerCodec="true" inputPathConfiguration="CVSD_IO" outputPathConfiguration="CVSD_IO" inputTransportConfiguration="CVSD_TXRX" outTransportConfiguration="CVSD_TXRX" />
+ <configuration name="CVSD_S4_controller" codec="CVSD" maxLatencyMs="12" packetTypes="959" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="CVSD_IO" outputPathConfiguration="CVSD_IO" inputTransportConfiguration="CVSD_TXRX" outTransportConfiguration="CVSD_TXRX" />
+
+ <configuration name="MSBC_T1_controller" codec="MSBC" maxLatencyMs="8" packetTypes="968" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="MSBC_IO" outputPathConfiguration="MSBC_IO" inputTransportConfiguration="MSBC_TXRX" outTransportConfiguration="MSBC_TXRX" />
+ <configuration name="MSBC_T2_controller" codec="MSBC" maxLatencyMs="13" packetTypes="904" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="MSBC_IO" outputPathConfiguration="MSBC_IO" inputTransportConfiguration="MSBC_TXRX" outTransportConfiguration="MSBC_TXRX" />
+
+ <configuration name="LC3_T1_controller" codec="LC3" maxLatencyMs="8" packetTypes="968" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="LC3_IO" outputPathConfiguration="LC3_IO" inputTransportConfiguration="LC3_TXRX" outTransportConfiguration="LC3_TXRX" />
+ <configuration name="LC3_T2_controller" codec="LC3" maxLatencyMs="13" packetTypes="896" retransmissionEffort="2" useControllerCodec="true" inputPathConfiguration="LC3_IO" outputPathConfiguration="LC3_IO" inputTransportConfiguration="LC3_TXRX" outTransportConfiguration="LC3_TXRX" />
+
+</hfpOffloadSetting>
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xsd b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xsd
new file mode 100644
index 0000000..c4787b9
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/hfp_codec_capabilities.xsd
@@ -0,0 +1,51 @@
+<!-- HFP Offload Codec Capability Schema -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element name="hfpOffloadSetting">
+ <xs:complexType>
+ <xs:element ref="pathConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+ <xs:element ref="transportConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+ <xs:element ref="configuration" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="pathConfiguration">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="bandwidth" type="xs:unsignedInt"/>
+ <xs:attribute name="codec" type="codecType"/>
+ <xs:attribute name="codedDataSize" type="xs:unsignedShort"/>
+ <xs:attribute name="pcmDataFormat" type="xs:unsignedByte"/>
+ <xs:attribute name="pcmPayloadMsbPosition" type="xs:unsignedByte"/>
+ <xs:attribute name="dataPath" type="xs:unsignedByte"/>
+ <xs:attribute name="transportUnitSize" type="xs:unsignedByte"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="transportConfiguration">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="bandwidth" type="xs:unsignedInt"/>
+ <xs:attribute name="codec" type="codecType"/>
+ <xs:attribute name="codedFrameSize" type="xs:unsignedShort"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="configuration">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="codec" type="codecType"/>
+ <xs:attribute name="maxLatencyMs" type="xs:unsignedShort"/>
+ <xs:attribute name="packetTypes" type="xs:unsignedShort"/>
+ <xs:attribute name="retransmissionEffort" type="xs:unsignedByte"/>
+ <xs:attribute name="useControllerCodec" type="xs:boolean"/>
+ <xs:attribute name="inputPathConfiguration" type="xs:string"/>
+ <xs:attribute name="outputPathConfiguration" type="xs:string"/>
+ <xs:attribute name="inputTransportConfiguration" type="xs:string"/>
+ <xs:attribute name="outputTransportConfiguration" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:simpleType name="codecType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="LC3"/>
+ <xs:enumeration value="CVSD"/>
+ <xs:enumeration value="MSBC"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/current.txt
new file mode 100644
index 0000000..4b49929
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/current.txt
@@ -0,0 +1,82 @@
+// Signature format: 2.0
+package aidl.android.hardware.bluetooth.audio.hfp.setting {
+
+ public enum CodecType {
+ method public String getRawName();
+ enum_constant public static final aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType CVSD;
+ enum_constant public static final aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType LC3;
+ enum_constant public static final aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType MSBC;
+ }
+
+ public class Configuration {
+ ctor public Configuration();
+ method public aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType getCodec();
+ method public String getInputPathConfiguration();
+ method public String getInputTransportConfiguration();
+ method public int getMaxLatencyMs();
+ method public String getName();
+ method public String getOutputPathConfiguration();
+ method public String getOutputTransportConfiguration();
+ method public int getPacketTypes();
+ method public short getRetransmissionEffort();
+ method public boolean getUseControllerCodec();
+ method public void setCodec(aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType);
+ method public void setInputPathConfiguration(String);
+ method public void setInputTransportConfiguration(String);
+ method public void setMaxLatencyMs(int);
+ method public void setName(String);
+ method public void setOutputPathConfiguration(String);
+ method public void setOutputTransportConfiguration(String);
+ method public void setPacketTypes(int);
+ method public void setRetransmissionEffort(short);
+ method public void setUseControllerCodec(boolean);
+ }
+
+ public class HfpOffloadSetting {
+ ctor public HfpOffloadSetting();
+ method public java.util.List<aidl.android.hardware.bluetooth.audio.hfp.setting.Configuration> getConfiguration();
+ method public java.util.List<aidl.android.hardware.bluetooth.audio.hfp.setting.PathConfiguration> getPathConfiguration();
+ method public java.util.List<aidl.android.hardware.bluetooth.audio.hfp.setting.TransportConfiguration> getTransportConfiguration();
+ }
+
+ public class PathConfiguration {
+ ctor public PathConfiguration();
+ method public long getBandwidth();
+ method public aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType getCodec();
+ method public int getCodedDataSize();
+ method public short getDataPath();
+ method public String getName();
+ method public short getPcmDataFormat();
+ method public short getPcmPayloadMsbPosition();
+ method public short getTransportUnitSize();
+ method public void setBandwidth(long);
+ method public void setCodec(aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType);
+ method public void setCodedDataSize(int);
+ method public void setDataPath(short);
+ method public void setName(String);
+ method public void setPcmDataFormat(short);
+ method public void setPcmPayloadMsbPosition(short);
+ method public void setTransportUnitSize(short);
+ }
+
+ public class TransportConfiguration {
+ ctor public TransportConfiguration();
+ method public long getBandwidth();
+ method public aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType getCodec();
+ method public int getCodedFrameSize();
+ method public String getName();
+ method public void setBandwidth(long);
+ method public void setCodec(aidl.android.hardware.bluetooth.audio.hfp.setting.CodecType);
+ method public void setCodedFrameSize(int);
+ method public void setName(String);
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static aidl.android.hardware.bluetooth.audio.hfp.setting.HfpOffloadSetting readHfpOffloadSetting(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_current.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_current.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_current.txt
@@ -0,0 +1 @@
+
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_removed.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_removed.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/last_removed.txt
@@ -0,0 +1 @@
+
diff --git a/bluetooth/audio/utils/hfp_codec_capabilities/schema/removed.txt b/bluetooth/audio/utils/hfp_codec_capabilities/schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/bluetooth/audio/utils/hfp_codec_capabilities/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
index 4a95a41..4d29743 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
@@ -174,7 +174,7 @@
* - 13 bit: Fractional bits of longitude
* - 8 bit: Integer bits of longitude
* - 1 bit: 0 for east and 1 for west for longitude
- * - 1 bit: 0, representing latitude
+ * - 1 bit: 0, representing longitude
* - 5 bit: pad of zeros separating longitude and latitude
* - 4 bit: Bits 4:7 of altitude
* - 13 bit: Fractional bits of latitude
diff --git a/broadcastradio/common/utilsaidl/src/Utils.cpp b/broadcastradio/common/utilsaidl/src/Utils.cpp
index ddc5b8d..4ab04d2 100644
--- a/broadcastradio/common/utilsaidl/src/Utils.cpp
+++ b/broadcastradio/common/utilsaidl/src/Utils.cpp
@@ -296,7 +296,12 @@
sel.primaryId.type > IdentifierType::VENDOR_END)) {
return false;
}
- return isValid(sel.primaryId);
+ for (auto it = begin(sel); it != end(sel); it++) {
+ if (!isValid(*it)) {
+ return false;
+ }
+ }
+ return true;
}
ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
diff --git a/broadcastradio/common/utilsaidl/src/UtilsV2.cpp b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
index 6c75759..56365c5 100644
--- a/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
+++ b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
@@ -102,15 +102,16 @@
expect(val < 1000u, "SXM channel < 1000");
break;
case IdentifierType::HD_STATION_LOCATION: {
+ val >>= 26;
uint64_t latitudeBit = val & 0x1;
- expect(latitudeBit == 1u, "Latitude comes first");
- val >>= 27;
+ expect(latitudeBit == 0u, "Longitude comes first");
+ val >>= 1;
uint64_t latitudePad = val & 0x1Fu;
- expect(latitudePad == 0u, "Latitude padding");
- val >>= 5;
+ expect(latitudePad == 0u, "Longitude padding");
+ val >>= 31;
uint64_t longitudeBit = val & 0x1;
- expect(longitudeBit == 1u, "Longitude comes next");
- val >>= 27;
+ expect(longitudeBit == 1u, "Latitude comes next");
+ val >>= 1;
uint64_t longitudePad = val & 0x1Fu;
expect(longitudePad == 0u, "Latitude padding");
break;
@@ -135,7 +136,12 @@
sel.primaryId.type > IdentifierType::VENDOR_END)) {
return false;
}
- return isValidV2(sel.primaryId);
+ for (auto it = begin(sel); it != end(sel); it++) {
+ if (!isValidV2(*it)) {
+ return false;
+ }
+ }
+ return true;
}
bool isValidMetadataV2(const Metadata& metadata) {
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsCommonTest.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsCommonTest.cpp
new file mode 100644
index 0000000..b71bf03
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsCommonTest.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2024 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 <broadcastradio-utils-aidl/Utils.h>
+#include <broadcastradio-utils-aidl/UtilsV2.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+constexpr int64_t kFmFrequencyKHz = 97900;
+constexpr uint32_t kDabSid = 0x0000C221u;
+constexpr int kDabEccCode = 0xE1u;
+constexpr int kDabSCIdS = 0x1u;
+constexpr uint64_t kDabSidExt = static_cast<uint64_t>(kDabSid) |
+ (static_cast<uint64_t>(kDabEccCode) << 32) |
+ (static_cast<uint64_t>(kDabSCIdS) << 40);
+constexpr uint32_t kDabEnsemble = 0xCE15u;
+constexpr uint64_t kDabFrequencyKhz = 225648u;
+constexpr uint64_t kHdStationId = 0xA0000001u;
+constexpr uint64_t kHdSubChannel = 1u;
+constexpr uint64_t kHdStationLocation = 0x44E647003665CF6u;
+constexpr uint64_t kHdStationLocationInvalid = 0x4E647007665CF6u;
+constexpr uint64_t kHdFrequency = 97700u;
+constexpr int64_t kRdsValue = 0xBEEF;
+
+struct IsValidIdentifierTestCase {
+ std::string name;
+ ProgramIdentifier id;
+ bool valid;
+};
+
+std::vector<IsValidIdentifierTestCase> getIsValidIdentifierTestCases() {
+ return std::vector<IsValidIdentifierTestCase>({
+ IsValidIdentifierTestCase{.name = "invalid_id_type",
+ .id = utils::makeIdentifier(IdentifierType::INVALID, 0),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_dab_frequency_high",
+ .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 10000000u),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_dab_frequency_low",
+ .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 100000u),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "valid_dab_frequency",
+ .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 1000000u),
+ .valid = true},
+ IsValidIdentifierTestCase{
+ .name = "invalid_am_fm_frequency_high",
+ .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 10000000u),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_am_fm_frequency_low",
+ .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 100u),
+ .valid = false},
+ IsValidIdentifierTestCase{.name = "valid_am_fm_frequency",
+ .id = utils::makeIdentifier(
+ IdentifierType::AMFM_FREQUENCY_KHZ, kFmFrequencyKHz),
+ .valid = true},
+ IsValidIdentifierTestCase{
+ .name = "drmo_frequency_high",
+ .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 10000000u),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "drmo_frequency_low",
+ .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 100u),
+ .valid = false},
+ IsValidIdentifierTestCase{.name = "valid_drmo_frequency",
+ .id = utils::makeIdentifier(
+ IdentifierType::DRMO_FREQUENCY_KHZ, kFmFrequencyKHz),
+ .valid = true},
+ IsValidIdentifierTestCase{.name = "invalid_rds_low",
+ .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x0),
+ .valid = false},
+ IsValidIdentifierTestCase{.name = "invalid_rds_high",
+ .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x10000),
+ .valid = false},
+ IsValidIdentifierTestCase{.name = "valid_rds",
+ .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x1000),
+ .valid = true},
+ IsValidIdentifierTestCase{
+ .name = "invalid_hd_id_zero",
+ .id = utils::makeSelectorHd(/* stationId= */ 0u, kHdSubChannel, kHdFrequency)
+ .primaryId,
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_hd_suchannel",
+ .id = utils::makeSelectorHd(kHdStationId, /* subChannel= */ 8u, kHdFrequency)
+ .primaryId,
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_hd_frequency_low",
+ .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, /* frequency= */ 100u)
+ .primaryId,
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "valid_hd_id",
+ .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency)
+ .primaryId,
+ .valid = true},
+ IsValidIdentifierTestCase{
+ .name = "invalid_hd_station_name",
+ .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x41422D464D),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "valid_hd_station_name",
+ .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x414231464D),
+ .valid = true},
+ IsValidIdentifierTestCase{
+ .name = "invalid_dab_sid",
+ .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0E100000000u),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_dab_ecc_low",
+ .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0F700000221u),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_dab_ecc_high",
+ .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x09900000221u),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "valid_dab_sid_ext",
+ .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, kDabSidExt),
+ .valid = true},
+ IsValidIdentifierTestCase{
+ .name = "invalid_dab_ensemble_zero",
+ .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x0),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_dab_ensemble_high",
+ .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x10000),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "valid_dab_ensemble",
+ .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, kDabEnsemble),
+ .valid = true},
+ IsValidIdentifierTestCase{.name = "invalid_dab_scid_low",
+ .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0xF),
+ .valid = false},
+ IsValidIdentifierTestCase{.name = "invalid_dab_scid_high",
+ .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x1000),
+ .valid = false},
+ IsValidIdentifierTestCase{.name = "valid_dab_scid",
+ .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x100),
+ .valid = true},
+ IsValidIdentifierTestCase{
+ .name = "invalid_drmo_id_zero",
+ .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x0),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "invalid_drmo_id_high",
+ .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x1000000),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "valid_drmo_id",
+ .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000),
+ .valid = true},
+ });
+}
+
+std::vector<IsValidIdentifierTestCase> getIsValidIdentifierV2TestCases() {
+ std::vector<IsValidIdentifierTestCase> testcases = getIsValidIdentifierTestCases();
+ std::vector<IsValidIdentifierTestCase> testcasesNew = std::vector<IsValidIdentifierTestCase>({
+ IsValidIdentifierTestCase{
+ .name = "invalid_hd_station_location_id",
+ .id = utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION,
+ kHdStationLocationInvalid),
+ .valid = false},
+ IsValidIdentifierTestCase{
+ .name = "valid_hd_station_location_id",
+ .id = utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION,
+ kHdStationLocation),
+ .valid = true},
+ });
+ testcases.insert(testcases.end(), testcasesNew.begin(), testcasesNew.end());
+ return testcases;
+}
+
+struct IsValidSelectorTestCase {
+ std::string name;
+ ProgramSelector sel;
+ bool valid;
+};
+
+std::vector<IsValidSelectorTestCase> getIsValidSelectorTestCases() {
+ return std::vector<IsValidSelectorTestCase>({
+ IsValidSelectorTestCase{.name = "valid_am_fm_selector",
+ .sel = utils::makeSelectorAmfm(kFmFrequencyKHz),
+ .valid = true},
+ IsValidSelectorTestCase{
+ .name = "valid_hd_selector",
+ .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency),
+ .valid = true},
+ IsValidSelectorTestCase{
+ .name = "valid_dab_selector",
+ .sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz),
+ .valid = true},
+ IsValidSelectorTestCase{.name = "valid_rds_selector",
+ .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
+ IdentifierType::RDS_PI, 0x1000)},
+ .valid = true},
+ IsValidSelectorTestCase{.name = "selector_with_invalid_id",
+ .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel,
+ /* frequency= */ 100u),
+ .valid = false},
+ IsValidSelectorTestCase{
+ .name = "selector_with_invalid_primary_id_type",
+ .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
+ IdentifierType::DAB_ENSEMBLE, kDabEnsemble)},
+ .valid = false},
+ IsValidSelectorTestCase{
+ .name = "selector_with_invalid_secondary_id",
+ .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
+ IdentifierType::DAB_SID_EXT, kDabSidExt),
+ .secondaryIds = {utils::makeIdentifier(
+ IdentifierType::DAB_ENSEMBLE, 0x0)}},
+ .valid = false},
+ });
+}
+
+std::vector<IsValidSelectorTestCase> getIsValidSelectorV2TestCases() {
+ ProgramSelector validHdSel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+ validHdSel.secondaryIds = {
+ utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION, kHdStationLocation)};
+ ProgramSelector invalidHdSel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+ invalidHdSel.secondaryIds = {
+ utils::makeIdentifier(IdentifierType::HD_STATION_LOCATION, kHdStationLocationInvalid)};
+ std::vector<IsValidSelectorTestCase> testcasesNew = std::vector<IsValidSelectorTestCase>(
+ {IsValidSelectorTestCase{.name = "hd_selector_with_valid_station_location",
+ .sel = validHdSel,
+ .valid = true},
+ IsValidSelectorTestCase{.name = "hd_selector_with_invalid_station_location",
+ .sel = invalidHdSel,
+ .valid = false}});
+ std::vector<IsValidSelectorTestCase> testcases = getIsValidSelectorTestCases();
+ testcases.insert(testcases.end(), testcasesNew.begin(), testcasesNew.end());
+ return testcases;
+}
+
+struct IsValidMetadataTestCase {
+ std::string name;
+ Metadata metadata;
+ bool valid;
+};
+
+std::vector<IsValidMetadataTestCase> getIsValidMetadataTestCases() {
+ return std::vector<IsValidMetadataTestCase>({
+ IsValidMetadataTestCase{.name = "valid_rds_pty",
+ .metadata = Metadata::make<Metadata::rdsPty>(1),
+ .valid = true},
+ IsValidMetadataTestCase{.name = "negative_rds_pty",
+ .metadata = Metadata::make<Metadata::rdsPty>(-1),
+ .valid = false},
+ IsValidMetadataTestCase{.name = "large_rds_pty",
+ .metadata = Metadata::make<Metadata::rdsPty>(256),
+ .valid = false},
+ IsValidMetadataTestCase{.name = "valid_rbds_pty",
+ .metadata = Metadata::make<Metadata::rbdsPty>(1),
+ .valid = true},
+ IsValidMetadataTestCase{.name = "negative_rbds_pty",
+ .metadata = Metadata::make<Metadata::rbdsPty>(-1),
+ .valid = false},
+ IsValidMetadataTestCase{.name = "large_rbds_pty",
+ .metadata = Metadata::make<Metadata::rbdsPty>(256),
+ .valid = false},
+ IsValidMetadataTestCase{
+ .name = "valid_dab_ensemble_name_short",
+ .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name"),
+ .valid = true},
+ IsValidMetadataTestCase{
+ .name = "too_long_dab_ensemble_name_short",
+ .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name_long"),
+ .valid = false},
+ IsValidMetadataTestCase{
+ .name = "valid_dab_service_name_short",
+ .metadata = Metadata::make<Metadata::dabServiceNameShort>("name"),
+ .valid = true},
+ IsValidMetadataTestCase{
+ .name = "too_long_dab_service_name_short",
+ .metadata = Metadata::make<Metadata::dabServiceNameShort>("name_long"),
+ .valid = false},
+ IsValidMetadataTestCase{
+ .name = "valid_dab_component_name_short",
+ .metadata = Metadata::make<Metadata::dabComponentNameShort>("name"),
+ .valid = true},
+ IsValidMetadataTestCase{
+ .name = "too_long_dab_component_name_short",
+ .metadata = Metadata::make<Metadata::dabComponentNameShort>("name_long"),
+ .valid = false},
+ });
+}
+
+std::vector<IsValidMetadataTestCase> getIsValidMetadataV2TestCases() {
+ std::vector<IsValidMetadataTestCase> testcases = getIsValidMetadataTestCases();
+ std::vector<IsValidMetadataTestCase> testcasesNew = std::vector<IsValidMetadataTestCase>({
+ IsValidMetadataTestCase{
+ .name = "valid_hd_station_name_short",
+ .metadata = Metadata::make<Metadata::hdStationNameShort>("name_short"),
+ .valid = true},
+ IsValidMetadataTestCase{
+ .name = "too_long_hd_station_name_short",
+ .metadata = Metadata::make<Metadata::hdStationNameShort>("name_too_long"),
+ .valid = false},
+ IsValidMetadataTestCase{.name = "valid_hd_subchannel_available",
+ .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(1),
+ .valid = true},
+ IsValidMetadataTestCase{
+ .name = "negative_subchannel_available",
+ .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(-1),
+ .valid = false},
+ IsValidMetadataTestCase{
+ .name = "large_subchannel_available",
+ .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(256),
+ .valid = false},
+ });
+ testcases.insert(testcases.end(), testcasesNew.begin(), testcasesNew.end());
+ return testcases;
+}
+} // namespace
+
+class IsValidIdentifierTest : public testing::TestWithParam<IsValidIdentifierTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidIdentifierTests, IsValidIdentifierTest,
+ testing::ValuesIn(getIsValidIdentifierTestCases()),
+ [](const testing::TestParamInfo<IsValidIdentifierTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(IsValidIdentifierTest, IsValid) {
+ IsValidIdentifierTestCase testcase = GetParam();
+
+ ASSERT_EQ(utils::isValid(testcase.id), testcase.valid);
+}
+
+class IsValidIdentifierV2Test : public testing::TestWithParam<IsValidIdentifierTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+ IsValidIdentifierV2Tests, IsValidIdentifierV2Test,
+ testing::ValuesIn(getIsValidIdentifierV2TestCases()),
+ [](const testing::TestParamInfo<IsValidIdentifierV2Test::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(IsValidIdentifierV2Test, IsValidV2) {
+ IsValidIdentifierTestCase testcase = GetParam();
+
+ ASSERT_EQ(utils::isValidV2(testcase.id), testcase.valid);
+}
+
+class IsValidSelectorTest : public testing::TestWithParam<IsValidSelectorTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidSelectorTests, IsValidSelectorTest,
+ testing::ValuesIn(getIsValidSelectorTestCases()),
+ [](const testing::TestParamInfo<IsValidSelectorTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(IsValidSelectorTest, IsValid) {
+ IsValidSelectorTestCase testcase = GetParam();
+
+ ASSERT_EQ(utils::isValid(testcase.sel), testcase.valid);
+}
+
+class IsValidSelectorV2Test : public testing::TestWithParam<IsValidSelectorTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidSelectorV2Tests, IsValidSelectorV2Test,
+ testing::ValuesIn(getIsValidSelectorV2TestCases()),
+ [](const testing::TestParamInfo<IsValidSelectorV2Test::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(IsValidSelectorV2Test, IsValidV2) {
+ IsValidSelectorTestCase testcase = GetParam();
+
+ ASSERT_EQ(utils::isValidV2(testcase.sel), testcase.valid);
+}
+
+class IsValidMetadataTest : public testing::TestWithParam<IsValidMetadataTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataTests, IsValidMetadataTest,
+ testing::ValuesIn(getIsValidMetadataTestCases()),
+ [](const testing::TestParamInfo<IsValidMetadataTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(IsValidMetadataTest, IsValidMetadata) {
+ IsValidMetadataTestCase testParam = GetParam();
+
+ ASSERT_EQ(utils::isValidMetadata(testParam.metadata), testParam.valid);
+}
+
+class IsValidMetadataV2Test : public testing::TestWithParam<IsValidMetadataTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataV2Tests, IsValidMetadataV2Test,
+ testing::ValuesIn(getIsValidMetadataV2TestCases()),
+ [](const testing::TestParamInfo<IsValidMetadataV2Test::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(IsValidMetadataV2Test, IsValidMetadataV2) {
+ IsValidMetadataTestCase testParam = GetParam();
+
+ ASSERT_EQ(utils::isValidMetadataV2(testParam.metadata), testParam.valid);
+}
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
index a5c9073..b633ff0 100644
--- a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
@@ -66,230 +66,6 @@
.frequency = 110000,
.bandResult = utils::FrequencyBand::UNKNOWN}});
}
-
-struct IsValidIdentifierTestCase {
- std::string name;
- ProgramIdentifier id;
- bool valid;
-};
-
-std::vector<IsValidIdentifierTestCase> getIsValidIdentifierTestCases() {
- return std::vector<IsValidIdentifierTestCase>({
- IsValidIdentifierTestCase{.name = "invalid_id_type",
- .id = utils::makeIdentifier(IdentifierType::INVALID, 0),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_dab_frequency_high",
- .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 10000000u),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_dab_frequency_low",
- .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 100000u),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "valid_dab_frequency",
- .id = utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, 1000000u),
- .valid = true},
- IsValidIdentifierTestCase{
- .name = "invalid_am_fm_frequency_high",
- .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 10000000u),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_am_fm_frequency_low",
- .id = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 100u),
- .valid = false},
- IsValidIdentifierTestCase{.name = "valid_am_fm_frequency",
- .id = utils::makeIdentifier(
- IdentifierType::AMFM_FREQUENCY_KHZ, kFmFrequencyKHz),
- .valid = true},
- IsValidIdentifierTestCase{
- .name = "drmo_frequency_high",
- .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 10000000u),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "drmo_frequency_low",
- .id = utils::makeIdentifier(IdentifierType::DRMO_FREQUENCY_KHZ, 100u),
- .valid = false},
- IsValidIdentifierTestCase{.name = "valid_drmo_frequency",
- .id = utils::makeIdentifier(
- IdentifierType::DRMO_FREQUENCY_KHZ, kFmFrequencyKHz),
- .valid = true},
- IsValidIdentifierTestCase{.name = "invalid_rds_low",
- .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x0),
- .valid = false},
- IsValidIdentifierTestCase{.name = "invalid_rds_high",
- .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x10000),
- .valid = false},
- IsValidIdentifierTestCase{.name = "valid_rds",
- .id = utils::makeIdentifier(IdentifierType::RDS_PI, 0x1000),
- .valid = true},
- IsValidIdentifierTestCase{
- .name = "invalid_hd_id_zero",
- .id = utils::makeSelectorHd(/* stationId= */ 0u, kHdSubChannel, kHdFrequency)
- .primaryId,
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_hd_suchannel",
- .id = utils::makeSelectorHd(kHdStationId, /* subChannel= */ 8u, kHdFrequency)
- .primaryId,
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_hd_frequency_low",
- .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, /* frequency= */ 100u)
- .primaryId,
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "valid_hd_id",
- .id = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency)
- .primaryId,
- .valid = true},
- IsValidIdentifierTestCase{
- .name = "invalid_hd_station_name",
- .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x41422D464D),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "valid_hd_station_name",
- .id = utils::makeIdentifier(IdentifierType::HD_STATION_NAME, 0x414231464D),
- .valid = true},
- IsValidIdentifierTestCase{
- .name = "invalid_dab_sid",
- .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0E100000000u),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_dab_ecc_low",
- .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x0F700000221u),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_dab_ecc_high",
- .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, 0x09900000221u),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "valid_dab_sid_ext",
- .id = utils::makeIdentifier(IdentifierType::DAB_SID_EXT, kDabSidExt),
- .valid = true},
- IsValidIdentifierTestCase{
- .name = "invalid_dab_ensemble_zero",
- .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x0),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_dab_ensemble_high",
- .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, 0x10000),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "valid_dab_ensemble",
- .id = utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, kDabEnsemble),
- .valid = true},
- IsValidIdentifierTestCase{.name = "invalid_dab_scid_low",
- .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0xF),
- .valid = false},
- IsValidIdentifierTestCase{.name = "invalid_dab_scid_high",
- .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x1000),
- .valid = false},
- IsValidIdentifierTestCase{.name = "valid_dab_scid",
- .id = utils::makeIdentifier(IdentifierType::DAB_SCID, 0x100),
- .valid = true},
- IsValidIdentifierTestCase{
- .name = "invalid_drmo_id_zero",
- .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x0),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "invalid_drmo_id_high",
- .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x1000000),
- .valid = false},
- IsValidIdentifierTestCase{
- .name = "valid_drmo_id",
- .id = utils::makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000),
- .valid = true},
- });
-}
-
-struct IsValidSelectorTestCase {
- std::string name;
- ProgramSelector sel;
- bool valid;
-};
-
-std::vector<IsValidSelectorTestCase> getIsValidSelectorTestCases() {
- return std::vector<IsValidSelectorTestCase>({
- IsValidSelectorTestCase{.name = "valid_am_fm_selector",
- .sel = utils::makeSelectorAmfm(kFmFrequencyKHz),
- .valid = true},
- IsValidSelectorTestCase{
- .name = "valid_hd_selector",
- .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency),
- .valid = true},
- IsValidSelectorTestCase{
- .name = "valid_dab_selector",
- .sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz),
- .valid = true},
- IsValidSelectorTestCase{.name = "valid_rds_selector",
- .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
- IdentifierType::RDS_PI, 0x1000)},
- .valid = true},
- IsValidSelectorTestCase{.name = "selector_with_invalid_id",
- .sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel,
- /* frequency= */ 100u),
- .valid = false},
- IsValidSelectorTestCase{
- .name = "selector_with_invalid_primary_id_type",
- .sel = ProgramSelector{.primaryId = utils::makeIdentifier(
- IdentifierType::DAB_ENSEMBLE, kDabEnsemble)},
- .valid = false},
- });
-}
-
-struct IsValidMetadataTestCase {
- std::string name;
- Metadata metadata;
- bool valid;
-};
-
-std::vector<IsValidMetadataTestCase> getIsValidMetadataTestCases() {
- return std::vector<IsValidMetadataTestCase>({
- IsValidMetadataTestCase{.name = "valid_rds_pty",
- .metadata = Metadata::make<Metadata::rdsPty>(1),
- .valid = true},
- IsValidMetadataTestCase{.name = "negative_rds_pty",
- .metadata = Metadata::make<Metadata::rdsPty>(-1),
- .valid = false},
- IsValidMetadataTestCase{.name = "large_rds_pty",
- .metadata = Metadata::make<Metadata::rdsPty>(256),
- .valid = false},
- IsValidMetadataTestCase{.name = "valid_rbds_pty",
- .metadata = Metadata::make<Metadata::rbdsPty>(1),
- .valid = true},
- IsValidMetadataTestCase{.name = "negative_rbds_pty",
- .metadata = Metadata::make<Metadata::rbdsPty>(-1),
- .valid = false},
- IsValidMetadataTestCase{.name = "large_rbds_pty",
- .metadata = Metadata::make<Metadata::rbdsPty>(256),
- .valid = false},
- IsValidMetadataTestCase{
- .name = "valid_dab_ensemble_name_short",
- .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name"),
- .valid = true},
- IsValidMetadataTestCase{
- .name = "too_long_dab_ensemble_name_short",
- .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name_long"),
- .valid = false},
- IsValidMetadataTestCase{
- .name = "valid_dab_service_name_short",
- .metadata = Metadata::make<Metadata::dabServiceNameShort>("name"),
- .valid = true},
- IsValidMetadataTestCase{
- .name = "too_long_dab_service_name_short",
- .metadata = Metadata::make<Metadata::dabServiceNameShort>("name_long"),
- .valid = false},
- IsValidMetadataTestCase{
- .name = "valid_dab_component_name_short",
- .metadata = Metadata::make<Metadata::dabComponentNameShort>("name"),
- .valid = true},
- IsValidMetadataTestCase{
- .name = "too_long_dab_component_name_short",
- .metadata = Metadata::make<Metadata::dabComponentNameShort>("name_long"),
- .valid = false},
- });
-}
} // namespace
class GetBandTest : public testing::TestWithParam<GetBandTestCase> {};
@@ -305,48 +81,6 @@
ASSERT_EQ(utils::getBand(testcase.frequency), testcase.bandResult);
}
-class IsValidMetadataTest : public testing::TestWithParam<IsValidMetadataTestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidMetadataTests, IsValidMetadataTest,
- testing::ValuesIn(getIsValidMetadataTestCases()),
- [](const testing::TestParamInfo<IsValidMetadataTest::ParamType>& info) {
- return info.param.name;
- });
-
-TEST_P(IsValidMetadataTest, IsValidMetadata) {
- IsValidMetadataTestCase testParam = GetParam();
-
- ASSERT_EQ(utils::isValidMetadata(testParam.metadata), testParam.valid);
-}
-
-class IsValidIdentifierTest : public testing::TestWithParam<IsValidIdentifierTestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidIdentifierTests, IsValidIdentifierTest,
- testing::ValuesIn(getIsValidIdentifierTestCases()),
- [](const testing::TestParamInfo<IsValidIdentifierTest::ParamType>& info) {
- return info.param.name;
- });
-
-TEST_P(IsValidIdentifierTest, IsValid) {
- IsValidIdentifierTestCase testcase = GetParam();
-
- ASSERT_EQ(utils::isValid(testcase.id), testcase.valid);
-}
-
-class IsValidSelectorTest : public testing::TestWithParam<IsValidSelectorTestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidSelectorTests, IsValidSelectorTest,
- testing::ValuesIn(getIsValidSelectorTestCases()),
- [](const testing::TestParamInfo<IsValidSelectorTest::ParamType>& info) {
- return info.param.name;
- });
-
-TEST_P(IsValidSelectorTest, IsValid) {
- IsValidSelectorTestCase testcase = GetParam();
-
- ASSERT_EQ(utils::isValid(testcase.sel), testcase.valid);
-}
-
TEST(BroadcastRadioUtilsTest, IdentifierIteratorBegin) {
ProgramSelector sel = {
.primaryId = utils::makeIdentifier(IdentifierType::RDS_PI, kRdsValue),
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
deleted file mode 100644
index cf9f9e9..0000000
--- a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2024 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 <broadcastradio-utils-aidl/UtilsV2.h>
-#include <gtest/gtest.h>
-
-namespace aidl::android::hardware::broadcastradio {
-
-namespace {
-struct IsValidMetadataV2TestCase {
- std::string name;
- Metadata metadata;
- bool valid;
-};
-
-std::vector<IsValidMetadataV2TestCase> getIsValidMetadataV2TestCases() {
- return std::vector<IsValidMetadataV2TestCase>({
- IsValidMetadataV2TestCase{.name = "valid_rds_pty",
- .metadata = Metadata::make<Metadata::rdsPty>(1),
- .valid = true},
- IsValidMetadataV2TestCase{.name = "negative_rds_pty",
- .metadata = Metadata::make<Metadata::rdsPty>(-1),
- .valid = false},
- IsValidMetadataV2TestCase{
- .name = "valid_hd_station_name_short",
- .metadata = Metadata::make<Metadata::hdStationNameShort>("name_short"),
- .valid = true},
- IsValidMetadataV2TestCase{
- .name = "too_long_hd_station_name_short",
- .metadata = Metadata::make<Metadata::hdStationNameShort>("name_too_long"),
- .valid = false},
- IsValidMetadataV2TestCase{
- .name = "valid_hd_subchannel_available",
- .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(1),
- .valid = true},
- IsValidMetadataV2TestCase{
- .name = "negative_subchannel_available",
- .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(-1),
- .valid = false},
- IsValidMetadataV2TestCase{
- .name = "large_subchannel_available",
- .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(256),
- .valid = false},
- });
-}
-} // namespace
-
-class IsValidMetadataV2Test : public testing::TestWithParam<IsValidMetadataV2TestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(IsValidMetadataV2Tests, IsValidMetadataV2Test,
- testing::ValuesIn(getIsValidMetadataV2TestCases()),
- [](const testing::TestParamInfo<IsValidMetadataV2Test::ParamType>& info) {
- return info.param.name;
- });
-
-TEST_P(IsValidMetadataV2Test, IsValidMetadataV2) {
- IsValidMetadataV2TestCase testParam = GetParam();
-
- ASSERT_EQ(utils::isValidMetadataV2(testParam.metadata), testParam.valid);
-}
-
-} // namespace aidl::android::hardware::broadcastradio
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 2b69442..951ca85 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -88,8 +88,7 @@
stem: "compatibility_matrix.202504.xml",
srcs: ["compatibility_matrix.202504.xml"],
kernel_configs: [
- "kernel_config_w_6.1",
- "kernel_config_w_6.6",
+ "kernel_config_w_6.next",
],
}
diff --git a/media/bufferpool/aidl/default/BufferPool.cpp b/media/bufferpool/aidl/default/BufferPool.cpp
index ed4574f..57716db 100644
--- a/media/bufferpool/aidl/default/BufferPool.cpp
+++ b/media/bufferpool/aidl/default/BufferPool.cpp
@@ -102,11 +102,11 @@
if (it->isInvalidated(bufferId)) {
uint32_t msgId = 0;
if (it->mNeedsAck) {
- msgId = ++mInvalidationId;
- if (msgId == 0) {
- // wrap happens
- msgId = ++mInvalidationId;
+ if (mInvalidationId == UINT_MAX) {
+ // wrap happens;
+ mInvalidationId = 0;
}
+ msgId = ++mInvalidationId;
}
channel.postInvalidation(msgId, it->mFrom, it->mTo);
it = mPendings.erase(it);
@@ -125,11 +125,11 @@
const std::shared_ptr<Accessor> &impl) {
uint32_t msgId = 0;
if (needsAck) {
- msgId = ++mInvalidationId;
- if (msgId == 0) {
- // wrap happens
- msgId = ++mInvalidationId;
+ if (mInvalidationId == UINT_MAX) {
+ //wrap happens
+ mInvalidationId = 0;
}
+ msgId = ++mInvalidationId;
}
ALOGV("bufferpool2 invalidation requested and queued");
if (left == 0) {
diff --git a/media/bufferpool/aidl/default/BufferStatus.cpp b/media/bufferpool/aidl/default/BufferStatus.cpp
index 19caa1e..fecbe3f 100644
--- a/media/bufferpool/aidl/default/BufferStatus.cpp
+++ b/media/bufferpool/aidl/default/BufferStatus.cpp
@@ -26,8 +26,17 @@
using aidl::android::hardware::media::bufferpool2::BufferStatus;
+uint32_t wrappedMinus(uint32_t a, uint32_t b) {
+ if (a >= b) {
+ return a - b;
+ } else {
+ return ~(b - a) + 1;
+ }
+}
+
bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
- return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+ return curMsgId != prevMsgId &&
+ wrappedMinus(curMsgId, prevMsgId) < wrappedMinus(prevMsgId, curMsgId);
}
bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
diff --git a/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
index 01f7327..451eaa9 100644
--- a/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
+++ b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
@@ -62,7 +62,7 @@
// IMS and SIP layer security (See 3GPP TS 33.203)
// No IPsec config
SIP_NO_IPSEC_CONFIG = 66,
- IMS_NULL = 67,
+ IMS_NULL = 67, // Deprecated. Use SIP_NO_IPSEC_CONFIG and SIP_NULL instead.
// Has IPsec config
SIP_NULL = 68,
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 953630b..122a421 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -46,9 +46,74 @@
],
}
+rust_binary {
+ name: "android.hardware.security.keymint-service.nonsecure",
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.security.keymint-service.rc"],
+ vintf_fragments: [
+ "android.hardware.security.keymint-service.xml",
+ "android.hardware.security.sharedsecret-service.xml",
+ "android.hardware.security.secureclock-service.xml",
+ ],
+ defaults: [
+ "keymint_use_latest_hal_aidl_rust",
+ ],
+ srcs: [
+ "main.rs",
+ ],
+ rustlibs: [
+ "libandroid_logger",
+ "libbinder_rs",
+ "liblog_rust",
+ "libkmr_hal",
+ "libkmr_hal_nonsecure",
+ "libkmr_ta_nonsecure",
+ ],
+ required: [
+ "android.hardware.hardware_keystore.xml",
+ ],
+}
+
prebuilt_etc {
name: "android.hardware.hardware_keystore.xml",
sub_dir: "permissions",
vendor: true,
src: "android.hardware.hardware_keystore.xml",
}
+
+rust_library {
+ name: "libkmr_hal_nonsecure",
+ crate_name: "kmr_hal_nonsecure",
+ vendor_available: true,
+ lints: "android",
+ rustlibs: [
+ "libbinder_rs",
+ "libhex",
+ "liblibc",
+ "liblog_rust",
+ "libkmr_hal",
+ "libkmr_wire",
+ ],
+ srcs: ["hal/lib.rs"],
+
+}
+
+rust_library {
+ name: "libkmr_ta_nonsecure",
+ crate_name: "kmr_ta_nonsecure",
+ vendor_available: true,
+ host_supported: true,
+ lints: "android",
+ rustlibs: [
+ "libhex",
+ "liblibc",
+ "liblog_rust",
+ "libkmr_common",
+ "libkmr_crypto_boring",
+ "libkmr_ta",
+ "libkmr_wire",
+ ],
+ srcs: ["ta/lib.rs"],
+
+}
diff --git a/security/keymint/aidl/default/hal/lib.rs b/security/keymint/aidl/default/hal/lib.rs
new file mode 100644
index 0000000..621f077
--- /dev/null
+++ b/security/keymint/aidl/default/hal/lib.rs
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+//! KeyMint helper functions that are only suitable for non-secure environments
+//! such as Cuttlefish.
+
+use kmr_hal::env::get_property;
+use log::error;
+
+/// Populate attestation ID information based on properties (where available).
+/// Retrieving the serial number requires SELinux permission.
+pub fn attestation_id_info() -> kmr_wire::AttestationIdInfo {
+ let prop = |name| {
+ get_property(name)
+ .unwrap_or_else(|_| format!("{} unavailable", name))
+ .as_bytes()
+ .to_vec()
+ };
+ kmr_wire::AttestationIdInfo {
+ brand: prop("ro.product.brand"),
+ device: prop("ro.product.device"),
+ product: prop("ro.product.name"),
+ serial: prop("ro.serialno"),
+ manufacturer: prop("ro.product.manufacturer"),
+ model: prop("ro.product.model"),
+ // Currently modem_simulator always returns one fixed value. See `handleGetIMEI` in
+ // device/google/cuttlefish/host/commands/modem_simulator/misc_service.cpp for more details.
+ // TODO(b/263188546): Use device-specific IMEI values when available.
+ imei: b"867400022047199".to_vec(),
+ imei2: b"867400022047199".to_vec(),
+ meid: vec![],
+ }
+}
+
+/// Get boot information based on system properties.
+pub fn get_boot_info() -> kmr_wire::SetBootInfoRequest {
+ // No access to a verified boot key.
+ let verified_boot_key = vec![0; 32];
+ let vbmeta_digest = get_property("ro.boot.vbmeta.digest").unwrap_or_else(|_| "00".repeat(32));
+ let verified_boot_hash = hex::decode(&vbmeta_digest).unwrap_or_else(|_e| {
+ error!("failed to parse hex data in '{}'", vbmeta_digest);
+ vec![0; 32]
+ });
+ let device_boot_locked = match get_property("ro.boot.vbmeta.device_state")
+ .unwrap_or_else(|_| "no-prop".to_string())
+ .as_str()
+ {
+ "locked" => true,
+ "unlocked" => false,
+ v => {
+ error!("Unknown device_state '{}', treating as unlocked", v);
+ false
+ }
+ };
+ let verified_boot_state = match get_property("ro.boot.verifiedbootstate")
+ .unwrap_or_else(|_| "no-prop".to_string())
+ .as_str()
+ {
+ "green" => 0, // Verified
+ "yellow" => 1, // SelfSigned
+ "orange" => 2, // Unverified,
+ "red" => 3, // Failed,
+ v => {
+ error!("Unknown boot state '{}', treating as Unverified", v);
+ 2
+ }
+ };
+
+ // Attempt to get the boot patchlevel from a system property. This requires an SELinux
+ // permission, so fall back to re-using the OS patchlevel if this can't be done.
+ let boot_patchlevel_prop = get_property("ro.vendor.boot_security_patch").unwrap_or_else(|e| {
+ error!("Failed to retrieve boot patchlevel: {:?}", e);
+ get_property(kmr_hal::env::OS_PATCHLEVEL_PROPERTY)
+ .unwrap_or_else(|_| "1970-09-19".to_string())
+ });
+ let boot_patchlevel =
+ kmr_hal::env::extract_patchlevel(&boot_patchlevel_prop).unwrap_or(19700919);
+
+ kmr_wire::SetBootInfoRequest {
+ verified_boot_key,
+ device_boot_locked,
+ verified_boot_state,
+ verified_boot_hash,
+ boot_patchlevel,
+ }
+}
diff --git a/security/keymint/aidl/default/main.rs b/security/keymint/aidl/default/main.rs
new file mode 100644
index 0000000..ea432d1
--- /dev/null
+++ b/security/keymint/aidl/default/main.rs
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Default implementation of the KeyMint HAL and related HALs.
+//!
+//! This implementation of the HAL is only intended to allow testing and policy compliance. A real
+//! implementation **must be implemented in a secure environment**.
+
+use kmr_hal::SerializedChannel;
+use kmr_hal_nonsecure::{attestation_id_info, get_boot_info};
+use log::{debug, error, info};
+use std::ops::DerefMut;
+use std::sync::{mpsc, Arc, Mutex};
+
+/// Name of KeyMint binder device instance.
+static SERVICE_INSTANCE: &str = "default";
+
+static KM_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
+static RPC_SERVICE_NAME: &str = "android.hardware.security.keymint.IRemotelyProvisionedComponent";
+static CLOCK_SERVICE_NAME: &str = "android.hardware.security.secureclock.ISecureClock";
+static SECRET_SERVICE_NAME: &str = "android.hardware.security.sharedsecret.ISharedSecret";
+
+/// Local error type for failures in the HAL service.
+#[derive(Debug, Clone)]
+struct HalServiceError(String);
+
+impl From<String> for HalServiceError {
+ fn from(s: String) -> Self {
+ Self(s)
+ }
+}
+
+fn main() {
+ if let Err(e) = inner_main() {
+ panic!("HAL service failed: {:?}", e);
+ }
+}
+
+fn inner_main() -> Result<(), HalServiceError> {
+ // Initialize Android logging.
+ android_logger::init_once(
+ android_logger::Config::default()
+ .with_tag("keymint-hal-nonsecure")
+ .with_max_level(log::LevelFilter::Info)
+ .with_log_buffer(android_logger::LogId::System),
+ );
+ // Redirect panic messages to logcat.
+ std::panic::set_hook(Box::new(|panic_info| {
+ error!("{}", panic_info);
+ }));
+
+ info!("Insecure KeyMint HAL service is starting.");
+
+ info!("Starting thread pool now.");
+ binder::ProcessState::start_thread_pool();
+
+ // Create a TA in-process, which acts as a local channel for communication.
+ let channel = Arc::new(Mutex::new(LocalTa::new()));
+
+ let km_service = kmr_hal::keymint::Device::new_as_binder(channel.clone());
+ let service_name = format!("{}/{}", KM_SERVICE_NAME, SERVICE_INSTANCE);
+ binder::add_service(&service_name, km_service.as_binder()).map_err(|e| {
+ HalServiceError(format!(
+ "Failed to register service {} because of {:?}.",
+ service_name, e
+ ))
+ })?;
+
+ let rpc_service = kmr_hal::rpc::Device::new_as_binder(channel.clone());
+ let service_name = format!("{}/{}", RPC_SERVICE_NAME, SERVICE_INSTANCE);
+ binder::add_service(&service_name, rpc_service.as_binder()).map_err(|e| {
+ HalServiceError(format!(
+ "Failed to register service {} because of {:?}.",
+ service_name, e
+ ))
+ })?;
+
+ let clock_service = kmr_hal::secureclock::Device::new_as_binder(channel.clone());
+ let service_name = format!("{}/{}", CLOCK_SERVICE_NAME, SERVICE_INSTANCE);
+ binder::add_service(&service_name, clock_service.as_binder()).map_err(|e| {
+ HalServiceError(format!(
+ "Failed to register service {} because of {:?}.",
+ service_name, e
+ ))
+ })?;
+
+ let secret_service = kmr_hal::sharedsecret::Device::new_as_binder(channel.clone());
+ let service_name = format!("{}/{}", SECRET_SERVICE_NAME, SERVICE_INSTANCE);
+ binder::add_service(&service_name, secret_service.as_binder()).map_err(|e| {
+ HalServiceError(format!(
+ "Failed to register service {} because of {:?}.",
+ service_name, e
+ ))
+ })?;
+
+ info!("Successfully registered KeyMint HAL services.");
+
+ // Let the TA know information about the boot environment. In a real device this
+ // is communicated directly from the bootloader to the TA, but here we retrieve
+ // the information from system properties and send from the HAL service.
+ let boot_req = get_boot_info();
+ debug!("boot/HAL->TA: boot info is {:?}", boot_req);
+ kmr_hal::send_boot_info(channel.lock().unwrap().deref_mut(), boot_req)
+ .map_err(|e| HalServiceError(format!("Failed to send boot info: {:?}", e)))?;
+
+ // Let the TA know information about the userspace environment.
+ if let Err(e) = kmr_hal::send_hal_info(channel.lock().unwrap().deref_mut()) {
+ error!("Failed to send HAL info: {:?}", e);
+ }
+
+ // Let the TA know about attestation IDs. (In a real device these would be pre-provisioned into
+ // the TA.)
+ let attest_ids = attestation_id_info();
+ if let Err(e) = kmr_hal::send_attest_ids(channel.lock().unwrap().deref_mut(), attest_ids) {
+ error!("Failed to send attestation ID info: {:?}", e);
+ }
+
+ info!("Successfully registered KeyMint HAL services.");
+ binder::ProcessState::join_thread_pool();
+ info!("KeyMint HAL service is terminating."); // should not reach here
+ Ok(())
+}
+
+/// Implementation of the KeyMint TA that runs locally in-process (and which is therefore
+/// insecure).
+#[derive(Debug)]
+pub struct LocalTa {
+ in_tx: mpsc::Sender<Vec<u8>>,
+ out_rx: mpsc::Receiver<Vec<u8>>,
+}
+
+impl LocalTa {
+ /// Create a new instance.
+ pub fn new() -> Self {
+ // Create a pair of channels to communicate with the TA thread.
+ let (in_tx, in_rx) = mpsc::channel();
+ let (out_tx, out_rx) = mpsc::channel();
+
+ // The TA code expects to run single threaded, so spawn a thread to run it in.
+ std::thread::spawn(move || {
+ let mut ta = kmr_ta_nonsecure::build_ta();
+ loop {
+ let req_data: Vec<u8> = in_rx.recv().expect("failed to receive next req");
+ let rsp_data = ta.process(&req_data);
+ out_tx.send(rsp_data).expect("failed to send out rsp");
+ }
+ });
+ Self { in_tx, out_rx }
+ }
+}
+
+impl SerializedChannel for LocalTa {
+ const MAX_SIZE: usize = usize::MAX;
+
+ fn execute(&mut self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+ self.in_tx
+ .send(req_data.to_vec())
+ .expect("failed to send in request");
+ Ok(self.out_rx.recv().expect("failed to receive response"))
+ }
+}
diff --git a/security/keymint/aidl/default/ta/attest.rs b/security/keymint/aidl/default/ta/attest.rs
new file mode 100644
index 0000000..1ce2066
--- /dev/null
+++ b/security/keymint/aidl/default/ta/attest.rs
@@ -0,0 +1,425 @@
+//
+// 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.
+
+//! Attestation keys and certificates.
+//!
+//! Hard-coded keys and certs copied from system/keymaster/context/soft_attestation_cert.cpp
+
+use kmr_common::{
+ crypto::ec, crypto::rsa, crypto::CurveType, crypto::KeyMaterial, wire::keymint,
+ wire::keymint::EcCurve, Error,
+};
+use kmr_ta::device::{RetrieveCertSigningInfo, SigningAlgorithm, SigningKeyType};
+
+/// RSA attestation private key in PKCS#1 format.
+///
+/// Decoded contents (using [der2ascii](https://github.com/google/der-ascii)):
+///
+/// ```
+/// SEQUENCE {
+/// INTEGER { 0 }
+/// INTEGER { `00c08323dc56881bb8302069f5b08561c6eebe7f05e2f5a842048abe8b47be76feaef25cf29b2afa3200141601429989a15fcfc6815eb363583c2fd2f20be4983283dd814b16d7e185417ae54abc296a3a6db5c004083b68c556c1f02339916419864d50b74d40aeca484c77356c895a0c275abfac499d5d7d2362f29c5e02e871` }
+/// INTEGER { 65537 }
+/// INTEGER { `00be860b0b99a802a6fb1a59438a7bb715065b09a36dc6e9cacc6bf3c02c34d7d79e94c6606428d88c7b7f6577c1cdea64074abe8e7286df1f0811dc9728260868de95d32efc96b6d084ff271a5f60defcc703e7a38e6e29ba9a3c5fc2c28076b6a896af1d34d78828ce9bddb1f34f9c9404430781298e201316725bbdbc993a41` }
+/// INTEGER { `00e1c6d927646c0916ec36826d594983740c21f1b074c4a1a59867c669795c85d3dc464c5b929e94bfb34e0dcc5014b10f13341ab7fdd5f60414d2a326cad41cc5` }
+/// INTEGER { `00da485997785cd5630fb0fd8c5254f98e538e18983aae9e6b7e6a5a7b5d343755b9218ebd40320d28387d789f76fa218bcc2d8b68a5f6418fbbeca5179ab3afbd` }
+/// INTEGER { `50fefc32649559616ed6534e154509329d93a3d810dbe5bdb982292cf78bd8badb8020ae8d57f4b71d05386ffe9e9db271ca3477a34999db76f8e5ece9c0d49d` }
+/// INTEGER { `15b74cf27cceff8bb36bf04d9d8346b09a2f70d2f4439b0f26ac7e03f7e9d1f77d4b915fd29b2823f03acb5d5200e0857ff2a803e93eee96d6235ce95442bc21` }
+/// INTEGER { `0090a745da8970b2cd649660324228c5f82856ffd665ba9a85c8d60f1b8bee717ecd2c72eae01dad86ba7654d4cf45adb5f1f2b31d9f8122cfa5f1a5570f9b2d25` }
+/// }
+/// ```
+const RSA_ATTEST_KEY: &str = concat!(
+ "3082025d02010002818100c08323dc56881bb8302069f5b08561c6eebe7f05e2",
+ "f5a842048abe8b47be76feaef25cf29b2afa3200141601429989a15fcfc6815e",
+ "b363583c2fd2f20be4983283dd814b16d7e185417ae54abc296a3a6db5c00408",
+ "3b68c556c1f02339916419864d50b74d40aeca484c77356c895a0c275abfac49",
+ "9d5d7d2362f29c5e02e871020301000102818100be860b0b99a802a6fb1a5943",
+ "8a7bb715065b09a36dc6e9cacc6bf3c02c34d7d79e94c6606428d88c7b7f6577",
+ "c1cdea64074abe8e7286df1f0811dc9728260868de95d32efc96b6d084ff271a",
+ "5f60defcc703e7a38e6e29ba9a3c5fc2c28076b6a896af1d34d78828ce9bddb1",
+ "f34f9c9404430781298e201316725bbdbc993a41024100e1c6d927646c0916ec",
+ "36826d594983740c21f1b074c4a1a59867c669795c85d3dc464c5b929e94bfb3",
+ "4e0dcc5014b10f13341ab7fdd5f60414d2a326cad41cc5024100da485997785c",
+ "d5630fb0fd8c5254f98e538e18983aae9e6b7e6a5a7b5d343755b9218ebd4032",
+ "0d28387d789f76fa218bcc2d8b68a5f6418fbbeca5179ab3afbd024050fefc32",
+ "649559616ed6534e154509329d93a3d810dbe5bdb982292cf78bd8badb8020ae",
+ "8d57f4b71d05386ffe9e9db271ca3477a34999db76f8e5ece9c0d49d024015b7",
+ "4cf27cceff8bb36bf04d9d8346b09a2f70d2f4439b0f26ac7e03f7e9d1f77d4b",
+ "915fd29b2823f03acb5d5200e0857ff2a803e93eee96d6235ce95442bc210241",
+ "0090a745da8970b2cd649660324228c5f82856ffd665ba9a85c8d60f1b8bee71",
+ "7ecd2c72eae01dad86ba7654d4cf45adb5f1f2b31d9f8122cfa5f1a5570f9b2d",
+ "25",
+);
+
+/// Attestation certificate corresponding to [`RSA_ATTEST_KEY`], signed by the key in
+/// [`RSA_ATTEST_ROOT_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+/// Data:
+/// Version: 3 (0x2)
+/// Serial Number: 4096 (0x1000)
+/// Signature Algorithm: SHA256-RSA
+/// Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California
+/// Validity:
+/// Not Before: 2016-01-04 12:40:53 +0000 UTC
+/// Not After : 2035-12-30 12:40:53 +0000 UTC
+/// Subject: C=US, O=Google, Inc., OU=Android, ST=California, CN=Android Software Attestation Key
+/// Subject Public Key Info:
+/// Public Key Algorithm: rsaEncryption
+/// Public Key: (1024 bit)
+/// Modulus:
+/// c0:83:23:dc:56:88:1b:b8:30:20:69:f5:b0:85:61:
+/// c6:ee:be:7f:05:e2:f5:a8:42:04:8a:be:8b:47:be:
+/// 76:fe:ae:f2:5c:f2:9b:2a:fa:32:00:14:16:01:42:
+/// 99:89:a1:5f:cf:c6:81:5e:b3:63:58:3c:2f:d2:f2:
+/// 0b:e4:98:32:83:dd:81:4b:16:d7:e1:85:41:7a:e5:
+/// 4a:bc:29:6a:3a:6d:b5:c0:04:08:3b:68:c5:56:c1:
+/// f0:23:39:91:64:19:86:4d:50:b7:4d:40:ae:ca:48:
+/// 4c:77:35:6c:89:5a:0c:27:5a:bf:ac:49:9d:5d:7d:
+/// 23:62:f2:9c:5e:02:e8:71:
+/// Exponent: 65537 (0x10001)
+/// X509v3 extensions:
+/// X509v3 Authority Key Identifier:
+/// keyid:29faf1accc4dd24c96402775b6b0e932e507fe2e
+/// X509v3 Subject Key Identifier:
+/// keyid:d40c101bf8cd63b9f73952b50e135ca6d7999386
+/// X509v3 Key Usage: critical
+/// Digital Signature, Certificate Signing
+/// X509v3 Basic Constraints: critical
+/// CA:true, pathlen:0
+/// Signature Algorithm: SHA256-RSA
+/// 9e:2d:48:5f:8c:67:33:dc:1a:85:ad:99:d7:50:23:ea:14:ec:
+/// 43:b0:e1:9d:ea:c2:23:46:1e:72:b5:19:dc:60:22:e4:a5:68:
+/// 31:6c:0b:55:c4:e6:9c:a2:2d:9f:3a:4f:93:6b:31:8b:16:78:
+/// 16:0d:88:cb:d9:8b:cc:80:9d:84:f0:c2:27:e3:6b:38:f1:fd:
+/// d1:e7:17:72:31:59:35:7d:96:f3:c5:7f:ab:9d:8f:96:61:26:
+/// 4f:b2:be:81:bb:0d:49:04:22:8a:ce:9f:f7:f5:42:2e:25:44:
+/// fa:21:07:12:5a:83:b5:55:ad:18:82:f8:40:14:9b:9c:20:63:
+/// 04:7f:
+/// ```
+const RSA_ATTEST_CERT: &str = concat!(
+ "308202b63082021fa00302010202021000300d06092a864886f70d01010b0500",
+ "3063310b30090603550406130255533113301106035504080c0a43616c69666f",
+ "726e69613116301406035504070c0d4d6f756e7461696e205669657731153013",
+ "060355040a0c0c476f6f676c652c20496e632e3110300e060355040b0c07416e",
+ "64726f6964301e170d3136303130343132343035335a170d3335313233303132",
+ "343035335a3076310b30090603550406130255533113301106035504080c0a43",
+ "616c69666f726e696131153013060355040a0c0c476f6f676c652c20496e632e",
+ "3110300e060355040b0c07416e64726f69643129302706035504030c20416e64",
+ "726f696420536f667477617265204174746573746174696f6e204b657930819f",
+ "300d06092a864886f70d010101050003818d0030818902818100c08323dc5688",
+ "1bb8302069f5b08561c6eebe7f05e2f5a842048abe8b47be76feaef25cf29b2a",
+ "fa3200141601429989a15fcfc6815eb363583c2fd2f20be4983283dd814b16d7",
+ "e185417ae54abc296a3a6db5c004083b68c556c1f02339916419864d50b74d40",
+ "aeca484c77356c895a0c275abfac499d5d7d2362f29c5e02e8710203010001a3",
+ "663064301d0603551d0e04160414d40c101bf8cd63b9f73952b50e135ca6d799",
+ "9386301f0603551d2304183016801429faf1accc4dd24c96402775b6b0e932e5",
+ "07fe2e30120603551d130101ff040830060101ff020100300e0603551d0f0101",
+ "ff040403020284300d06092a864886f70d01010b0500038181009e2d485f8c67",
+ "33dc1a85ad99d75023ea14ec43b0e19deac223461e72b519dc6022e4a568316c",
+ "0b55c4e69ca22d9f3a4f936b318b1678160d88cbd98bcc809d84f0c227e36b38",
+ "f1fdd1e717723159357d96f3c57fab9d8f9661264fb2be81bb0d4904228ace9f",
+ "f7f5422e2544fa2107125a83b555ad1882f840149b9c2063047f",
+);
+
+/// Attestation self-signed root certificate holding the key that signed [`RSA_ATTEST_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+/// Data:
+/// Version: 3 (0x2)
+/// Serial Number: 18416584322103887884 (0xff94d9dd9f07c80c)
+/// Signature Algorithm: SHA256-RSA
+/// Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California
+/// Validity:
+/// Not Before: 2016-01-04 12:31:08 +0000 UTC
+/// Not After : 2035-12-30 12:31:08 +0000 UTC
+/// Subject: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California
+/// Subject Public Key Info:
+/// Public Key Algorithm: rsaEncryption
+/// Public Key: (1024 bit)
+/// Modulus:
+/// a2:6b:ad:eb:6e:2e:44:61:ef:d5:0e:82:e6:b7:94:
+/// d1:75:23:1f:77:9b:63:91:63:ff:f7:aa:ff:0b:72:
+/// 47:4e:c0:2c:43:ec:33:7c:d7:ac:ed:40:3e:8c:28:
+/// a0:66:d5:f7:87:0b:33:97:de:0e:b8:4e:13:40:ab:
+/// af:a5:27:bf:95:69:a0:31:db:06:52:65:f8:44:59:
+/// 57:61:f0:bb:f2:17:4b:b7:41:80:64:c0:28:0e:8f:
+/// 52:77:8e:db:d2:47:b6:45:e9:19:c8:e9:8b:c3:db:
+/// c2:91:3f:d7:d7:50:c4:1d:35:66:f9:57:e4:97:96:
+/// 0b:09:ac:ce:92:35:85:9b:
+/// Exponent: 65537 (0x10001)
+/// X509v3 extensions:
+/// X509v3 Authority Key Identifier:
+/// keyid:29faf1accc4dd24c96402775b6b0e932e507fe2e
+/// X509v3 Subject Key Identifier:
+/// keyid:29faf1accc4dd24c96402775b6b0e932e507fe2e
+/// X509v3 Key Usage: critical
+/// Digital Signature, Certificate Signing
+/// X509v3 Basic Constraints: critical
+/// CA:true
+/// Signature Algorithm: SHA256-RSA
+/// 4f:72:f3:36:59:8d:0e:c1:b9:74:5b:31:59:f6:f0:8d:25:49:
+/// 30:9e:a3:1c:1c:29:d2:45:2d:20:b9:4d:5f:64:b4:e8:80:c7:
+/// 78:7a:9c:39:de:a8:b3:f5:bf:2f:70:5f:47:10:5c:c5:e6:eb:
+/// 4d:06:99:61:d2:ae:9a:07:ff:f7:7c:b8:ab:eb:9c:0f:24:07:
+/// 5e:b1:7f:ba:79:71:fd:4d:5b:9e:df:14:a9:fe:df:ed:7c:c0:
+/// 88:5d:f8:dd:9b:64:32:56:d5:35:9a:e2:13:f9:8f:ce:c1:7c:
+/// dc:ef:a4:aa:b2:55:c3:83:a9:2e:fb:5c:f6:62:f5:27:52:17:
+/// be:63:
+/// ```
+const RSA_ATTEST_ROOT_CERT: &str = concat!(
+ "308202a730820210a003020102020900ff94d9dd9f07c80c300d06092a864886",
+ "f70d01010b05003063310b30090603550406130255533113301106035504080c",
+ "0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e2056",
+ "69657731153013060355040a0c0c476f6f676c652c20496e632e3110300e0603",
+ "55040b0c07416e64726f6964301e170d3136303130343132333130385a170d33",
+ "35313233303132333130385a3063310b30090603550406130255533113301106",
+ "035504080c0a43616c69666f726e69613116301406035504070c0d4d6f756e74",
+ "61696e205669657731153013060355040a0c0c476f6f676c652c20496e632e31",
+ "10300e060355040b0c07416e64726f696430819f300d06092a864886f70d0101",
+ "01050003818d0030818902818100a26badeb6e2e4461efd50e82e6b794d17523",
+ "1f779b639163fff7aaff0b72474ec02c43ec337cd7aced403e8c28a066d5f787",
+ "0b3397de0eb84e1340abafa527bf9569a031db065265f844595761f0bbf2174b",
+ "b7418064c0280e8f52778edbd247b645e919c8e98bc3dbc2913fd7d750c41d35",
+ "66f957e497960b09acce9235859b0203010001a3633061301d0603551d0e0416",
+ "041429faf1accc4dd24c96402775b6b0e932e507fe2e301f0603551d23041830",
+ "16801429faf1accc4dd24c96402775b6b0e932e507fe2e300f0603551d130101",
+ "ff040530030101ff300e0603551d0f0101ff040403020284300d06092a864886",
+ "f70d01010b0500038181004f72f336598d0ec1b9745b3159f6f08d2549309ea3",
+ "1c1c29d2452d20b94d5f64b4e880c7787a9c39dea8b3f5bf2f705f47105cc5e6",
+ "eb4d069961d2ae9a07fff77cb8abeb9c0f24075eb17fba7971fd4d5b9edf14a9",
+ "fedfed7cc0885df8dd9b643256d5359ae213f98fcec17cdcefa4aab255c383a9",
+ "2efb5cf662f5275217be63",
+);
+
+/// EC attestation private key in `ECPrivateKey` format.
+///
+/// Decoded contents (using [der2ascii](https://github.com/google/der-ascii)):
+///
+/// ```
+/// SEQUENCE {
+/// INTEGER { 1 }
+/// OCTET_STRING { `21e086432a15198459cf363a50fc14c9daadf935f527c2dfd71e4d6dbc42e544` }
+/// [0] {
+/// # secp256r1
+/// OBJECT_IDENTIFIER { 1.2.840.10045.3.1.7 }
+/// }
+/// [1] {
+/// BIT_STRING { `00` `04eb9e79f8426359accb2a914c8986cc70ad90669382a9732613feaccbf821274c2174974a2afea5b94d7f66d4e065106635bc53b7a0a3a671583edb3e11ae1014` }
+/// }
+/// }
+/// ```
+const EC_ATTEST_KEY: &str = concat!(
+ "3077020101042021e086432a15198459cf363a50fc14c9daadf935f527c2dfd7",
+ "1e4d6dbc42e544a00a06082a8648ce3d030107a14403420004eb9e79f8426359",
+ "accb2a914c8986cc70ad90669382a9732613feaccbf821274c2174974a2afea5",
+ "b94d7f66d4e065106635bc53b7a0a3a671583edb3e11ae1014",
+);
+
+/// Attestation certificate corresponding to [`EC_ATTEST_KEY`], signed by the key in
+/// [`EC_ATTEST_ROOT_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+/// Data:
+/// Version: 3 (0x2)
+/// Serial Number: 4097 (0x1001)
+/// Signature Algorithm: ECDSA-SHA256
+/// Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California, CN=Android Keystore Software Attestation Root
+/// Validity:
+/// Not Before: 2016-01-11 00:46:09 +0000 UTC
+/// Not After : 2026-01-08 00:46:09 +0000 UTC
+/// Subject: C=US, O=Google, Inc., OU=Android, ST=California, CN=Android Keystore Software Attestation Intermediate
+/// Subject Public Key Info:
+/// Public Key Algorithm: id-ecPublicKey
+/// Public Key: (256 bit)
+/// pub:
+/// 04:eb:9e:79:f8:42:63:59:ac:cb:2a:91:4c:89:86:
+/// cc:70:ad:90:66:93:82:a9:73:26:13:fe:ac:cb:f8:
+/// 21:27:4c:21:74:97:4a:2a:fe:a5:b9:4d:7f:66:d4:
+/// e0:65:10:66:35:bc:53:b7:a0:a3:a6:71:58:3e:db:
+/// 3e:11:ae:10:14:
+/// ASN1 OID: prime256v1
+/// X509v3 extensions:
+/// X509v3 Authority Key Identifier:
+/// keyid:c8ade9774c45c3a3cf0d1610e479433a215a30cf
+/// X509v3 Subject Key Identifier:
+/// keyid:3ffcacd61ab13a9e8120b8d5251cc565bb1e91a9
+/// X509v3 Key Usage: critical
+/// Digital Signature, Certificate Signing
+/// X509v3 Basic Constraints: critical
+/// CA:true, pathlen:0
+/// Signature Algorithm: ECDSA-SHA256
+/// 30:45:02:20:4b:8a:9b:7b:ee:82:bc:c0:33:87:ae:2f:c0:89:
+/// 98:b4:dd:c3:8d:ab:27:2a:45:9f:69:0c:c7:c3:92:d4:0f:8e:
+/// 02:21:00:ee:da:01:5d:b6:f4:32:e9:d4:84:3b:62:4c:94:04:
+/// ef:3a:7c:cc:bd:5e:fb:22:bb:e7:fe:b9:77:3f:59:3f:fb:
+/// ```
+const EC_ATTEST_CERT: &str = concat!(
+ "308202783082021ea00302010202021001300a06082a8648ce3d040302308198",
+ "310b30090603550406130255533113301106035504080c0a43616c69666f726e",
+ "69613116301406035504070c0d4d6f756e7461696e2056696577311530130603",
+ "55040a0c0c476f6f676c652c20496e632e3110300e060355040b0c07416e6472",
+ "6f69643133303106035504030c2a416e64726f6964204b657973746f72652053",
+ "6f667477617265204174746573746174696f6e20526f6f74301e170d31363031",
+ "31313030343630395a170d3236303130383030343630395a308188310b300906",
+ "03550406130255533113301106035504080c0a43616c69666f726e6961311530",
+ "13060355040a0c0c476f6f676c652c20496e632e3110300e060355040b0c0741",
+ "6e64726f6964313b303906035504030c32416e64726f6964204b657973746f72",
+ "6520536f667477617265204174746573746174696f6e20496e7465726d656469",
+ "6174653059301306072a8648ce3d020106082a8648ce3d03010703420004eb9e",
+ "79f8426359accb2a914c8986cc70ad90669382a9732613feaccbf821274c2174",
+ "974a2afea5b94d7f66d4e065106635bc53b7a0a3a671583edb3e11ae1014a366",
+ "3064301d0603551d0e041604143ffcacd61ab13a9e8120b8d5251cc565bb1e91",
+ "a9301f0603551d23041830168014c8ade9774c45c3a3cf0d1610e479433a215a",
+ "30cf30120603551d130101ff040830060101ff020100300e0603551d0f0101ff",
+ "040403020284300a06082a8648ce3d040302034800304502204b8a9b7bee82bc",
+ "c03387ae2fc08998b4ddc38dab272a459f690cc7c392d40f8e022100eeda015d",
+ "b6f432e9d4843b624c9404ef3a7cccbd5efb22bbe7feb9773f593ffb",
+);
+
+/// Attestation self-signed root certificate holding the key that signed [`EC_ATTEST_CERT`].
+///
+/// Decoded contents:
+///
+/// ```
+/// Certificate:
+/// Data:
+/// Version: 3 (0x2)
+/// Serial Number: 11674912229752527703 (0xa2059ed10e435b57)
+/// Signature Algorithm: ECDSA-SHA256
+/// Issuer: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California, CN=Android Keystore Software Attestation Root
+/// Validity:
+/// Not Before: 2016-01-11 00:43:50 +0000 UTC
+/// Not After : 2036-01-06 00:43:50 +0000 UTC
+/// Subject: C=US, O=Google, Inc., OU=Android, L=Mountain View, ST=California, CN=Android Keystore Software Attestation Root
+/// Subject Public Key Info:
+/// Public Key Algorithm: id-ecPublicKey
+/// Public Key: (256 bit)
+/// pub:
+/// 04:ee:5d:5e:c7:e1:c0:db:6d:03:a6:7e:e6:b6:1b:
+/// ec:4d:6a:5d:6a:68:2e:0f:ff:7f:49:0e:7d:77:1f:
+/// 44:22:6d:bd:b1:af:fa:16:cb:c7:ad:c5:77:d2:56:
+/// 9c:aa:b7:b0:2d:54:01:5d:3e:43:2b:2a:8e:d7:4e:
+/// ec:48:75:41:a4:
+/// ASN1 OID: prime256v1
+/// X509v3 extensions:
+/// X509v3 Authority Key Identifier:
+/// keyid:c8ade9774c45c3a3cf0d1610e479433a215a30cf
+/// X509v3 Subject Key Identifier:
+/// keyid:c8ade9774c45c3a3cf0d1610e479433a215a30cf
+/// X509v3 Key Usage: critical
+/// Digital Signature, Certificate Signing
+/// X509v3 Basic Constraints: critical
+/// CA:true
+/// Signature Algorithm: ECDSA-SHA256
+/// 30:44:02:20:35:21:a3:ef:8b:34:46:1e:9c:d5:60:f3:1d:58:
+/// 89:20:6a:dc:a3:65:41:f6:0d:9e:ce:8a:19:8c:66:48:60:7b:
+/// 02:20:4d:0b:f3:51:d9:30:7c:7d:5b:da:35:34:1d:a8:47:1b:
+/// 63:a5:85:65:3c:ad:4f:24:a7:e7:4d:af:41:7d:f1:bf:
+/// ```
+const EC_ATTEST_ROOT_CERT: &str = concat!(
+ "3082028b30820232a003020102020900a2059ed10e435b57300a06082a8648ce",
+ "3d040302308198310b30090603550406130255533113301106035504080c0a43",
+ "616c69666f726e69613116301406035504070c0d4d6f756e7461696e20566965",
+ "7731153013060355040a0c0c476f6f676c652c20496e632e3110300e06035504",
+ "0b0c07416e64726f69643133303106035504030c2a416e64726f6964204b6579",
+ "73746f726520536f667477617265204174746573746174696f6e20526f6f7430",
+ "1e170d3136303131313030343335305a170d3336303130363030343335305a30",
+ "8198310b30090603550406130255533113301106035504080c0a43616c69666f",
+ "726e69613116301406035504070c0d4d6f756e7461696e205669657731153013",
+ "060355040a0c0c476f6f676c652c20496e632e3110300e060355040b0c07416e",
+ "64726f69643133303106035504030c2a416e64726f6964204b657973746f7265",
+ "20536f667477617265204174746573746174696f6e20526f6f74305930130607",
+ "2a8648ce3d020106082a8648ce3d03010703420004ee5d5ec7e1c0db6d03a67e",
+ "e6b61bec4d6a5d6a682e0fff7f490e7d771f44226dbdb1affa16cbc7adc577d2",
+ "569caab7b02d54015d3e432b2a8ed74eec487541a4a3633061301d0603551d0e",
+ "04160414c8ade9774c45c3a3cf0d1610e479433a215a30cf301f0603551d2304",
+ "1830168014c8ade9774c45c3a3cf0d1610e479433a215a30cf300f0603551d13",
+ "0101ff040530030101ff300e0603551d0f0101ff040403020284300a06082a86",
+ "48ce3d040302034700304402203521a3ef8b34461e9cd560f31d5889206adca3",
+ "6541f60d9ece8a198c6648607b02204d0bf351d9307c7d5bda35341da8471b63",
+ "a585653cad4f24a7e74daf417df1bf",
+);
+
+/// Per-algorithm attestation certificate signing information.
+pub struct CertSignAlgoInfo {
+ key: KeyMaterial,
+ chain: Vec<keymint::Certificate>,
+}
+
+/// Certificate signing information for all asymmetric key types.
+pub struct CertSignInfo {
+ rsa_info: CertSignAlgoInfo,
+ ec_info: CertSignAlgoInfo,
+}
+
+impl CertSignInfo {
+ /// Create a new cert signing impl.
+ pub fn new() -> Self {
+ CertSignInfo {
+ rsa_info: CertSignAlgoInfo {
+ key: KeyMaterial::Rsa(rsa::Key(hex::decode(RSA_ATTEST_KEY).unwrap()).into()),
+ chain: vec![
+ keymint::Certificate {
+ encoded_certificate: hex::decode(RSA_ATTEST_CERT).unwrap(),
+ },
+ keymint::Certificate {
+ encoded_certificate: hex::decode(RSA_ATTEST_ROOT_CERT).unwrap(),
+ },
+ ],
+ },
+ ec_info: CertSignAlgoInfo {
+ key: KeyMaterial::Ec(
+ EcCurve::P256,
+ CurveType::Nist,
+ ec::Key::P256(ec::NistKey(hex::decode(EC_ATTEST_KEY).unwrap())).into(),
+ ),
+ chain: vec![
+ keymint::Certificate {
+ encoded_certificate: hex::decode(EC_ATTEST_CERT).unwrap(),
+ },
+ keymint::Certificate {
+ encoded_certificate: hex::decode(EC_ATTEST_ROOT_CERT).unwrap(),
+ },
+ ],
+ },
+ }
+ }
+}
+
+impl RetrieveCertSigningInfo for CertSignInfo {
+ fn signing_key(&self, key_type: SigningKeyType) -> Result<KeyMaterial, Error> {
+ Ok(match key_type.algo_hint {
+ SigningAlgorithm::Rsa => self.rsa_info.key.clone(),
+ SigningAlgorithm::Ec => self.ec_info.key.clone(),
+ })
+ }
+
+ fn cert_chain(&self, key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error> {
+ Ok(match key_type.algo_hint {
+ SigningAlgorithm::Rsa => self.rsa_info.chain.clone(),
+ SigningAlgorithm::Ec => self.ec_info.chain.clone(),
+ })
+ }
+}
diff --git a/security/keymint/aidl/default/ta/clock.rs b/security/keymint/aidl/default/ta/clock.rs
new file mode 100644
index 0000000..ad8509a
--- /dev/null
+++ b/security/keymint/aidl/default/ta/clock.rs
@@ -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.
+
+//! Monotonic clock implementation.
+
+use kmr_common::crypto;
+use std::time::Instant;
+
+/// Monotonic clock.
+pub struct StdClock {
+ start: Instant,
+}
+
+impl StdClock {
+ /// Create new clock instance, holding time since construction.
+ pub fn new() -> Self {
+ Self {
+ start: Instant::now(),
+ }
+ }
+}
+
+impl crypto::MonotonicClock for StdClock {
+ fn now(&self) -> crypto::MillisecondsSinceEpoch {
+ let duration = self.start.elapsed();
+ crypto::MillisecondsSinceEpoch(duration.as_millis().try_into().unwrap())
+ }
+}
diff --git a/security/keymint/aidl/default/ta/lib.rs b/security/keymint/aidl/default/ta/lib.rs
new file mode 100644
index 0000000..fe8ad95
--- /dev/null
+++ b/security/keymint/aidl/default/ta/lib.rs
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Local in-process implementation of the KeyMint TA. This is insecure and should
+//! only be used for testing purposes.
+
+// This crate is `std` using, but some of the code uses macros from a `no_std` world.
+extern crate alloc;
+
+use kmr_common::crypto;
+use kmr_crypto_boring::{
+ aes::BoringAes, aes_cmac::BoringAesCmac, des::BoringDes, ec::BoringEc, eq::BoringEq,
+ hmac::BoringHmac, rng::BoringRng, rsa::BoringRsa, sha256::BoringSha256,
+};
+use kmr_ta::device::{
+ BootloaderDone, CsrSigningAlgorithm, Implementation, TrustedPresenceUnsupported,
+};
+use kmr_ta::{HardwareInfo, KeyMintTa, RpcInfo, RpcInfoV3};
+use kmr_wire::keymint::SecurityLevel;
+use kmr_wire::rpc::MINIMUM_SUPPORTED_KEYS_IN_CSR;
+use log::info;
+
+pub mod attest;
+pub mod clock;
+pub mod rpc;
+pub mod soft;
+
+/// Build a set of crypto trait implementations based around BoringSSL and the standard library
+/// clock.
+pub fn boringssl_crypto_impls() -> crypto::Implementation {
+ let rng = BoringRng;
+ let clock = clock::StdClock::new();
+ let rsa = BoringRsa::default();
+ let ec = BoringEc::default();
+ crypto::Implementation {
+ rng: Box::new(rng),
+ clock: Some(Box::new(clock)),
+ compare: Box::new(BoringEq),
+ aes: Box::new(BoringAes),
+ des: Box::new(BoringDes),
+ hmac: Box::new(BoringHmac),
+ rsa: Box::new(rsa),
+ ec: Box::new(ec),
+ ckdf: Box::new(BoringAesCmac),
+ hkdf: Box::new(BoringHmac),
+ sha256: Box::new(BoringSha256),
+ }
+}
+
+/// Build a [`kmr_ta::KeyMintTa`] instance for nonsecure use.
+pub fn build_ta() -> kmr_ta::KeyMintTa {
+ info!("Building NON-SECURE KeyMint Rust TA");
+ let hw_info = HardwareInfo {
+ version_number: 1,
+ security_level: SecurityLevel::TrustedEnvironment,
+ impl_name: "Rust reference implementation",
+ author_name: "Google",
+ unique_id: "NON-SECURE KeyMint TA",
+ };
+ let rpc_sign_algo = CsrSigningAlgorithm::EdDSA;
+ let rpc_info_v3 = RpcInfoV3 {
+ author_name: "Google",
+ unique_id: "NON-SECURE KeyMint TA",
+ fused: false,
+ supported_num_of_keys_in_csr: MINIMUM_SUPPORTED_KEYS_IN_CSR,
+ };
+
+ let sign_info = attest::CertSignInfo::new();
+ let keys: Box<dyn kmr_ta::device::RetrieveKeyMaterial> = Box::new(soft::Keys);
+ let rpc: Box<dyn kmr_ta::device::RetrieveRpcArtifacts> = Box::new(soft::RpcArtifacts::new(
+ soft::Derive::default(),
+ rpc_sign_algo,
+ ));
+ let dev = Implementation {
+ keys,
+ sign_info: Box::new(sign_info),
+ // HAL populates attestation IDs from properties.
+ attest_ids: None,
+ sdd_mgr: None,
+ // `BOOTLOADER_ONLY` keys not supported.
+ bootloader: Box::new(BootloaderDone),
+ // `STORAGE_KEY` keys not supported.
+ sk_wrapper: None,
+ // `TRUSTED_USER_PRESENCE_REQUIRED` keys not supported
+ tup: Box::new(TrustedPresenceUnsupported),
+ // No support for converting previous implementation's keyblobs.
+ legacy_key: None,
+ rpc,
+ };
+ KeyMintTa::new(
+ hw_info,
+ RpcInfo::V3(rpc_info_v3),
+ boringssl_crypto_impls(),
+ dev,
+ )
+}
diff --git a/security/keymint/aidl/default/ta/rpc.rs b/security/keymint/aidl/default/ta/rpc.rs
new file mode 100644
index 0000000..39da50e
--- /dev/null
+++ b/security/keymint/aidl/default/ta/rpc.rs
@@ -0,0 +1,234 @@
+//
+// 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.
+
+//! Emulated implementation of device traits for `IRemotelyProvisionedComponent`.
+
+use core::cell::RefCell;
+use kmr_common::crypto::{ec, ec::CoseKeyPurpose, Ec, KeyMaterial};
+use kmr_common::{crypto, explicit, rpc_err, vec_try, Error};
+use kmr_crypto_boring::{ec::BoringEc, hmac::BoringHmac, rng::BoringRng};
+use kmr_ta::device::{
+ CsrSigningAlgorithm, DiceInfo, PubDiceArtifacts, RetrieveRpcArtifacts, RpcV2Req,
+};
+use kmr_wire::coset::{iana, CoseSign1Builder, HeaderBuilder};
+use kmr_wire::keymint::{Digest, EcCurve};
+use kmr_wire::{cbor::value::Value, coset::AsCborValue, rpc, CborError};
+
+/// Trait to encapsulate deterministic derivation of secret data.
+pub trait DeriveBytes {
+ /// Derive `output_len` bytes of data from `context`, deterministically.
+ fn derive_bytes(&self, context: &[u8], output_len: usize) -> Result<Vec<u8>, Error>;
+}
+
+/// Common emulated implementation of RPC artifact retrieval.
+pub struct Artifacts<T: DeriveBytes> {
+ derive: T,
+ sign_algo: CsrSigningAlgorithm,
+ // Invariant once populated: `self.dice_info.signing_algorithm` == `self.sign_algo`
+ dice_info: RefCell<Option<DiceInfo>>,
+ // Invariant once populated: `self.bcc_signing_key` is a variant that matches `self.sign_algo`
+ bcc_signing_key: RefCell<Option<ec::Key>>,
+}
+
+impl<T: DeriveBytes> RetrieveRpcArtifacts for Artifacts<T> {
+ fn derive_bytes_from_hbk(
+ &self,
+ _hkdf: &dyn crypto::Hkdf,
+ context: &[u8],
+ output_len: usize,
+ ) -> Result<Vec<u8>, Error> {
+ self.derive.derive_bytes(context, output_len)
+ }
+
+ fn get_dice_info(&self, _test_mode: rpc::TestMode) -> Result<DiceInfo, Error> {
+ if self.dice_info.borrow().is_none() {
+ let (dice_info, priv_key) = self.generate_dice_artifacts(rpc::TestMode(false))?;
+ *self.dice_info.borrow_mut() = Some(dice_info);
+ *self.bcc_signing_key.borrow_mut() = Some(priv_key);
+ }
+
+ Ok(self
+ .dice_info
+ .borrow()
+ .as_ref()
+ .ok_or_else(|| rpc_err!(Failed, "DICE artifacts are not initialized."))?
+ .clone())
+ }
+
+ fn sign_data(
+ &self,
+ ec: &dyn crypto::Ec,
+ data: &[u8],
+ _rpc_v2: Option<RpcV2Req>,
+ ) -> Result<Vec<u8>, Error> {
+ // DICE artifacts should have been initialized via `get_dice_info()` by the time this
+ // method is called.
+ let private_key = self
+ .bcc_signing_key
+ .borrow()
+ .as_ref()
+ .ok_or_else(|| rpc_err!(Failed, "DICE artifacts are not initialized."))?
+ .clone();
+
+ let mut op = ec.begin_sign(private_key.into(), self.signing_digest())?;
+ op.update(data)?;
+ let sig = op.finish()?;
+ crypto::ec::to_cose_signature(self.signing_curve(), sig)
+ }
+}
+
+impl<T: DeriveBytes> Artifacts<T> {
+ /// Constructor.
+ pub fn new(derive: T, sign_algo: CsrSigningAlgorithm) -> Self {
+ Self {
+ derive,
+ sign_algo,
+ dice_info: RefCell::new(None),
+ bcc_signing_key: RefCell::new(None),
+ }
+ }
+
+ /// Indicate the curve used in signing.
+ fn signing_curve(&self) -> EcCurve {
+ match self.sign_algo {
+ CsrSigningAlgorithm::ES256 => EcCurve::P256,
+ CsrSigningAlgorithm::ES384 => EcCurve::P384,
+ CsrSigningAlgorithm::EdDSA => EcCurve::Curve25519,
+ }
+ }
+
+ /// Indicate the digest used in signing.
+ fn signing_digest(&self) -> Digest {
+ match self.sign_algo {
+ CsrSigningAlgorithm::ES256 => Digest::Sha256,
+ CsrSigningAlgorithm::ES384 => Digest::Sha384,
+ CsrSigningAlgorithm::EdDSA => Digest::None,
+ }
+ }
+
+ /// Indicate the COSE algorithm value associated with signing.
+ fn signing_cose_algo(&self) -> iana::Algorithm {
+ match self.sign_algo {
+ CsrSigningAlgorithm::ES256 => iana::Algorithm::ES256,
+ CsrSigningAlgorithm::ES384 => iana::Algorithm::ES384,
+ CsrSigningAlgorithm::EdDSA => iana::Algorithm::EdDSA,
+ }
+ }
+
+ fn generate_dice_artifacts(
+ &self,
+ _test_mode: rpc::TestMode,
+ ) -> Result<(DiceInfo, ec::Key), Error> {
+ let ec = BoringEc::default();
+
+ let key_material = match self.sign_algo {
+ CsrSigningAlgorithm::EdDSA => {
+ let secret = self.derive_bytes_from_hbk(&BoringHmac, b"Device Key Seed", 32)?;
+ ec::import_raw_ed25519_key(&secret)
+ }
+ // TODO: generate the *same* key after reboot, by use of the TPM.
+ CsrSigningAlgorithm::ES256 => {
+ ec.generate_nist_key(&mut BoringRng, ec::NistCurve::P256, &[])
+ }
+ CsrSigningAlgorithm::ES384 => {
+ ec.generate_nist_key(&mut BoringRng, ec::NistCurve::P384, &[])
+ }
+ }?;
+ let (pub_cose_key, private_key) = match key_material {
+ KeyMaterial::Ec(curve, curve_type, key) => (
+ key.public_cose_key(
+ &ec,
+ curve,
+ curve_type,
+ CoseKeyPurpose::Sign,
+ None, /* no key ID */
+ rpc::TestMode(false),
+ )?,
+ key,
+ ),
+ _ => {
+ return Err(rpc_err!(
+ Failed,
+ "expected the Ec variant of KeyMaterial for the cdi leaf key."
+ ))
+ }
+ };
+
+ let cose_key_cbor = pub_cose_key.to_cbor_value().map_err(CborError::from)?;
+ let cose_key_cbor_data = kmr_ta::rkp::serialize_cbor(&cose_key_cbor)?;
+
+ // Construct `DiceChainEntryPayload`
+ let dice_chain_entry_payload = Value::Map(vec_try![
+ // Issuer
+ (
+ Value::Integer(1.into()),
+ Value::Text(String::from("Issuer"))
+ ),
+ // Subject
+ (
+ Value::Integer(2.into()),
+ Value::Text(String::from("Subject"))
+ ),
+ // Subject public key
+ (
+ Value::Integer((-4670552).into()),
+ Value::Bytes(cose_key_cbor_data)
+ ),
+ // Key Usage field contains a CBOR byte string of the bits which correspond
+ // to `keyCertSign` as per RFC 5280 Section 4.2.1.3 (in little-endian byte order)
+ (
+ Value::Integer((-4670553).into()),
+ Value::Bytes(vec_try![0x20]?)
+ ),
+ ]?);
+ let dice_chain_entry_payload_data = kmr_ta::rkp::serialize_cbor(&dice_chain_entry_payload)?;
+
+ // Construct `DiceChainEntry`
+ let protected = HeaderBuilder::new()
+ .algorithm(self.signing_cose_algo())
+ .build();
+ let dice_chain_entry = CoseSign1Builder::new()
+ .protected(protected)
+ .payload(dice_chain_entry_payload_data)
+ .try_create_signature(&[], |input| {
+ let mut op = ec.begin_sign(private_key.clone(), self.signing_digest())?;
+ op.update(input)?;
+ let sig = op.finish()?;
+ crypto::ec::to_cose_signature(self.signing_curve(), sig)
+ })?
+ .build();
+ let dice_chain_entry_cbor = dice_chain_entry.to_cbor_value().map_err(CborError::from)?;
+
+ // Construct `DiceCertChain`
+ let dice_cert_chain = Value::Array(vec_try![cose_key_cbor, dice_chain_entry_cbor]?);
+ let dice_cert_chain_data = kmr_ta::rkp::serialize_cbor(&dice_cert_chain)?;
+
+ // Construct `UdsCerts` as an empty CBOR map
+ let uds_certs_data = kmr_ta::rkp::serialize_cbor(&Value::Map(Vec::new()))?;
+
+ let pub_dice_artifacts = PubDiceArtifacts {
+ dice_cert_chain: dice_cert_chain_data,
+ uds_certs: uds_certs_data,
+ };
+
+ let dice_info = DiceInfo {
+ pub_dice_artifacts,
+ signing_algorithm: self.sign_algo,
+ rpc_v2_test_cdi_priv: None,
+ };
+
+ Ok((dice_info, explicit!(private_key)?))
+ }
+}
diff --git a/security/keymint/aidl/default/ta/soft.rs b/security/keymint/aidl/default/ta/soft.rs
new file mode 100644
index 0000000..5bbe060
--- /dev/null
+++ b/security/keymint/aidl/default/ta/soft.rs
@@ -0,0 +1,67 @@
+//
+// 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.
+
+//! Software-only trait implementations using fake keys.
+
+use kmr_common::{
+ crypto,
+ crypto::{Hkdf, Rng},
+ Error,
+};
+use kmr_crypto_boring::{hmac::BoringHmac, rng::BoringRng};
+use kmr_ta::device::RetrieveKeyMaterial;
+
+/// Root key retrieval using hard-coded fake keys.
+pub struct Keys;
+
+impl RetrieveKeyMaterial for Keys {
+ fn root_kek(&self, _context: &[u8]) -> Result<crypto::OpaqueOr<crypto::hmac::Key>, Error> {
+ // Matches `MASTER_KEY` in system/keymaster/key_blob_utils/software_keyblobs.cpp
+ Ok(crypto::hmac::Key::new([0; 16].to_vec()).into())
+ }
+ fn kak(&self) -> Result<crypto::OpaqueOr<crypto::aes::Key>, Error> {
+ // Matches `kFakeKeyAgreementKey` in
+ // system/keymaster/km_openssl/soft_keymaster_enforcement.cpp.
+ Ok(crypto::aes::Key::Aes256([0; 32]).into())
+ }
+ fn unique_id_hbk(&self, _ckdf: &dyn crypto::Ckdf) -> Result<crypto::hmac::Key, Error> {
+ // Matches value used in system/keymaster/contexts/pure_soft_keymaster_context.cpp.
+ crypto::hmac::Key::new_from(b"MustBeRandomBits")
+ }
+}
+
+/// Implementation of key derivation using a random fake key.
+pub struct Derive {
+ hbk: Vec<u8>,
+}
+
+impl Default for Derive {
+ fn default() -> Self {
+ // Use random data as an emulation of a hardware-backed key.
+ let mut hbk = vec![0; 32];
+ let mut rng = BoringRng;
+ rng.fill_bytes(&mut hbk);
+ Self { hbk }
+ }
+}
+
+impl crate::rpc::DeriveBytes for Derive {
+ fn derive_bytes(&self, context: &[u8], output_len: usize) -> Result<Vec<u8>, Error> {
+ BoringHmac.hkdf(&[], &self.hbk, context, output_len)
+ }
+}
+
+/// RPC artifact retrieval using software fake key.
+pub type RpcArtifacts = crate::rpc::Artifacts<Derive>;
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 087f763..c121d31 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -2024,7 +2024,7 @@
}
}
- if (KeyMintAidlTestBase::dump_Attestations) std::cout << cert_data.str();
+ if (KeyMintAidlTestBase::dump_Attestations) std::cout << "cert chain:\n" << cert_data.str();
return AssertionSuccess();
}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
index f668536..98cf023 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -28,8 +28,9 @@
parcelable DeviceInfo {
/**
* DeviceInfo is a CBOR Map structure described by the following CDDL. DeviceInfo must be
- * canonicalized according to the specification in RFC 7049. The ordering presented here is
- * non-canonical to group similar entries semantically.
+ * ordered according to the Length-First Map Key Ordering specified in RFC 8949,
+ * Section 4.2.3. Please note that the ordering presented here groups similar entries
+ * semantically, and not in the correct order per RFC 8949, Section 4.2.3.
*
* The DeviceInfo has changed across versions 1, 2, and 3 of the HAL. All versions of the
* DeviceInfo CDDL are described in the DeviceInfoV*.cddl files. Please refer to the CDDL