Merge changes from topic "bluetooth_finder_hal" into main
* changes:
Bluetooth Finder: Add Vts and AIDL default implement
Bluetooth Finder: Interface for Bluetooth Finder
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
index 9f97de0..98ecee0 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
@@ -35,12 +35,13 @@
@VintfStability
union Spatializer {
android.hardware.audio.effect.VendorExtension vendor;
- android.media.audio.common.Spatialization.Level spatializationLevel;
- android.media.audio.common.HeadTracking.Mode headTrackingMode;
android.media.audio.common.AudioChannelLayout[] supportedChannelLayout;
+ android.media.audio.common.Spatialization.Level spatializationLevel;
android.media.audio.common.Spatialization.Mode spatializationMode;
- float[6] headToStage;
- const int HEAD_TO_STAGE_VEC_SIZE = 6;
+ int headTrackingSensorId;
+ android.media.audio.common.HeadTracking.Mode headTrackingMode;
+ android.media.audio.common.HeadTracking.ConnectionMode headTrackingConnectionMode;
+ android.media.audio.common.HeadTracking.SensorData headTrackingSensorData;
@VintfStability
union Id {
android.hardware.audio.effect.VendorExtension vendorExtensionTag;
diff --git a/audio/aidl/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
index 4edb2e8..6ebe0d5 100644
--- a/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
@@ -52,29 +52,37 @@
VendorExtension vendor;
/**
- * Level of spatialization.
- */
- Spatialization.Level spatializationLevel;
-
- /**
- * Head tracking mode for spatialization.
- */
- HeadTracking.Mode headTrackingMode;
-
- /**
* List of supported input channel layouts.
*/
AudioChannelLayout[] supportedChannelLayout;
/**
+ * Level of spatialization.
+ */
+ Spatialization.Level spatializationLevel;
+
+ /**
* Spatialization mode, Binaural or Transaural for example.
*/
Spatialization.Mode spatializationMode;
/**
- * Vector representing of the head-to-stage pose with six floats: first three are a translation
- * vector, and the last three are a rotation vector.
+ * Head tracking sensor ID.
*/
- const int HEAD_TO_STAGE_VEC_SIZE = 6;
- float[HEAD_TO_STAGE_VEC_SIZE] headToStage;
+ int headTrackingSensorId;
+
+ /**
+ * Head tracking mode for spatialization.
+ */
+ HeadTracking.Mode headTrackingMode;
+
+ /**
+ * Head tracking sensor connection mode for spatialization.
+ */
+ HeadTracking.ConnectionMode headTrackingConnectionMode;
+
+ /**
+ * Headtracking sensor data.
+ */
+ HeadTracking.SensorData headTrackingSensorData;
}
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 7b96293..949b654 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -94,6 +94,7 @@
"audio_policy_engine_configuration_aidl_default",
],
shared_libs: [
+ "android.hardware.bluetooth.audio-impl",
"libaudio_aidl_conversion_common_ndk",
"libbluetooth_audio_session_aidl",
"libmedia_helper",
@@ -127,6 +128,7 @@
"libaudioserviceexampleimpl",
],
shared_libs: [
+ "android.hardware.bluetooth.audio-impl",
"libaudio_aidl_conversion_common_ndk",
"libbluetooth_audio_session_aidl",
"libmedia_helper",
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index d09552b..254eb46 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -302,8 +302,9 @@
// 2. The canonical r_submix configuration only lists 'STEREO' and '48000',
// however the framework attempts to open streams for other sample rates
// as well. The legacy r_submix implementation allowed that, but libaudiohal@aidl
-// will not find a mix port to use. Because of that, list all channel
-// masks and sample rates that the legacy implementation allowed.
+// will not find a mix port to use. Because of that, list all sample rates that
+// the legacy implementation allowed (note that mono was not allowed, the framework
+// is expected to upmix mono tracks into stereo if needed).
// 3. The legacy implementation had a hard limit on the number of routes (10),
// and this is checked indirectly by AudioPlaybackCaptureTest#testPlaybackCaptureDoS
// CTS test. Instead of hardcoding the number of routes, we can use
@@ -331,9 +332,8 @@
std::unique_ptr<Configuration> getRSubmixConfiguration() {
static const Configuration configuration = []() {
Configuration c;
- const std::vector<AudioProfile> standardPcmAudioProfiles{
- createProfile(PcmType::INT_16_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ const std::vector<AudioProfile> remoteSubmixPcmAudioProfiles{
+ createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
{8000, 11025, 16000, 32000, 44100, 48000})};
// Device ports
@@ -343,25 +343,25 @@
createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
AudioDeviceDescription::CONNECTION_VIRTUAL));
c.ports.push_back(rsubmixOutDevice);
- c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles;
+ c.connectedProfiles[rsubmixOutDevice.id] = remoteSubmixPcmAudioProfiles;
AudioPort rsubmixInDevice =
createPort(c.nextPortId++, "Remote Submix In", 0, true,
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0,
AudioDeviceDescription::CONNECTION_VIRTUAL));
c.ports.push_back(rsubmixInDevice);
- c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles;
+ c.connectedProfiles[rsubmixInDevice.id] = remoteSubmixPcmAudioProfiles;
// Mix ports
AudioPort rsubmixOutMix =
createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(20, 10));
- rsubmixOutMix.profiles = standardPcmAudioProfiles;
+ rsubmixOutMix.profiles = remoteSubmixPcmAudioProfiles;
c.ports.push_back(rsubmixOutMix);
AudioPort rsubmixInMix =
createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(20, 10));
- rsubmixInMix.profiles = standardPcmAudioProfiles;
+ rsubmixInMix.profiles = remoteSubmixPcmAudioProfiles;
c.ports.push_back(rsubmixInMix);
c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
diff --git a/audio/aidl/default/XsdcConversion.cpp b/audio/aidl/default/XsdcConversion.cpp
index 9e30347..1720949 100644
--- a/audio/aidl/default/XsdcConversion.cpp
+++ b/audio/aidl/default/XsdcConversion.cpp
@@ -205,24 +205,28 @@
ConversionResult<AudioIoFlags> convertIoFlagsToAidl(
const std::vector<ap_xsd::AudioInOutFlag>& flags, const ap_xsd::Role role,
bool flagsForMixPort) {
- int flagMask = 0;
+ int legacyFlagMask = 0;
if ((role == ap_xsd::Role::sink && flagsForMixPort) ||
(role == ap_xsd::Role::source && !flagsForMixPort)) {
for (const ap_xsd::AudioInOutFlag& flag : flags) {
audio_input_flags_t legacyFlag;
if (::android::InputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
- flagMask |= static_cast<int>(legacyFlag);
+ legacyFlagMask |= static_cast<int>(legacyFlag);
}
}
- return AudioIoFlags::make<AudioIoFlags::Tag::input>(flagMask);
+ return AudioIoFlags::make<AudioIoFlags::Tag::input>(
+ VALUE_OR_FATAL(legacy2aidl_audio_input_flags_t_int32_t_mask(
+ static_cast<audio_input_flags_t>(legacyFlagMask))));
} else {
for (const ap_xsd::AudioInOutFlag& flag : flags) {
audio_output_flags_t legacyFlag;
if (::android::OutputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
- flagMask |= static_cast<int>(legacyFlag);
+ legacyFlagMask |= static_cast<int>(legacyFlag);
}
}
- return AudioIoFlags::make<AudioIoFlags::Tag::output>(flagMask);
+ return AudioIoFlags::make<AudioIoFlags::Tag::output>(
+ VALUE_OR_FATAL(legacy2aidl_audio_output_flags_t_int32_t_mask(
+ static_cast<audio_output_flags_t>(legacyFlagMask))));
}
}
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
index 8727232..5e18f1b 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -76,7 +76,7 @@
.proxy = std::nullopt},
.flags = {.type = Flags::Type::PRE_PROC,
.insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
+ .volume = Flags::Volume::NONE},
.name = AcousticEchoCancelerSw::kEffectName,
.implementor = "The Android Open Source Project"},
.capability = AcousticEchoCancelerSw::kCapability};
diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
index 502b153..8a1cbbf 100644
--- a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
@@ -33,8 +33,23 @@
using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+// TODO(b/312265159) bluetooth audio should be in its own process
+// Remove this and the shared_libs when that happens
+extern "C" binder_status_t createIBluetoothAudioProviderFactory();
+
namespace aidl::android::hardware::audio::core {
+ModuleBluetooth::ModuleBluetooth(std::unique_ptr<Module::Configuration>&& config)
+ : Module(Type::BLUETOOTH, std::move(config)) {
+ // TODO(b/312265159) bluetooth audio should be in its own process
+ // Remove this and the shared_libs when that happens
+ binder_status_t status = createIBluetoothAudioProviderFactory();
+ if (status != STATUS_OK) {
+ LOG(ERROR) << "Failed to create bluetooth audio provider factory. Status: "
+ << ::android::statusToString(status);
+ }
+}
+
ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp(
std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
*_aidl_return = getBtA2dp().getInstance();
diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
index a58798b..631b088 100644
--- a/audio/aidl/default/include/core-impl/ModuleBluetooth.h
+++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
@@ -28,8 +28,7 @@
std::weak_ptr<IBluetoothLe>>
BtProfileHandles;
- ModuleBluetooth(std::unique_ptr<Configuration>&& config)
- : Module(Type::BLUETOOTH, std::move(config)) {}
+ ModuleBluetooth(std::unique_ptr<Configuration>&& config);
private:
ChildInterface<BluetoothA2dp>& getBtA2dp();
diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h
index abc119c..145c3c4 100644
--- a/audio/aidl/default/include/core-impl/StreamPrimary.h
+++ b/audio/aidl/default/include/core-impl/StreamPrimary.h
@@ -27,13 +27,18 @@
public:
StreamPrimary(StreamContext* context, const Metadata& metadata);
+ ::android::status_t start() override;
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) override;
+ ::android::status_t refinePosition(StreamDescriptor::Position* position) override;
protected:
std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
const bool mIsAsynchronous;
+ long mStartTimeNs = 0;
+ long mFramesSinceStart = 0;
+ bool mSkipNextTransfer = false;
};
class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
index 99f2caf..a3208df 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
@@ -67,7 +67,7 @@
.proxy = std::nullopt},
.flags = {.type = Flags::Type::PRE_PROC,
.insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
+ .volume = Flags::Volume::NONE},
.name = NoiseSuppressionSw::kEffectName,
.implementor = "The Android Open Source Project"}};
diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp
index 7e3bdd4..b22ef32 100644
--- a/audio/aidl/default/primary/StreamPrimary.cpp
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#include <chrono>
-
#define LOG_TAG "AHAL_StreamPrimary"
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <audio_utils/clock.h>
+#include <error/Result.h>
#include <error/expected_utils.h>
#include "PrimaryMixer.h"
@@ -43,26 +42,52 @@
context->startStreamDataProcessor();
}
+::android::status_t StreamPrimary::start() {
+ RETURN_STATUS_IF_ERROR(StreamAlsa::start());
+ mStartTimeNs = ::android::uptimeNanos();
+ mFramesSinceStart = 0;
+ mSkipNextTransfer = false;
+ return ::android::OK;
+}
+
::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount,
size_t* actualFrameCount, int32_t* latencyMs) {
- auto start = std::chrono::steady_clock::now();
- if (auto status = StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs);
- status != ::android::OK) {
- return status;
- }
// This is a workaround for the emulator implementation which has a host-side buffer
- // and this can result in reading faster than real time.
- if (mIsInput && !mIsAsynchronous) {
- auto recordDurationUs = std::chrono::duration_cast<std::chrono::microseconds>(
- std::chrono::steady_clock::now() - start);
- const long projectedVsObservedOffsetUs =
- *actualFrameCount * MICROS_PER_SECOND / mContext.getSampleRate() -
- recordDurationUs.count();
- if (projectedVsObservedOffsetUs > 0) {
- LOG(VERBOSE) << __func__ << ": sleeping for " << projectedVsObservedOffsetUs << " us";
- usleep(projectedVsObservedOffsetUs);
- }
+ // and is not being able to achieve real-time behavior similar to ADSPs (b/302587331).
+ if (!mSkipNextTransfer) {
+ RETURN_STATUS_IF_ERROR(
+ StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs));
+ } else {
+ LOG(DEBUG) << __func__ << ": skipping transfer (" << frameCount << " frames)";
+ *actualFrameCount = frameCount;
+ if (mIsInput) memset(buffer, 0, frameCount * mFrameSizeBytes);
+ mSkipNextTransfer = false;
}
+ if (!mIsAsynchronous) {
+ const long bufferDurationUs =
+ (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
+ const auto totalDurationUs =
+ (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
+ mFramesSinceStart += *actualFrameCount;
+ const long totalOffsetUs =
+ mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
+ LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
+ if (totalOffsetUs > 0) {
+ const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
+ LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
+ usleep(sleepTimeUs);
+ } else {
+ mSkipNextTransfer = true;
+ }
+ } else {
+ LOG(VERBOSE) << __func__ << ": asynchronous transfer";
+ }
+ return ::android::OK;
+}
+
+::android::status_t StreamPrimary::refinePosition(StreamDescriptor::Position*) {
+ // Since not all data is actually sent to the HAL, use the position maintained by Stream class
+ // which accounts for all frames passed from / to the client.
return ::android::OK;
}
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 38281b9..fc61dcb 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -131,6 +131,8 @@
LOG(DEBUG) << __func__ << ": shutting down MonoPipe sink";
sink->shutdown(true);
+ // The client already considers this stream as closed, release the output end.
+ route->closeStream(mIsInput);
} else {
LOG(DEBUG) << __func__ << ": stream already closed.";
ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 0909f25..285c102 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -73,7 +73,7 @@
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
+ .volume = Flags::Volume::NONE},
.name = VisualizerSw::kEffectName,
.implementor = "The Android Open Source Project"},
.capability = VisualizerSw::kCapability};
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index a633d83..2b86271 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -17,6 +17,9 @@
#include <algorithm>
#include <chrono>
+#define LOG_TAG "VtsHalAudio.ModuleConfig"
+#include <android-base/logging.h>
+
#include <Utils.h>
#include <aidl/android/media/audio/common/AudioInputFlags.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index ca1cea9..aaf9ad4 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -596,8 +596,14 @@
Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
Parameter::VolumeStereo volume = {.left = 10.0, .right = 10.0};
- ASSERT_NO_FATAL_FAILURE(
- setAndGetParameter(id, Parameter::make<Parameter::volumeStereo>(volume)));
+ if (mDescriptor.common.flags.volume == Flags::Volume::CTRL) {
+ Parameter get;
+ EXPECT_IS_OK(mEffect->setParameter(volume));
+ EXPECT_IS_OK(mEffect->getParameter(id, &get));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ setAndGetParameter(id, Parameter::make<Parameter::volumeStereo>(volume)));
+ }
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
diff --git a/audio/effect/4.0/xml/Android.bp b/audio/effect/4.0/xml/Android.bp
index 8c03a35..bdffe60 100644
--- a/audio/effect/4.0/xml/Android.bp
+++ b/audio/effect/4.0/xml/Android.bp
@@ -9,9 +9,9 @@
genrule {
name: "audio_effects_conf_V4_0",
- srcs: ["audio_effects_conf.xsd"],
+ srcs: [":audio_effects_conf_V2_0"],
out: [
"audio_effects_conf_V4_0.xsd",
],
- cmd: "cp -f $(in) $(genDir)/audio_effects_conf_V4_0.xsd",
+ cmd: "cp -f $(in) $(out)",
}
diff --git a/audio/effect/4.0/xml/audio_effects_conf.xsd b/audio/effect/4.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/4.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
index 96110db..e882160 100644
--- a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
@@ -18,9 +18,9 @@
namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
-constexpr CanController::InterfaceType kInterfaceType[] = {CanController::InterfaceType::VIRTUAL,
- CanController::InterfaceType::SOCKETCAN,
- CanController::InterfaceType::SLCAN};
+constexpr CanController::InterfaceType kInterfaceType[] = {
+ CanController::InterfaceType::VIRTUAL, CanController::InterfaceType::SOCKETCAN,
+ CanController::InterfaceType::SLCAN, CanController::InterfaceType::INDEXED};
constexpr FilterFlag kFilterFlag[] = {FilterFlag::DONT_CARE, FilterFlag::SET, FilterFlag::NOT_SET};
constexpr size_t kInterfaceTypeLength = std::size(kInterfaceType);
constexpr size_t kFilterFlagLength = std::size(kFilterFlag);
@@ -28,8 +28,8 @@
constexpr size_t kMaxPayloadBytes = 64;
constexpr size_t kMaxFilters = 20;
constexpr size_t kMaxSerialNumber = 1000;
-constexpr size_t kMaxBuses = 10;
-constexpr size_t kMaxRepeat = 5;
+constexpr size_t kMaxBuses = 100;
+constexpr size_t kMaxRepeat = 100;
Bus CanFuzzer::makeBus() {
ICanController::BusConfig config = {};
@@ -56,9 +56,13 @@
}
void CanFuzzer::invokeUpInterface() {
- const CanController::InterfaceType iftype =
- kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
- 0, kInterfaceTypeLength - 1)];
+ CanController::InterfaceType controller;
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ controller = (CanController::InterfaceType)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+ } else {
+ controller = kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+ 0, kInterfaceTypeLength - 1)];
+ }
std::string configName;
if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
@@ -73,7 +77,7 @@
ICanController::BusConfig config = {.name = configName};
- if (iftype == CanController::InterfaceType::SOCKETCAN) {
+ if (controller == CanController::InterfaceType::SOCKETCAN) {
CanController::BusConfig::InterfaceId::Socketcan socketcan = {};
if (const bool shouldPassSerialSocket = mFuzzedDataProvider->ConsumeBool();
shouldPassSerialSocket) {
@@ -83,7 +87,7 @@
socketcan.ifname(ifname);
}
config.interfaceId.socketcan(socketcan);
- } else if (iftype == CanController::InterfaceType::SLCAN) {
+ } else if (controller == CanController::InterfaceType::SLCAN) {
CanController::BusConfig::InterfaceId::Slcan slcan = {};
if (const bool shouldPassSerialSlcan = mFuzzedDataProvider->ConsumeBool();
shouldPassSerialSlcan) {
@@ -93,8 +97,12 @@
slcan.ttyname(ifname);
}
config.interfaceId.slcan(slcan);
- } else if (iftype == CanController::InterfaceType::VIRTUAL) {
+ } else if (controller == CanController::InterfaceType::VIRTUAL) {
config.interfaceId.virtualif({ifname});
+ } else if (controller == CanController::InterfaceType::INDEXED) {
+ CanController::BusConfig::InterfaceId::Indexed indexed;
+ indexed.index = mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+ config.interfaceId.indexed(indexed);
}
const size_t numInvocations =
@@ -108,8 +116,13 @@
hidl_string configName;
if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
(shouldInvokeValidBus) && (mBusNames.size() > 0)) {
- const size_t busNameIndex =
- mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+ size_t busNameIndex;
+ if (mBusNames.size() == 1) {
+ busNameIndex = 0;
+ } else {
+ busNameIndex =
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+ }
configName = mBusNames[busNameIndex];
} else {
configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
@@ -122,12 +135,6 @@
}
}
-void CanFuzzer::invokeController() {
- getSupportedInterfaceTypes();
- invokeUpInterface();
- invokeDownInterface();
-}
-
void CanFuzzer::invokeBus() {
const size_t numBuses = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(1, kMaxBuses);
for (size_t i = 0; i < numBuses; ++i) {
@@ -152,12 +159,22 @@
for (uint32_t k = 0; k < numFilters; ++k) {
filterVector[k].id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
filterVector[k].mask = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
- filterVector[k].rtr =
- kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
- 0, kFilterFlagLength - 1)];
- filterVector[k].extendedFormat =
- kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
- 0, kFilterFlagLength - 1)];
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ filterVector[k].rtr =
+ (FilterFlag)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+ } else {
+ filterVector[k].rtr =
+ kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+ 0, kFilterFlagLength - 1)];
+ }
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ filterVector[k].extendedFormat =
+ (FilterFlag)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+ } else {
+ filterVector[k].extendedFormat =
+ kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+ 0, kFilterFlagLength - 1)];
+ }
filterVector[k].exclude = mFuzzedDataProvider->ConsumeBool();
}
auto listener = listeningBus.listen(filterVector);
@@ -175,8 +192,16 @@
void CanFuzzer::process(const uint8_t* data, size_t size) {
mFuzzedDataProvider = new FuzzedDataProvider(data, size);
- invokeController();
- invokeBus();
+ while (mFuzzedDataProvider->remaining_bytes()) {
+ auto CanFuzzerFunction =
+ mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() { getSupportedInterfaceTypes(); },
+ [&]() { invokeUpInterface(); },
+ [&]() { invokeDownInterface(); },
+ [&]() { invokeBus(); },
+ });
+ CanFuzzerFunction();
+ }
}
bool CanFuzzer::init() {
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
index 930cddd..3211bd0 100644
--- a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
@@ -116,7 +116,6 @@
hidl_vec<hidl_string> getBusNames();
void getSupportedInterfaceTypes();
void invokeBus();
- void invokeController();
void invokeUpInterface();
void invokeDownInterface();
FuzzedDataProvider* mFuzzedDataProvider = nullptr;
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
index 8a085e5..4d0995d 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
@@ -76,30 +76,20 @@
using ::android::hardware::automotive::vehicle::V2_0::vms::VmsLayerOffering;
using ::android::hardware::automotive::vehicle::V2_0::vms::VmsOffers;
-constexpr const char kCarMake[] = "Default Car";
-constexpr VehicleProperty kVehicleProp[] = {VehicleProperty::INVALID,
- VehicleProperty::HVAC_FAN_SPEED,
- VehicleProperty::INFO_MAKE,
- VehicleProperty::DISPLAY_BRIGHTNESS,
- VehicleProperty::INFO_FUEL_CAPACITY,
- VehicleProperty::HVAC_SEAT_TEMPERATURE};
-constexpr DiagnosticIntegerSensorIndex kDiagnosticIntIndex[] = {
- DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
- DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON,
- DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT,
- DiagnosticIntegerSensorIndex::FUEL_TYPE};
-constexpr DiagnosticFloatSensorIndex kDiagnosticFloatIndex[] = {
- DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD,
- DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1,
- DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1,
- DiagnosticFloatSensorIndex::THROTTLE_POSITION};
-constexpr size_t kVehiclePropArrayLength = std::size(kVehicleProp);
-constexpr size_t kIntSensorArrayLength = std::size(kDiagnosticIntIndex);
-constexpr size_t kFloatSensorArrayLength = std::size(kDiagnosticFloatIndex);
-constexpr VmsMessageType kAvailabilityMessageType[] = {VmsMessageType::AVAILABILITY_CHANGE,
- VmsMessageType::AVAILABILITY_RESPONSE};
-constexpr VmsMessageType kSubscriptionMessageType[] = {VmsMessageType::SUBSCRIPTIONS_CHANGE,
- VmsMessageType::SUBSCRIPTIONS_RESPONSE};
+std::string kCarMake;
+constexpr int32_t kMaxCaseMessage = 8;
+constexpr int32_t kMaxRuns = 20;
+constexpr int32_t kMaxSize = 1000;
+constexpr int32_t kMinSize = 0;
+constexpr int32_t kMaxFileSize = 100;
+float kFloatValue;
+std::vector<int32_t> kVec32;
+std::vector<int64_t> kVec64;
+std::vector<uint8_t> kVec8;
+std::vector<float> kVecFloat;
+static const std::vector<std::string> kSampleDtcs = {"P0070",
+ "P0102"
+ "P0123"};
MockedVehicleHal::VehiclePropValuePtr MockedVehicleHal::get(
const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
@@ -113,23 +103,23 @@
switch (property) {
case VehicleProperty::INFO_MAKE:
- pValue = getValuePool()->obtainString(kCarMake);
+ pValue = getValuePool()->obtainString(kCarMake.c_str());
break;
case VehicleProperty::INFO_FUEL_CAPACITY:
if (mFuelCapacityAttemptsLeft-- > 0) {
*outStatus = StatusCode::TRY_AGAIN;
} else {
- pValue = getValuePool()->obtainFloat(42.42);
+ pValue = getValuePool()->obtainFloat(kFloatValue);
}
break;
default:
if (requestedPropValue.prop == kCustomComplexProperty) {
pValue = getValuePool()->obtainComplex();
- pValue->value.int32Values = hidl_vec<int32_t>{10, 20};
- pValue->value.int64Values = hidl_vec<int64_t>{30, 40};
- pValue->value.floatValues = hidl_vec<float_t>{1.1, 2.2};
- pValue->value.bytes = hidl_vec<uint8_t>{1, 2, 3};
- pValue->value.stringValue = kCarMake;
+ pValue->value.int32Values = hidl_vec<int32_t>{kVec32};
+ pValue->value.int64Values = hidl_vec<int64_t>{kVec64};
+ pValue->value.floatValues = hidl_vec<float_t>{kVecFloat};
+ pValue->value.bytes = hidl_vec<uint8_t>{kVec8};
+ pValue->value.stringValue = kCarMake.c_str();
break;
}
auto key = makeKey(toInt(property), areaId);
@@ -145,28 +135,72 @@
return pValue;
}
+void VehicleHalManagerFuzzer::initValue() {
+ kCarMake = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+ kFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+ fillParameter<int32_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+ kVec32);
+ fillParameter<int64_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+ kVec64);
+ fillParameter<uint8_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+ kVec8);
+ size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+ for (size_t i = 0; i < size; ++i) {
+ kVecFloat.push_back(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
+ }
+}
+
void VehicleHalManagerFuzzer::process(const uint8_t* data, size_t size) {
mFuzzedDataProvider = new FuzzedDataProvider(data, size);
- invokeDebug();
- invokePropConfigs();
- invokeSubscribe();
- invokeSetAndGetValues();
- invokeObd2SensorStore();
- invokeVmsUtils();
- invokeVehiclePropStore();
- invokeWatchDogClient();
+ initValue();
+ /* Limited while loop runs to prevent timeouts caused
+ * by repeated calls to high-execution-time APIs.
+ */
+ size_t maxRuns = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxRuns);
+ size_t itr = 0;
+ while (mFuzzedDataProvider->remaining_bytes() && ++itr <= maxRuns) {
+ auto invokeVehicleHalManagerFuzzer =
+ mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() { invokeDebug(); },
+ [&]() { invokePropConfigs(); },
+ [&]() { invokeSubscribe(); },
+ [&]() { invokeSetAndGetValues(); },
+ [&]() { invokeObd2SensorStore(); },
+ [&]() { invokeVmsUtils(); },
+ [&]() { invokeVehiclePropStore(); },
+ [&]() { invokeWatchDogClient(); },
+ });
+ invokeVehicleHalManagerFuzzer();
+ }
}
void VehicleHalManagerFuzzer::invokeDebug() {
- hidl_string debugOption = mFuzzedDataProvider->PickValueInArray(
- {"--help", "--list", "--get", "--set", "", "invalid"});
hidl_handle fd = {};
native_handle_t* rawHandle = native_handle_create(/*numFds=*/1, /*numInts=*/0);
fd.setTo(native_handle_clone(rawHandle), /*shouldOwn=*/true);
+ int32_t size = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxFileSize);
+ hidl_vec<hidl_string> options(size);
- mManager->debug(fd, {});
- mManager->debug(fd, {debugOption});
+ for (int32_t idx = 0; idx < size; ++idx) {
+ if (idx == 0 && mFuzzedDataProvider->ConsumeBool()) {
+ options[idx] = mFuzzedDataProvider->PickValueInArray(
+ {"--help", "--list", "--get", "--set", "", "invalid"});
+ } else if (idx == 2 && mFuzzedDataProvider->ConsumeBool()) {
+ options[idx] =
+ mFuzzedDataProvider->PickValueInArray({"-i", "-i64", "-f", "-s", "-b", "-a"});
+ } else if (mFuzzedDataProvider->ConsumeBool()) {
+ options[idx] = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxSize);
+ } else {
+ options[idx] = std::to_string(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+ }
+ }
+
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ mManager->debug(fd, {});
+ } else {
+ mManager->debug(fd, options);
+ }
native_handle_delete(rawHandle);
}
@@ -175,178 +209,245 @@
int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
hidl_vec<int32_t> properties = {vehicleProp1, vehicleProp2};
+ auto invokePropConfigsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() {
+ mManager->getPropConfigs(
+ properties, []([[maybe_unused]] StatusCode status,
+ [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+ },
+ [&]() {
+ mManager->getPropConfigs(
+ {mFuzzedDataProvider->ConsumeIntegral<int32_t>()},
+ []([[maybe_unused]] StatusCode status,
+ [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+ },
+ [&]() {
+ mManager->getAllPropConfigs(
+ []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+ },
- mManager->getPropConfigs(properties,
- []([[maybe_unused]] StatusCode status,
- [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
- mManager->getPropConfigs({toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength])},
- []([[maybe_unused]] StatusCode status,
- [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
- mManager->getAllPropConfigs(
- []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+ });
+ invokePropConfigsAPI();
}
void VehicleHalManagerFuzzer::invokeSubscribe() {
- int32_t vehicleProp1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
int32_t vehicleProp3 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
- const auto prop1 = toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength]);
sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+ VehiclePropertyType type =
+ static_cast<VehiclePropertyType>(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
- hidl_vec<SubscribeOptions> options = {
- SubscribeOptions{.propId = prop1, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
+ auto invokeSubscribeAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() {
+ size_t size =
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+ hidl_vec<SubscribeOptions> options(size);
+ for (size_t idx = 0; idx < size; ++idx) {
+ options[idx] = {SubscribeOptions{
+ .propId = mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ .flags = static_cast<SubscribeFlags>(
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>())}};
+ }
+ mManager->subscribe(cb, options);
+ },
+ [&]() {
+ auto unsubscribedValue = mObjectPool->obtain(type);
+ if (!unsubscribedValue) {
+ return;
+ }
+ unsubscribedValue->prop = vehicleProp2;
+ unsubscribedValue->value.int32Values[0] = INT32_MAX;
+ mHal->sendPropEvent(std::move(unsubscribedValue));
+ cb->waitForExpectedEvents(mFuzzedDataProvider->ConsumeIntegral<size_t>());
+ },
+ [&]() {
+ const auto prop1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ mManager->unsubscribe(cb, prop1);
+ },
+ [&]() {
+ mHal->sendHalError(StatusCode::TRY_AGAIN, vehicleProp3,
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>() /*areaId=*/);
+ },
- mManager->subscribe(cb, options);
-
- auto unsubscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
- unsubscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
-
- mHal->sendPropEvent(std::move(unsubscribedValue));
- cb->getReceivedEvents();
- cb->waitForExpectedEvents(0);
-
- auto subscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
- subscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
- subscribedValue->value.int32Values[0] = INT32_MAX;
-
- cb->reset();
- VehiclePropValue actualValue(*subscribedValue.get());
- mHal->sendPropEvent(std::move(subscribedValue));
- cb->waitForExpectedEvents(1);
- mManager->unsubscribe(cb, prop1);
-
- sp<MockedVehicleCallback> cb2 = new MockedVehicleCallback();
-
- hidl_vec<SubscribeOptions> options2 = {
- SubscribeOptions{
- .propId = toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
- .flags = SubscribeFlags::EVENTS_FROM_CAR},
- };
-
- mManager->subscribe(cb2, options2);
-
- mHal->sendHalError(StatusCode::TRY_AGAIN,
- toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
- /*areaId=*/0);
+ });
+ invokeSubscribeAPI();
}
void VehicleHalManagerFuzzer::invokeSetAndGetValues() {
- uint32_t vehicleProp1 =
- mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
- uint32_t vehicleProp2 =
- mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
- uint32_t vehicleProp3 =
- mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-
- invokeGet(kCustomComplexProperty, 0);
- invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
- invokeGet(toInt(kVehicleProp[vehicleProp1]), 0);
-
- auto expectedValue = mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
- mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>());
- mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
- mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool());
- expectedValue->prop = toInt(kVehicleProp[vehicleProp2]);
- expectedValue->areaId = 0;
-
- mManager->set(*expectedValue.get());
- invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
- expectedValue->prop = toInt(kVehicleProp[vehicleProp3]);
- mManager->set(*expectedValue.get());
- expectedValue->prop = toInt(VehicleProperty::INVALID);
- mManager->set(*expectedValue.get());
+ auto invokeSetAndGetAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() {
+ invokeGet(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+ },
+ [&]() { mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>()); },
+ [&]() { mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>()); },
+ [&]() { mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool()); },
+ [&]() {
+ int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ auto expectedValue =
+ mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+ expectedValue->prop = vehicleProp2;
+ expectedValue->areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ mManager->set(*expectedValue.get());
+ },
+ });
+ invokeSetAndGetAPI();
}
void VehicleHalManagerFuzzer::invokeObd2SensorStore() {
- uint32_t diagnosticIntIndex =
- mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kIntSensorArrayLength - 1);
- int32_t diagnosticIntValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
- uint32_t diagnosticFloatIndex =
- mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kFloatSensorArrayLength - 1);
- float diagnosticFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+ size_t diagnosticInt = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+ size_t diagnosticFloat =
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
std::unique_ptr<Obd2SensorStore> sensorStore(
- new Obd2SensorStore(kIntSensorArrayLength, kFloatSensorArrayLength));
- if (sensorStore) {
- sensorStore->setIntegerSensor(kDiagnosticIntIndex[diagnosticIntIndex], diagnosticIntValue);
- sensorStore->setFloatSensor(kDiagnosticFloatIndex[diagnosticFloatIndex],
- diagnosticFloatValue);
- sensorStore->getIntegerSensors();
- sensorStore->getFloatSensors();
- sensorStore->getSensorsBitmask();
- static std::vector<std::string> sampleDtcs = {"P0070",
- "P0102"
- "P0123"};
- for (auto&& dtc : sampleDtcs) {
- auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
- sensorStore->fillPropValue(dtc, freezeFrame.get());
- freezeFrame->prop = static_cast<int>(VehicleProperty::OBD2_FREEZE_FRAME);
- }
+ new Obd2SensorStore(diagnosticInt, diagnosticFloat));
+
+ if (!sensorStore.get()) {
+ return;
}
+
+ auto invokeObd2SensorStoreAPI =
+ mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() {
+ int32_t diagnosticIntValue =
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ int32_t diagnosticIntIndex =
+ mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+ kMinSize,
+ toInt(DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX) +
+ diagnosticInt);
+ sensorStore->setIntegerSensor(
+ static_cast<DiagnosticIntegerSensorIndex>(diagnosticIntIndex),
+ diagnosticIntValue);
+ },
+ [&]() {
+ float diagnosticFloatValue =
+ mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+ int32_t diagnosticFloatIndex =
+ mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+ kMinSize,
+ toInt(DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX) +
+ diagnosticFloat);
+ sensorStore->setFloatSensor(
+ static_cast<DiagnosticFloatSensorIndex>(diagnosticFloatIndex),
+ diagnosticFloatValue);
+ },
+ [&]() { sensorStore->getIntegerSensors(); },
+ [&]() { sensorStore->getFloatSensors(); },
+ [&]() { sensorStore->getSensorsBitmask(); },
+ [&]() {
+ for (auto&& dtc : kSampleDtcs) {
+ VehiclePropertyType type = static_cast<VehiclePropertyType>(
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+ auto freezeFrame = createVehiclePropValue(
+ type, mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+ kMinSize, kMaxSize));
+ if (!freezeFrame.get()) {
+ return;
+ }
+ freezeFrame->prop = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ sensorStore->fillPropValue(dtc, freezeFrame.get());
+ }
+ },
+ });
+ invokeObd2SensorStoreAPI();
}
void VehicleHalManagerFuzzer::invokeVmsUtils() {
- bool availabilityMsgType = mFuzzedDataProvider->ConsumeBool();
- bool subscriptionMsgType = mFuzzedDataProvider->ConsumeBool();
+ std::unique_ptr<VehiclePropValue> message;
int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ VmsLayer layer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+ VmsOffers offers = {
+ intValue,
+ {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+ const VmsLayerAndPublisher layer_and_publisher(
+ VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>()),
+ intValue);
- VmsLayer layer(1, 0, 2);
- auto message = createSubscribeMessage(layer);
+ switch (mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxCaseMessage)) {
+ case 0: {
+ message = createSubscribeMessage(layer);
+ break;
+ }
+ case 1: {
+ message = createUnsubscribeMessage(layer);
+ break;
+ }
+ case 2: {
+ message = createSubscriptionsRequest();
+ break;
+ }
+ case 3: {
+ message = createOfferingMessage(offers);
+ break;
+ }
+ case 4: {
+ message = createAvailabilityRequest();
+ break;
+ }
+ case 5: {
+ std::string pub_bytes;
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ pub_bytes = "pub_id";
+ } else {
+ pub_bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+ }
+ message = createPublisherIdRequest(pub_bytes);
+ break;
+ }
+ case 6: {
+ std::string bytes = "placeholder";
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ bytes = "placeholder";
+ } else {
+ bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+ }
+ message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
+ break;
+ }
+ case 7: {
+ message = createBaseVmsMessage(
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize));
+ break;
+ }
+ case 8: {
+ message = createStartSessionMessage(intValue, intValue + 1);
+ break;
+ }
+ }
+
isValidVmsMessage(*message);
- message = createUnsubscribeMessage(layer);
-
- VmsOffers offers = {intValue, {VmsLayerOffering(VmsLayer(1, 0, 2))}};
- message = createOfferingMessage(offers);
- std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2), VmsLayer(3, 0, 3)};
- std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
- offers = {intValue, offering};
- message = createOfferingMessage(offers);
-
- message = createAvailabilityRequest();
- message = createSubscriptionsRequest();
-
- std::string bytes = "placeholder";
- const VmsLayerAndPublisher layer_and_publisher(VmsLayer(2, 0, 1), intValue);
- message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
- parseData(*message);
- createSubscribeToPublisherMessage(layer_and_publisher);
- createUnsubscribeToPublisherMessage(layer_and_publisher);
-
- std::string pub_bytes = "pub_id";
- message = createPublisherIdRequest(pub_bytes);
- message = createBaseVmsMessage(2);
message->value.int32Values =
- hidl_vec<int32_t>{toInt(VmsMessageType::PUBLISHER_ID_RESPONSE), intValue};
- parsePublisherIdResponse(*message);
+ hidl_vec<int32_t>{mFuzzedDataProvider->ConsumeIntegral<int32_t>(), intValue};
- message->value.int32Values =
- hidl_vec<int32_t>{toInt(kSubscriptionMessageType[subscriptionMsgType]), intValue};
- getSequenceNumberForSubscriptionsState(*message);
-
- message->value.int32Values = hidl_vec<int32_t>{toInt(kSubscriptionMessageType[0]), intValue};
- isSequenceNumberNewer(*message, intValue + 1);
- invokeGetSubscribedLayers(kSubscriptionMessageType[subscriptionMsgType]);
-
- message->value.int32Values =
- hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), 0};
- hasServiceNewlyStarted(*message);
- message = createStartSessionMessage(intValue, intValue + 1);
- parseMessageType(*message);
-
- message->value.int32Values =
- hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
- isAvailabilitySequenceNumberNewer(*message, intValue + 1);
-
- message->value.int32Values =
- hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
- getSequenceNumberForAvailabilityState(*message);
- message = createBaseVmsMessage(3);
- int new_service_id;
- message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 0, -1};
- parseStartSessionMessage(*message, -1, 0, &new_service_id);
+ auto invokeVmsUtilsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() { parseData(*message); },
+ [&]() { createSubscribeToPublisherMessage(layer_and_publisher); },
+ [&]() { createUnsubscribeToPublisherMessage(layer_and_publisher); },
+ [&]() { parsePublisherIdResponse(*message); },
+ [&]() { getSequenceNumberForSubscriptionsState(*message); },
+ [&]() { isSequenceNumberNewer(*message, intValue + 1); },
+ [&]() {
+ invokeGetSubscribedLayers(
+ (VmsMessageType)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+ },
+ [&]() { hasServiceNewlyStarted(*message); },
+ [&]() { parseMessageType(*message); },
+ [&]() { isAvailabilitySequenceNumberNewer(*message, intValue + 1); },
+ [&]() { getSequenceNumberForAvailabilityState(*message); },
+ [&]() {
+ int32_t new_service_id;
+ parseStartSessionMessage(*message, -1, 0, &new_service_id);
+ },
+ });
+ invokeVmsUtilsAPI();
}
void VehicleHalManagerFuzzer::invokeGet(int32_t property, int32_t areaId) {
@@ -367,27 +468,31 @@
mActualStatusCode = refStatus;
}
-void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType type) {
- VmsOffers offers = {123,
- {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
- VmsLayerOffering(VmsLayer(2, 0, 1))}};
- auto message = createBaseVmsMessage(16);
- message->value.int32Values = hidl_vec<int32_t>{toInt(type),
- 1234, // sequence number
- 2, // number of layers
- 1, // number of associated layers
- 1, // layer 1
- 0, 1,
- 4, // layer 2
- 1, 1,
- 2, // associated layer
- 0, 1,
- 2, // number of publisher IDs
- 111, // publisher IDs
- 123};
- isValidVmsMessage(*message);
- getSubscribedLayers(*message, offers);
- getAvailableLayers(*message);
+void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType /*type*/) {
+ int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ VmsOffers offers = {
+ intValue,
+ {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+ auto message = createBaseVmsMessage(
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxFileSize));
+ std::vector<int32_t> v;
+ size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+ for (size_t i = 0; i < size; i++) {
+ v.push_back(mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxSize));
+ }
+
+ message->value.int32Values = hidl_vec<int32_t>(v);
+ if (!isValidVmsMessage(*message)) {
+ return;
+ }
+
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ getSubscribedLayers(*message, offers);
+ } else {
+ getAvailableLayers(*message);
+ }
}
void VehicleHalManagerFuzzer::invokeVehiclePropStore() {
@@ -398,33 +503,49 @@
.prop = vehicleProp,
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = (mFuzzedDataProvider->ConsumeIntegral<int32_t>())}},
};
- store->registerProperty(config);
VehiclePropValue propValue{};
propValue.prop = vehicleProp;
- propValue.areaId = 0;
- store->writeValue(propValue, shouldWriteStatus);
- store->readAllValues();
- store->getAllConfigs();
- store->getConfigOrNull(vehicleProp);
- store->readValuesForProperty(vehicleProp);
- store->readValueOrNull(propValue);
- store->readValueOrNull(propValue.prop, propValue.areaId, 0);
- store->removeValuesForProperty(vehicleProp);
- store->removeValue(propValue);
- store->getConfigOrDie(vehicleProp);
+ propValue.areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+
+ auto invokeVehiclePropStoreAPI =
+ mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+ [&]() { store->registerProperty(config); },
+ [&]() { store->writeValue(propValue, shouldWriteStatus); },
+ [&]() { store->readAllValues(); },
+ [&]() { store->getAllConfigs(); },
+ [&]() { store->getConfigOrNull(vehicleProp); },
+ [&]() { store->readValuesForProperty(vehicleProp); },
+ [&]() { store->readValueOrNull(propValue); },
+ [&]() {
+ store->readValueOrNull(propValue.prop, propValue.areaId,
+ mFuzzedDataProvider->ConsumeIntegralInRange<int64_t>(
+ kMinSize, kMaxFileSize));
+ },
+ [&]() { store->removeValuesForProperty(vehicleProp); },
+ [&]() { store->removeValue(propValue); },
+ [&]() {
+ if (store->getConfigOrNull(vehicleProp)) {
+ store->getConfigOrDie(vehicleProp);
+ }
+ },
+ });
+ invokeVehiclePropStoreAPI();
}
void VehicleHalManagerFuzzer::invokeWatchDogClient() {
- auto service = new VehicleHalManager(mHal.get());
sp<Looper> looper(Looper::prepare(/*opts=*/mFuzzedDataProvider->ConsumeBool()));
- if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, service);
+ if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, mManager.get());
watchdogClient->initialize()) {
- watchdogClient->checkIfAlive(-1, TimeoutLength::TIMEOUT_NORMAL);
+ if (mFuzzedDataProvider->ConsumeBool()) {
+ watchdogClient->checkIfAlive(
+ mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+ (TimeoutLength)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+ }
watchdogClient->prepareProcessTermination();
}
- delete service;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
index e9335d3..26ac11e 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
@@ -98,6 +98,13 @@
}
void process(const uint8_t* data, size_t size);
+ template <typename T>
+ void fillParameter(size_t size, std::vector<T>& data) {
+ for (size_t i = 0; i < size; ++i) {
+ data.push_back(mFuzzedDataProvider->ConsumeIntegral<T>());
+ }
+ }
+
private:
FuzzedDataProvider* mFuzzedDataProvider = nullptr;
VehiclePropValue mActualValue = VehiclePropValue{};
@@ -108,6 +115,7 @@
std::unique_ptr<VehicleHalManager> mManager;
void invokeDebug();
+ void initValue();
void invokePropConfigs();
void invokeSubscribe();
void invokeSetAndGetValues();
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index 06c9600..e5106f8 100644
--- a/automotive/vehicle/aidl/impl/grpc/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/Android.bp
@@ -22,9 +22,11 @@
"aprotoc",
"protoc-gen-grpc-cpp-plugin",
],
- cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
srcs: [
"proto/VehicleServer.proto",
+ ":libprotobuf-internal-protos",
+ ":VehicleHalProtoFiles",
],
out: [
"VehicleServer.pb.h",
@@ -39,9 +41,11 @@
"aprotoc",
"protoc-gen-grpc-cpp-plugin",
],
- cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
srcs: [
"proto/VehicleServer.proto",
+ ":libprotobuf-internal-protos",
+ ":VehicleHalProtoFiles",
],
out: [
"VehicleServer.pb.cc",
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 0bcafa3..c283148 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -439,6 +439,9 @@
}
void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
+ if (session_type_ != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return;
+ }
std::lock_guard<std::recursive_mutex> guard(mutex_);
low_latency_allowed_ = allowed;
// TODO(b/294498919): Remove this after there is API to update latency mode
@@ -588,15 +591,32 @@
<< " has NO session";
return std::vector<LatencyMode>();
}
- if (low_latency_allowed_) return latency_modes_;
- std::vector<LatencyMode> modes;
- for (LatencyMode mode : latency_modes_) {
- if (mode == LatencyMode::LOW_LATENCY)
- // ignore those low latency mode if Bluetooth stack doesn't allow
- continue;
- modes.push_back(mode);
+
+ std::vector<LatencyMode> supported_latency_modes;
+ if (session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ for (LatencyMode mode : latency_modes_) {
+ if (mode == LatencyMode::LOW_LATENCY) {
+ // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
+ continue;
+ }
+ supported_latency_modes.push_back(mode);
+ }
+ } else {
+ for (LatencyMode mode : latency_modes_) {
+ if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
+ // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
+ continue;
+ }
+ if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
+ mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+ // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC sessions
+ continue;
+ }
+ supported_latency_modes.push_back(mode);
+ }
}
- return modes;
+ return supported_latency_modes;
}
void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
index c962974..88e4b75 100644
--- a/camera/device/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -786,9 +786,8 @@
outputBuffer.bufferId = buffer.bufferId;
outputBuffer.status = BufferStatus::ERROR;
if (buffer.acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = buffer.acquireFence;
- outputBuffer.releaseFence = android::makeToAidl(handle);
+ outputBuffer.releaseFence.fds.resize(1);
+ outputBuffer.releaseFence.fds.at(0).set(buffer.acquireFence);
}
} else {
offlineBuffers.push_back(buffer);
@@ -1769,9 +1768,8 @@
result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
result.outputBuffers[i].status = BufferStatus::ERROR;
if (req->buffers[i].acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = req->buffers[i].acquireFence;
- result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ result.outputBuffers[i].releaseFence.fds.resize(1);
+ result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
}
}
@@ -1815,18 +1813,16 @@
if (req->buffers[i].fenceTimeout) {
result.outputBuffers[i].status = BufferStatus::ERROR;
if (req->buffers[i].acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = req->buffers[i].acquireFence;
- result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ result.outputBuffers[i].releaseFence.fds.resize(1);
+ result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
}
notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
} else {
result.outputBuffers[i].status = BufferStatus::OK;
// TODO: refactor
if (req->buffers[i].acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = req->buffers[i].acquireFence;
- result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ result.outputBuffers[i].releaseFence.fds.resize(1);
+ result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
}
}
}
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 712f28a..b3ca293 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -31,7 +31,6 @@
"kernel_config_q_4.14",
"kernel_config_q_4.19",
],
- core_hals: "only",
}
vintf_compatibility_matrix {
@@ -45,7 +44,6 @@
"kernel_config_r_4.19",
"kernel_config_r_5.4",
],
- core_hals: "only",
}
vintf_compatibility_matrix {
@@ -59,7 +57,6 @@
"kernel_config_s_5.4",
"kernel_config_s_5.10",
],
- core_hals: "only",
}
vintf_compatibility_matrix {
@@ -72,7 +69,6 @@
"kernel_config_t_5.10",
"kernel_config_t_5.15",
],
- core_hals: "only",
}
vintf_compatibility_matrix {
@@ -85,7 +81,6 @@
"kernel_config_u_5.15",
"kernel_config_u_6.1",
],
- core_hals: "only",
}
vintf_compatibility_matrix {
@@ -98,5 +93,4 @@
"kernel_config_v_5.15",
"kernel_config_v_6.1",
],
- core_hals: "only",
}
diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go
index 4f342b2..c72cbde 100644
--- a/compatibility_matrices/build/vintf_compatibility_matrix.go
+++ b/compatibility_matrices/build/vintf_compatibility_matrix.go
@@ -35,10 +35,10 @@
pctx = android.NewPackageContext("android/vintf")
assembleVintfRule = pctx.AndroidStaticRule("assemble_vintf", blueprint.RuleParams{
- Command: `${assembleVintfCmd} -i ${inputs} -o ${out} ${extraParams}`,
+ Command: `${assembleVintfCmd} -i ${inputs} -o ${out}`,
CommandDeps: []string{"${assembleVintfCmd}"},
Description: "assemble_vintf -i ${inputs}",
- }, "inputs", "extraParams")
+ }, "inputs")
xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{
Command: `$XmlLintCmd --quiet --schema $xsd $in > /dev/null && touch -a $out`,
@@ -64,13 +64,6 @@
// list of kernel_config modules to be combined to final output
Kernel_configs []string
-
- // Default is "default" for compatibility matrices on /vendor
- // and /odm, and "disallow" for compatibility matrices on /system,
- // /product, and /system_ext.
- // If value is "only", only android.* HALs are allowed. If value
- // is "disallow", none of android.* HALs are allowed.
- Core_hals *string
}
type vintfCompatibilityMatrixRule struct {
@@ -173,8 +166,7 @@
Implicits: inputPaths,
Output: g.genFile,
Args: map[string]string{
- "inputs": strings.Join(inputPaths.Strings(), ":"),
- "extraParams": strings.Join(g.getExtraParams(), " "),
+ "inputs": strings.Join(inputPaths.Strings(), ":"),
},
})
g.generateValidateBuildAction(ctx, g.genFile, schema.Path())
@@ -199,23 +191,3 @@
},
}
}
-
-// Return extra parameters to assemble_vintf.
-func (g *vintfCompatibilityMatrixRule) getExtraParams() []string {
- var extraParams []string
-
- coreHalsStrategy := proptools.StringDefault(
- g.properties.Core_hals,
- g.defaultCoreHalsStrategy(),
- )
- extraParams = append(extraParams, "--core-hals", proptools.ShellEscape(coreHalsStrategy))
- return extraParams
-}
-
-func (g *vintfCompatibilityMatrixRule) defaultCoreHalsStrategy() string {
- // TODO(b/290408770): default to "disallow" for FCMs
-
- // For Device (vendor, odm) compatibility matrix, default is
- // to not check anything.
- return "default"
-}
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index d79e492..de2e1d1 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -310,6 +310,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.security.secretkeeper</name>
+ <version>1</version>
+ <interface>
+ <name>ISecretkeeper</name>
+ <instance>nonsecure</instance>
+ </interface>
+ </hal>
<hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.security.keymint</name>
<version>1-3</version>
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index 3e460dd..e13ba1f 100644
--- a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -39,7 +39,7 @@
ParcelFileDescriptor getWaitableFd();
parcelable Allocation {
android.hardware.HardwareBuffer buffer;
- ParcelFileDescriptor fence;
+ @nullable ParcelFileDescriptor fence;
}
parcelable Description {
int width;
diff --git a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index 49c4ea4..1710242 100644
--- a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -35,7 +35,7 @@
*/
parcelable Allocation {
HardwareBuffer buffer;
- ParcelFileDescriptor fence;
+ @nullable ParcelFileDescriptor fence;
}
/**
diff --git a/renderscript/1.0/default/Android.bp b/renderscript/1.0/default/Android.bp
index c68e370..23fa252 100644
--- a/renderscript/1.0/default/Android.bp
+++ b/renderscript/1.0/default/Android.bp
@@ -27,6 +27,12 @@
"android.hardware.renderscript@1.0",
],
+ runtime_libs: [
+ "libRS_internal",
+ //TODO(b/313564579) Install libRSDriver as dependency of libRS_internal
+ "libRSDriver",
+ ],
+
product_variables: {
override_rs_driver: {
cflags: ["-DOVERRIDE_RS_DRIVER=%s"],
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
index 4c1b965..0bc39d6 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
@@ -28,19 +28,19 @@
? -70003 : int, ; Timestamp in milliseconds since some starting point (generally
; the most recent device boot) which all of the applications within
; the secure domain must agree upon
- ? -70004 : bstr .size 16, ; Nonce used in key exchange methods
+ ? -70004 : bstr .size 16, ; Nonce (a cryptographic random number of 16 bytes) used in key
+ ; exchange methods
? -70005 : PayloadType, ; Payload type, if needed to disambiguate, when processing an arc
? -70006 : int, ; Version of the payload structure (if applicable)
? -70007 : int, ; Sequence number (if needed to prevent replay attacks)
? -70008 : Direction ; Direction of the encryption key (i.e. whether it is used to
; encrypt incoming messages or outgoing messages)
? -70009 : bool, ; "authentication_completed" - this is used during authenticated
- ; key exchange indicate whether signature verification is done
- ? -70010 : bstr .size 32 ; "session_id" computed during key exchange protocol
+ ; key exchange to indicate whether signature verification is done
+ ? -70010 : bstr .size 32 ; "session_id" computed during the key exchange protocol
}
-; Permissions indicate what an arc can be used with. Permissions are added to an arc during the
-; `create()` primitive operation and are propagated during `mint` and `snap` primitive operations.
+; Permissions indicate what an arc can be used with.
Permission = &(
-4770552 : IdentityEncoded, ; "source_id" - in the operations performed by a source, the
; source adds its own identity to the permissions of an arc.
@@ -54,12 +54,10 @@
; biometrics.
)
-; Limitations indicate what restrictions are applied on the usage of an arc. Permissions are added
-; to an arc during the `create` primitive operation and are propagated during `snap` primitive
-; operation.
+; Limitations indicate what restrictions are applied on the usage of an arc.
Limitation = &(
- -4770554 : bstr, ; "challenge" - is added to an arc that transfers an auth key to a channel
- ; key, in order to ensure the freshness of the authentication.
+ -4770554 : bstr, ; "challenge" - is added to an arc that encrypts an auth key from a
+ ; channel key, in order to ensure the freshness of the authentication.
; A challenge is issued by a sink (e.g. Keymint TA, Biometric TAs).
)
@@ -83,7 +81,7 @@
; Any other payload formats should also be defined here
)
-SecretKey = &( ; One of the payload types of an Arc is a secret key
+SecretKey = &(
SymmetricKey,
ECPrivateKey, ; Private key of a key pair generated for key exchange
)
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
index 6ceb09c..a3fb959 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
@@ -41,8 +41,8 @@
interface IAuthGraphKeyExchange {
/**
* This method is invoked on P1 (source).
- * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (of 16 bytes) for
- * key exchange.
+ * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (a cryptographic random
+ * number of 16 bytes) for key exchange.
*
* @return SessionInitiationInfo including the `Key` containing the public key of the created
* key pair and an arc from the per-boot key to the private key, the nonce, the persistent
@@ -52,8 +52,8 @@
* `SessionInitiationInfo` serves two purposes:
* i. A mapping to correlate `create` and `finish` calls to P1 in a particular instance of the
* key exchange protocol.
- * ii.A way to minimize the in-memory storage (P1 can include the nonce in the protected headers
- * of the arc).
+ * ii.A way to minimize the in-memory storage of P1 allocated for key exchange (P1 can include
+ * the nonce in the protected headers of the arc).
* However, P1 should maintain some form of in-memory record to be able to verify that the input
* `Key` sent to `finish` is from an unfinished instance of a key exchange protocol, to prevent
* any replay attacks in `finish`.
@@ -66,9 +66,9 @@
* 0. If either `peerPubKey`, `peerId`, `peerNonce` is not in the expected format, return
* errors: INVALID_PEER_KE_KEY, INVALID_IDENTITY, INVALID_PEER_NONCE respectively.
* 1. Create an ephemeral EC key pair on NIST curve P-256.
- * 2. Create a nonce (of 16 bytes).
- * 3. Compute the diffie-hellman shared secret: Z.
- * 4. Compute a salt = bstr .cbor [
+ * 2. Create a nonce (a cryptographic random number of 16 bytes).
+ * 3. Compute the Diffie-Hellman shared secret: Z.
+ * 4. Compute a salt_input = bstr .cbor [
* source_version: int, ; from input `peerVersion`
* sink_pub_key: bstr .cbor PlainPubKey, ; from step #1
* source_pub_key: bstr .cbor PlainPubKey, ; from input `peerPubKey`
@@ -77,7 +77,8 @@
* sink_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
* source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
* ]
- * 5. Extract a cryptographic secret S from Z, using the salt from #4 above.
+ * 5. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+ * as the salt.
* 6. Derive two symmetric encryption keys of 256 bits with:
* i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt incoming
* messages
@@ -96,28 +97,29 @@
* part of the party's identity.
*
* @param peerPubKey - the public key of the key pair created by the peer (P1) for key exchange
+ * in `create`
*
* @param peerId - the persistent identity of the peer
*
- * @param peerNonce - nonce created by the peer
+ * @param peerNonce - nonce created by the peer in `create`
*
* @param peerVersion - an integer representing the latest protocol version (i.e. AIDL version)
* supported by the peer
*
- * @return KeInitResult including the `Key` containing the public key of the created key pair,
- * the nonce, the persistent identity, two shared key arcs from step #7, session id, signature
- * over the session id and the negotiated protocol version. The negotiated protocol version
- * should be less than or equal to the peer's version.
+ * @return KeInitResult including the `Key` containing the public key of the key pair created in
+ * step #1, the nonce from step #2, the persistent identity of P2, two shared key arcs
+ * from step #7, session id from step #10, signature over the session id from step #11 and the
+ * negotiated protocol version. The negotiated protocol version should be less than or equal to
+ * the `peerVersion`.
*
- * Note: The two shared key arcs in the return type: `KeInitResult` serves two purposes:
+ * Note: The two shared key arcs in the return type: `KeInitResult` serve two purposes:
* i. A mapping to correlate `init` and `authenticationComplete` calls to P2 in a particular
* instance of the key exchange protocol.
* ii.A way to minimize the in-memory storage of P2 allocated for key exchange.
* However, P2 should maintain some in-memory record to be able to verify that the input
- * `sharedkeys` sent to `authenticationComplete` and to any subsequent AuthGraph protocol
- * methods are valid shared keys agreed with the party identified by `peerId`, to prevent
- * any replay attacks in `authenticationComplete` and in any subsequent AuthGraph protocol
- * methods which use the shared keys to encrypt the secret messages.
+ * `sharedkeys` sent to `authenticationComplete` are from an unfinished instance of a key
+ * exchange protocol carried out with the party identified by `peerId`, to prevent any replay
+ * attacks in `authenticationComplete`.
*/
KeInitResult init(
in PubKey peerPubKey, in Identity peerId, in byte[] peerNonce, in int peerVersion);
@@ -133,8 +135,8 @@
* exchange protocol, return error: INVALID_KE_KEY. Similarly, if the public key or the
* arc containing the private key in `ownKey` is invalid, return INVALID_PUB_KEY_IN_KEY
* and INVALID_PRIV_KEY_ARC_IN_KEY respectively.
- * 1. Compute the diffie-hellman shared secret: Z.
- * 2. Compute a salt = bstr .cbor [
+ * 1. Compute the Diffie-Hellman shared secret: Z.
+ * 2. Compute a salt_input = bstr .cbor [
* source_version: int, ; the protocol version used in `create`
* sink_pub_key: bstr .cbor PlainPubKey, ; from input `peerPubKey`
* source_pub_key: bstr .cbor PlainPubKey, ; from the output of `create`
@@ -143,7 +145,8 @@
* sink_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
* source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
* ]
- * 3. Extract a cryptographic secret S from Z, using the salt from #2 above.
+ * 3. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+ * as the salt.
* 4. Derive two symmetric encryption keys of 256 bits with:
* i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt outgoing
* messages
@@ -164,25 +167,26 @@
* part of the party's identity.
*
* @param peerPubKey - the public key of the key pair created by the peer (P2) for key exchange
+ * in `init`
*
* @param peerId - the persistent identity of the peer
*
* @param peerSignature - the signature created by the peer over the session id computed by the
- * peer
+ * peer in `init`
*
- * @param peerNonce - nonce created by the peer
+ * @param peerNonce - nonce created by the peer in `init`
*
* @param peerVersion - an integer representing the protocol version (i.e. AIDL version)
* negotiated with the peer
*
- * @param ownKey - the key created by P1 (source) in `create()` for key exchange
+ * @param ownKey - the key created by P1 (source) in `create` for key exchange
*
- * @return SessionInfo including the two shared key arcs from step #9, session id and the
- * signature over the session id.
+ * @return SessionInfo including the two shared key arcs from step #9, session id from step #7
+ * and the signature over the session id from step #10.
*
- * Note: The two shared key arcs in the return type: `SessionInfo` serves two purposes:
+ * Note: The two shared key arcs in the return type: `SessionInfo` serve two purposes:
* i. A mapping to correlate the key exchange protocol taken place with a particular peer and
- * subsequent AuthGraph protocols execued with the same peer.
+ * subsequent AuthGraph protocols executed with the same peer.
* ii.A way to minimize the in-memory storage for shared keys.
* However, P1 should maintain some in-memory record to be able to verify that the shared key
* arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
@@ -196,21 +200,33 @@
* This method is invoked on P2 (sink).
* Perform the following steps:
* 0. If input `sharedKeys` is invalid (i.e. they cannot be decrypted with P2's per-boot key
- * or they are not in P2's in-memory records as valid shared keys agreed with the party
- * identified by `peerId`), return error: INVALID_SHARED_KEY_ARCS.
+ * or they are not in P2's in-memory records for unfinished instances of a key exchange
+ * protocol carried out with the party identified by the identity included in the
+ * `source_id` protected header of the shared key arcs),
+ * return error: INVALID_SHARED_KEY_ARCS.
* 1. Verify that both shared key arcs have the same session id and peer identity.
- * 2. Verify the peer's signature over the session id attached to the shared key arcs'
- * headers. If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
- * 3. Mark authentication_complete = true in the shared key arcs' headers
+ * 2. Verify the `peerSignature` over the session id included in the `session_id` protected
+ * header of the shared key arcs.
+ * If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
+ * 3. Mark authentication_complete = true in the shared key arcs' headers.
*
* @param peerSignature - the signature created by the peer over the session id computed by the
- * peer
+ * peer in `finish`
*
* @param sharedKeys - two shared key arcs created by P2 in `init`. P2 obtains from the arcs'
* protected headers, the session id and the peer's identity to verify the
* peer's signature over the session id.
*
* @return Arc[] - an array of two updated shared key arcs
+ *
+ * Note: The two returned shared key arcs serve two purposes:
+ * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
+ * subsequent AuthGraph protocols executed with the same peer.
+ * ii.A way to minimize the in-memory storage for shared keys.
+ * However, P2 should maintain some in-memory record to be able to verify that the shared key
+ * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
+ * party identified by the identity included in the `source_id` protected header of the shared
+ * key arcs, to prevent any replay attacks.
*/
Arc[2] authenticationComplete(in SessionIdSignature peerSignature, in Arc[2] sharedKeys);
}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
index ef49a1a..82b8c17 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
@@ -26,8 +26,8 @@
@RustDerive(Clone=true, Eq=true, PartialEq=true)
parcelable SessionInfo {
/**
- * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication)
- * from the party's per-boot key.
+ * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication).
+ * The encryption key is the party's per-boot key.
*/
Arc[2] sharedKeys;
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
index c630d91..8179ac2 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
@@ -27,20 +27,22 @@
@RustDerive(Clone=true, Eq=true, PartialEq=true)
parcelable SessionInitiationInfo {
/**
- * An ephemeral EC key created for the ECDH process.
+ * An ephemeral EC key created for the Elliptic-curve Diffie-Hellman (ECDH) process.
*/
Key key;
/**
- * The identity of the party who created the Diffie-Hellman key exchange key.
+ * The identity of the party who creates this `SessionInitiationInfo`.
*/
Identity identity;
/**
- * Nonce value specific to this session. The nonce serves three purposes:
+ * Nonce (a cryptographic random number of 16 bytes) specific to this session.
+ * The nonce serves three purposes:
* 1. freshness of key exchange
* 2. creating a session id (a publicly known value related to the exchanged keys)
- * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the shared DH key
+ * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the Diffie-Hellman
+ * shared secret
*/
byte[] nonce;
diff --git a/security/authgraph/aidl/vts/functional/Android.bp b/security/authgraph/aidl/vts/functional/Android.bp
index 0e3480f..28a70e2 100644
--- a/security/authgraph/aidl/vts/functional/Android.bp
+++ b/security/authgraph/aidl/vts/functional/Android.bp
@@ -50,6 +50,7 @@
rust_test {
name: "VtsAidlAuthGraphRoleTest",
srcs: ["role_test.rs"],
+ require_root: true,
test_suites: [
"general-tests",
"vts",
diff --git a/security/authgraph/aidl/vts/functional/lib.rs b/security/authgraph/aidl/vts/functional/lib.rs
index 7b9b2b9..da3fa1c 100644
--- a/security/authgraph/aidl/vts/functional/lib.rs
+++ b/security/authgraph/aidl/vts/functional/lib.rs
@@ -24,22 +24,19 @@
PlainPubKey::PlainPubKey, PubKey::PubKey, SessionIdSignature::SessionIdSignature,
};
use authgraph_boringssl as boring;
-use authgraph_core::keyexchange as ke;
-use authgraph_core::{arc, key, traits};
-use authgraph_nonsecure::StdClock;
+use authgraph_core::{error::Error as AgError, keyexchange as ke};
use coset::CborSerializable;
pub mod sink;
pub mod source;
-/// Return a collection of AuthGraph trait implementations suitable for testing.
-pub fn test_impls() -> traits::TraitImpl {
- // Note that the local implementation is using a clock with a potentially different epoch than
- // the implementation under test.
- boring::trait_impls(
+/// Return an AuthGraphParticipant suitable for testing.
+pub fn test_ag_participant() -> Result<ke::AuthGraphParticipant, AgError> {
+ Ok(ke::AuthGraphParticipant::new(
+ boring::crypto_trait_impls(),
Box::<boring::test_device::AgDevice>::default(),
- Some(Box::new(StdClock::default())),
- )
+ ke::MAX_OPENED_SESSIONS,
+ )?)
}
fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> PubKey {
@@ -56,14 +53,6 @@
}
}
-fn verification_key_from_identity(impls: &traits::TraitImpl, identity: &[u8]) -> key::EcVerifyKey {
- let identity = key::Identity::from_slice(identity).expect("invalid identity CBOR");
- impls
- .device
- .process_peer_cert_chain(&identity.cert_chain, &*impls.ecdsa)
- .expect("failed to extract signing key")
-}
-
fn vec_to_identity(data: &[u8]) -> Identity {
Identity {
identity: data.to_vec(),
@@ -75,26 +64,3 @@
signature: data.to_vec(),
}
}
-
-/// Decrypt a pair of AES-256 keys encrypted with the AuthGraph PBK.
-pub fn decipher_aes_keys(imp: &traits::TraitImpl, arc: &[Vec<u8>; 2]) -> [key::AesKey; 2] {
- [
- decipher_aes_key(imp, &arc[0]),
- decipher_aes_key(imp, &arc[1]),
- ]
-}
-
-/// Decrypt an AES-256 key encrypted with the AuthGraph PBK.
-pub fn decipher_aes_key(imp: &traits::TraitImpl, arc: &[u8]) -> key::AesKey {
- let pbk = imp.device.get_per_boot_key().expect("no PBK available");
- let arc::ArcContent {
- payload,
- protected_headers: _,
- unprotected_headers: _,
- } = arc::decipher_arc(&pbk, arc, &*imp.aes_gcm).expect("failed to decrypt arc");
- assert_eq!(payload.0.len(), 32);
- let mut key = key::AesKey([0; 32]);
- key.0.copy_from_slice(&payload.0);
- assert_ne!(key.0, [0; 32], "agreed AES-256 key should be non-zero");
- key
-}
diff --git a/security/authgraph/aidl/vts/functional/role_test.rs b/security/authgraph/aidl/vts/functional/role_test.rs
index e95361a..3075d8a 100644
--- a/security/authgraph/aidl/vts/functional/role_test.rs
+++ b/security/authgraph/aidl/vts/functional/role_test.rs
@@ -22,13 +22,18 @@
use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
IAuthGraphKeyExchange::IAuthGraphKeyExchange,
};
+use binder::StatusCode;
const AUTH_GRAPH_NONSECURE: &str =
"android.hardware.security.authgraph.IAuthGraphKeyExchange/nonsecure";
/// Retrieve the /nonsecure instance of AuthGraph, which supports both sink and source roles.
fn get_nonsecure() -> Option<binder::Strong<dyn IAuthGraphKeyExchange>> {
- binder::get_interface(AUTH_GRAPH_NONSECURE).ok()
+ match binder::get_interface(AUTH_GRAPH_NONSECURE) {
+ Ok(ag) => Some(ag),
+ Err(StatusCode::NAME_NOT_FOUND) => None,
+ Err(e) => panic!("failed to get AuthGraph/nonsecure: {e:?}"),
+ }
}
/// Macro to require availability of a /nonsecure instance of AuthGraph.
@@ -48,31 +53,31 @@
#[test]
fn test_nonsecure_source_mainline() {
- let mut impls = vts::test_impls();
- vts::source::test_mainline(&mut impls, require_nonsecure!());
+ let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+ vts::source::test_mainline(&mut sink, require_nonsecure!());
}
#[test]
fn test_nonsecure_source_corrupt_sig() {
- let mut impls = vts::test_impls();
- vts::source::test_corrupt_sig(&mut impls, require_nonsecure!());
+ let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+ vts::source::test_corrupt_sig(&mut sink, require_nonsecure!());
}
#[test]
fn test_nonsecure_source_corrupt_keys() {
- let mut impls = vts::test_impls();
- vts::source::test_corrupt_key(&mut impls, require_nonsecure!());
+ let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+ vts::source::test_corrupt_key(&mut sink, require_nonsecure!());
}
#[test]
fn test_nonsecure_sink_mainline() {
- let mut impls = vts::test_impls();
- vts::sink::test_mainline(&mut impls, require_nonsecure!());
+ let mut source = vts::test_ag_participant().expect("failed to create a local source");
+ vts::sink::test_mainline(&mut source, require_nonsecure!());
}
#[test]
fn test_nonsecure_sink_corrupt_sig() {
- let mut impls = vts::test_impls();
- vts::sink::test_corrupt_sig(&mut impls, require_nonsecure!());
+ let mut source = vts::test_ag_participant().expect("failed to create a local source");
+ vts::sink::test_corrupt_sig(&mut source, require_nonsecure!());
}
#[test]
fn test_nonsecure_sink_corrupt_keys() {
- let mut impls = vts::test_impls();
- vts::sink::test_corrupt_keys(&mut impls, require_nonsecure!());
+ let mut source = vts::test_ag_participant().expect("failed to create a local source");
+ vts::sink::test_corrupt_keys(&mut source, require_nonsecure!());
}
diff --git a/security/authgraph/aidl/vts/functional/sink.rs b/security/authgraph/aidl/vts/functional/sink.rs
index 5c81593..bb357b8 100644
--- a/security/authgraph/aidl/vts/functional/sink.rs
+++ b/security/authgraph/aidl/vts/functional/sink.rs
@@ -16,23 +16,28 @@
//! VTS tests for sinks
use super::*;
-use authgraph_core::traits;
+use authgraph_core::{key, keyexchange as ke};
/// Run AuthGraph tests against the provided sink, using a local test source implementation.
-pub fn test(impls: &mut traits::TraitImpl, sink: binder::Strong<dyn IAuthGraphKeyExchange>) {
- test_mainline(impls, sink.clone());
- test_corrupt_sig(impls, sink.clone());
- test_corrupt_keys(impls, sink);
+pub fn test(
+ local_source: &mut ke::AuthGraphParticipant,
+ sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+ test_mainline(local_source, sink.clone());
+ test_corrupt_sig(local_source, sink.clone());
+ test_corrupt_keys(local_source, sink);
}
/// Perform mainline AuthGraph key exchange with the provided sink and local implementation.
/// Return the agreed AES keys in plaintext.
pub fn test_mainline(
- impls: &mut traits::TraitImpl,
+ local_source: &mut ke::AuthGraphParticipant,
sink: binder::Strong<dyn IAuthGraphKeyExchange>,
) -> [key::AesKey; 2] {
// Step 1: create an ephemeral ECDH key at the (local) source.
- let source_init_info = ke::create(impls).expect("failed to create() with local impl");
+ let source_init_info = local_source
+ .create()
+ .expect("failed to create() with local impl");
// Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
let init_result = sink
@@ -50,40 +55,43 @@
assert!(!sink_info.sessionId.is_empty());
// The AuthGraph core library will verify the session ID signature, but do it here too.
- let sink_verification_key =
- verification_key_from_identity(&impls, &sink_init_info.identity.identity);
- ke::verify_signature_on_session_id(
- &sink_verification_key,
- &sink_info.sessionId,
- &sink_info.signature.signature,
- &*impls.ecdsa,
- )
- .expect("failed verification of signed session ID");
+ let sink_verification_key = local_source
+ .peer_verification_key_from_identity(&sink_init_info.identity.identity)
+ .expect("failed to get peer verification from identity");
+ local_source
+ .verify_signature_on_session_id(
+ &sink_verification_key,
+ &sink_info.sessionId,
+ &sink_info.signature.signature,
+ )
+ .expect("failed verification of signed session ID");
// Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
// can calculate the same pair of symmetric keys.
- let source_info = ke::finish(
- impls,
- &sink_pub_key.plainPubKey,
- &sink_init_info.identity.identity,
- &sink_info.signature.signature,
- &sink_init_info.nonce,
- sink_init_info.version,
- source_init_info.ke_key,
- )
- .expect("failed to finish() with local impl");
+ let source_info = local_source
+ .finish(
+ &sink_pub_key.plainPubKey,
+ &sink_init_info.identity.identity,
+ &sink_info.signature.signature,
+ &sink_init_info.nonce,
+ sink_init_info.version,
+ source_init_info.ke_key,
+ )
+ .expect("failed to finish() with local impl");
assert!(!source_info.session_id.is_empty());
// The AuthGraph core library will verify the session ID signature, but do it here too.
- let source_verification_key =
- verification_key_from_identity(&impls, &source_init_info.identity);
- ke::verify_signature_on_session_id(
- &source_verification_key,
- &source_info.session_id,
- &source_info.session_id_signature,
- &*impls.ecdsa,
- )
- .expect("failed verification of signed session ID");
+ let source_verification_key = key::Identity::from_slice(&source_init_info.identity)
+ .expect("invalid identity CBOR")
+ .cert_chain
+ .root_key;
+ local_source
+ .verify_signature_on_session_id(
+ &source_verification_key,
+ &source_info.session_id,
+ &source_info.session_id_signature,
+ )
+ .expect("failed verification of signed session ID");
// Both ends should agree on the session ID.
assert_eq!(source_info.session_id, sink_info.sessionId);
@@ -96,19 +104,28 @@
&sink_info.sharedKeys,
)
.expect("failed to authenticationComplete() with remote sink");
-
// Decrypt and return the session keys.
- decipher_aes_keys(&impls, &source_info.shared_keys)
+ let decrypted_shared_keys = local_source
+ .decipher_shared_keys_from_arcs(&source_info.shared_keys)
+ .expect("failed to decrypt shared key arcs")
+ .try_into();
+ let decrypted_shared_keys_array = match decrypted_shared_keys {
+ Ok(array) => array,
+ Err(_) => panic!("wrong number of decrypted shared key arcs"),
+ };
+ decrypted_shared_keys_array
}
/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
/// session ID signature.
pub fn test_corrupt_sig(
- impls: &mut traits::TraitImpl,
+ local_source: &mut ke::AuthGraphParticipant,
sink: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
// Step 1: create an ephemeral ECDH key at the (local) source.
- let source_init_info = ke::create(impls).expect("failed to create() with local impl");
+ let source_init_info = local_source
+ .create()
+ .expect("failed to create() with local impl");
// Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
let init_result = sink
@@ -127,16 +144,16 @@
// Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
// can calculate the same pair of symmetric keys.
- let source_info = ke::finish(
- impls,
- &sink_pub_key.plainPubKey,
- &sink_init_info.identity.identity,
- &sink_info.signature.signature,
- &sink_init_info.nonce,
- sink_init_info.version,
- source_init_info.ke_key,
- )
- .expect("failed to finish() with local impl");
+ let source_info = local_source
+ .finish(
+ &sink_pub_key.plainPubKey,
+ &sink_init_info.identity.identity,
+ &sink_info.signature.signature,
+ &sink_init_info.nonce,
+ sink_init_info.version,
+ source_init_info.ke_key,
+ )
+ .expect("failed to finish() with local impl");
assert!(!source_info.session_id.is_empty());
// Build a corrupted version of the (local) source's session ID signature.
@@ -158,11 +175,13 @@
/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
/// Arc for the sink's key.
pub fn test_corrupt_keys(
- impls: &mut traits::TraitImpl,
+ local_source: &mut ke::AuthGraphParticipant,
sink: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
// Step 1: create an ephemeral ECDH key at the (local) source.
- let source_init_info = ke::create(impls).expect("failed to create() with local impl");
+ let source_init_info = local_source
+ .create()
+ .expect("failed to create() with local impl");
// Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
let init_result = sink
@@ -181,16 +200,16 @@
// Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
// can calculate the same pair of symmetric keys.
- let source_info = ke::finish(
- impls,
- &sink_pub_key.plainPubKey,
- &sink_init_info.identity.identity,
- &sink_info.signature.signature,
- &sink_init_info.nonce,
- sink_init_info.version,
- source_init_info.ke_key,
- )
- .expect("failed to finish() with local impl");
+ let source_info = local_source
+ .finish(
+ &sink_pub_key.plainPubKey,
+ &sink_init_info.identity.identity,
+ &sink_info.signature.signature,
+ &sink_init_info.nonce,
+ sink_init_info.version,
+ source_init_info.ke_key,
+ )
+ .expect("failed to finish() with local impl");
assert!(!source_info.session_id.is_empty());
// Deliberately corrupt the sink's shared key Arcs before returning them
diff --git a/security/authgraph/aidl/vts/functional/source.rs b/security/authgraph/aidl/vts/functional/source.rs
index 9aaaaee..a1e76b3 100644
--- a/security/authgraph/aidl/vts/functional/source.rs
+++ b/security/authgraph/aidl/vts/functional/source.rs
@@ -16,19 +16,22 @@
//! VTS tests for sources
use super::*;
-use authgraph_core::traits;
+use authgraph_core::{key, keyexchange as ke};
/// Run AuthGraph tests against the provided source, using a local test sink implementation.
-pub fn test(impls: &mut traits::TraitImpl, source: binder::Strong<dyn IAuthGraphKeyExchange>) {
- test_mainline(impls, source.clone());
- test_corrupt_sig(impls, source.clone());
- test_corrupt_key(impls, source);
+pub fn test(
+ local_sink: &mut ke::AuthGraphParticipant,
+ source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+ test_mainline(local_sink, source.clone());
+ test_corrupt_sig(local_sink, source.clone());
+ test_corrupt_key(local_sink, source);
}
/// Perform mainline AuthGraph key exchange with the provided source.
/// Return the agreed AES keys in plaintext.
pub fn test_mainline(
- impls: &mut traits::TraitImpl,
+ local_sink: &mut ke::AuthGraphParticipant,
source: binder::Strong<dyn IAuthGraphKeyExchange>,
) -> [key::AesKey; 2] {
// Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -40,14 +43,14 @@
let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
// Step 2: pass the source's ECDH public key and other session info to the (local) sink.
- let init_result = ke::init(
- impls,
- &source_pub_key.plainPubKey,
- &source_init_info.identity.identity,
- &source_init_info.nonce,
- source_init_info.version,
- )
- .expect("failed to init() with local impl");
+ let init_result = local_sink
+ .init(
+ &source_pub_key.plainPubKey,
+ &source_init_info.identity.identity,
+ &source_init_info.nonce,
+ source_init_info.version,
+ )
+ .expect("failed to init() with local impl");
let sink_init_info = init_result.session_init_info;
let sink_pub_key = sink_init_info
.ke_key
@@ -58,14 +61,17 @@
assert!(!sink_info.session_id.is_empty());
// The AuthGraph core library will verify the session ID signature, but do it here too.
- let sink_verification_key = verification_key_from_identity(&impls, &sink_init_info.identity);
- ke::verify_signature_on_session_id(
- &sink_verification_key,
- &sink_info.session_id,
- &sink_info.session_id_signature,
- &*impls.ecdsa,
- )
- .expect("failed verification of signed session ID");
+ let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+ .expect("invalid identity CBOR")
+ .cert_chain
+ .root_key;
+ local_sink
+ .verify_signature_on_session_id(
+ &sink_verification_key,
+ &sink_info.session_id,
+ &sink_info.session_id_signature,
+ )
+ .expect("failed verification of signed session ID");
// Step 3: pass the sink's ECDH public key and other session info to the (remote) source, so it
// can calculate the same pair of symmetric keys.
@@ -86,36 +92,41 @@
assert!(!source_info.sessionId.is_empty());
// The AuthGraph core library will verify the session ID signature, but do it here too.
- let source_verification_key =
- verification_key_from_identity(&impls, &source_init_info.identity.identity);
- ke::verify_signature_on_session_id(
- &source_verification_key,
- &source_info.sessionId,
- &source_info.signature.signature,
- &*impls.ecdsa,
- )
- .expect("failed verification of signed session ID");
+ let source_verification_key = local_sink
+ .peer_verification_key_from_identity(&source_init_info.identity.identity)
+ .expect("failed to get peer verification from identity");
+ local_sink
+ .verify_signature_on_session_id(
+ &source_verification_key,
+ &source_info.sessionId,
+ &source_info.signature.signature,
+ )
+ .expect("failed verification of signed session ID");
// Both ends should agree on the session ID.
assert_eq!(source_info.sessionId, sink_info.session_id);
// Step 4: pass the (remote) source's session ID signature back to the sink, so it can check it
// and update the symmetric keys so they're marked as authentication complete.
- let sink_arcs = ke::authentication_complete(
- impls,
- &source_info.signature.signature,
- sink_info.shared_keys,
- )
- .expect("failed to authenticationComplete() with local sink");
-
+ let sink_arcs = local_sink
+ .authentication_complete(&source_info.signature.signature, sink_info.shared_keys)
+ .expect("failed to authenticationComplete() with local sink");
// Decrypt and return the session keys.
- decipher_aes_keys(&impls, &sink_arcs)
+ let decrypted_shared_keys = local_sink
+ .decipher_shared_keys_from_arcs(&sink_arcs)
+ .expect("failed to decrypt shared key arcs")
+ .try_into();
+ let decrypted_shared_keys_array = match decrypted_shared_keys {
+ Ok(array) => array,
+ Err(_) => panic!("wrong number of decrypted shared key arcs"),
+ };
+ decrypted_shared_keys_array
}
/// Perform mainline AuthGraph key exchange with the provided source, but provide an invalid session
/// ID signature.
pub fn test_corrupt_sig(
- impls: &mut traits::TraitImpl,
+ local_sink: &mut ke::AuthGraphParticipant,
source: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
// Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -127,14 +138,14 @@
let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
// Step 2: pass the source's ECDH public key and other session info to the (local) sink.
- let init_result = ke::init(
- impls,
- &source_pub_key.plainPubKey,
- &source_init_info.identity.identity,
- &source_init_info.nonce,
- source_init_info.version,
- )
- .expect("failed to init() with local impl");
+ let init_result = local_sink
+ .init(
+ &source_pub_key.plainPubKey,
+ &source_init_info.identity.identity,
+ &source_init_info.nonce,
+ source_init_info.version,
+ )
+ .expect("failed to init() with local impl");
let sink_init_info = init_result.session_init_info;
let sink_pub_key = sink_init_info
.ke_key
@@ -172,7 +183,7 @@
/// Perform mainline AuthGraph key exchange with the provided source, but give it back
/// a corrupted key.
pub fn test_corrupt_key(
- impls: &mut traits::TraitImpl,
+ local_sink: &mut ke::AuthGraphParticipant,
source: binder::Strong<dyn IAuthGraphKeyExchange>,
) {
// Step 1: create an ephemeral ECDH key at the (remote) source.
@@ -184,14 +195,14 @@
let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
// Step 2: pass the source's ECDH public key and other session info to the (local) sink.
- let init_result = ke::init(
- impls,
- &source_pub_key.plainPubKey,
- &source_init_info.identity.identity,
- &source_init_info.nonce,
- source_init_info.version,
- )
- .expect("failed to init() with local impl");
+ let init_result = local_sink
+ .init(
+ &source_pub_key.plainPubKey,
+ &source_init_info.identity.identity,
+ &source_init_info.nonce,
+ source_init_info.version,
+ )
+ .expect("failed to init() with local impl");
let sink_init_info = init_result.session_init_info;
let sink_pub_key = sink_init_info
.ke_key
@@ -202,14 +213,17 @@
assert!(!sink_info.session_id.is_empty());
// The AuthGraph core library will verify the session ID signature, but do it here too.
- let sink_verification_key = verification_key_from_identity(&impls, &sink_init_info.identity);
- ke::verify_signature_on_session_id(
- &sink_verification_key,
- &sink_info.session_id,
- &sink_info.session_id_signature,
- &*impls.ecdsa,
- )
- .expect("failed verification of signed session ID");
+ let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+ .expect("invalid identity CBOR")
+ .cert_chain
+ .root_key;
+ local_sink
+ .verify_signature_on_session_id(
+ &sink_verification_key,
+ &sink_info.session_id,
+ &sink_info.session_id_signature,
+ )
+ .expect("failed verification of signed session ID");
// Deliberately corrupt the source's encrypted key.
let mut corrupt_key = source_init_info.key.clone();
@@ -236,9 +250,13 @@
&corrupt_key,
);
- let err = result.expect_err("expect failure with corrupt signature");
- assert_eq!(
- err,
- binder::Status::new_service_specific_error(Error::INVALID_PRIV_KEY_ARC_IN_KEY.0, None)
+ let err = result.expect_err("expect failure with corrupt key");
+ assert!(
+ err == binder::Status::new_service_specific_error(Error::INVALID_KE_KEY.0, None)
+ || err
+ == binder::Status::new_service_specific_error(
+ Error::INVALID_PRIV_KEY_ARC_IN_KEY.0,
+ None
+ )
);
}
diff --git a/security/authgraph/default/Android.bp b/security/authgraph/default/Android.bp
index c481075..7894477 100644
--- a/security/authgraph/default/Android.bp
+++ b/security/authgraph/default/Android.bp
@@ -46,11 +46,11 @@
name: "android.hardware.security.authgraph-service.nonsecure",
relative_install_path: "hw",
vendor: true,
- init_rc: ["authgraph.rc"],
- vintf_fragments: ["authgraph.xml"],
+ installable: false, // install com.android.hardware.security.authgraph
defaults: [
"authgraph_use_latest_hal_aidl_rust",
],
+ prefer_rlib: true,
rustlibs: [
"libandroid_logger",
"libauthgraph_hal",
@@ -80,3 +80,34 @@
],
},
}
+
+prebuilt_etc {
+ name: "authgraph.xml",
+ src: "authgraph.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "authgraph.rc",
+ src: "authgraph.rc",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.security.authgraph",
+ manifest: "apex_manifest.json",
+ file_contexts: "apex_file_contexts",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ vendor: true,
+ updatable: false,
+
+ binaries: [
+ "android.hardware.security.authgraph-service.nonsecure",
+ ],
+ prebuilts: [
+ "authgraph.rc",
+ "authgraph.xml",
+ ],
+}
diff --git a/security/authgraph/default/apex_file_contexts b/security/authgraph/default/apex_file_contexts
new file mode 100644
index 0000000..9a54613
--- /dev/null
+++ b/security/authgraph/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.security\.authgraph-service\.nonsecure u:object_r:hal_authgraph_default_exec:s0
diff --git a/security/authgraph/default/apex_manifest.json b/security/authgraph/default/apex_manifest.json
new file mode 100644
index 0000000..0723846
--- /dev/null
+++ b/security/authgraph/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.security.authgraph",
+ "version": 1
+}
\ No newline at end of file
diff --git a/security/authgraph/default/authgraph.rc b/security/authgraph/default/authgraph.rc
index 0222994..2d07542 100644
--- a/security/authgraph/default/authgraph.rc
+++ b/security/authgraph/default/authgraph.rc
@@ -1,4 +1,4 @@
-service vendor.authgraph /vendor/bin/hw/android.hardware.security.authgraph-service.nonsecure
+service vendor.authgraph /apex/com.android.hardware.security.authgraph/bin/hw/android.hardware.security.authgraph-service.nonsecure
interface aidl android.hardware.security.authgraph.IAuthGraph/nonsecure
class hal
user nobody
diff --git a/security/authgraph/default/src/fuzzer.rs b/security/authgraph/default/src/fuzzer.rs
index 6a9cfdd..d401777 100644
--- a/security/authgraph/default/src/fuzzer.rs
+++ b/security/authgraph/default/src/fuzzer.rs
@@ -25,7 +25,7 @@
use std::sync::{Arc, Mutex};
fuzz_target!(|data: &[u8]| {
- let local_ta = LocalTa::new();
+ let local_ta = LocalTa::new().expect("Failed to create an AuthGraph local TA.");
let service = AuthGraphService::new_as_binder(Arc::new(Mutex::new(local_ta)));
fuzz_service(&mut service.as_binder(), data);
});
diff --git a/security/authgraph/default/src/lib.rs b/security/authgraph/default/src/lib.rs
index 4cd0cb7..14741aa 100644
--- a/security/authgraph/default/src/lib.rs
+++ b/security/authgraph/default/src/lib.rs
@@ -18,36 +18,11 @@
use authgraph_boringssl as boring;
use authgraph_core::{
- key::MillisecondsSinceEpoch,
+ error, keyexchange,
ta::{AuthGraphTa, Role},
- traits,
};
use authgraph_hal::channel::SerializedChannel;
use std::sync::{Arc, Mutex};
-use std::time::Instant;
-
-/// Monotonic clock with an epoch that starts at the point of construction.
-/// (This makes it unsuitable for use outside of testing, because the epoch
-/// will not match that of any other component.)
-pub struct StdClock(Instant);
-
-impl Default for StdClock {
- fn default() -> Self {
- Self(Instant::now())
- }
-}
-
-impl traits::MonotonicClock for StdClock {
- fn now(&self) -> MillisecondsSinceEpoch {
- let millis: i64 = self
- .0
- .elapsed()
- .as_millis()
- .try_into()
- .expect("failed to fit timestamp in i64");
- MillisecondsSinceEpoch(millis)
- }
-}
/// Implementation of the AuthGraph TA that runs locally in-process (and which is therefore
/// insecure).
@@ -57,16 +32,17 @@
impl LocalTa {
/// Create a new instance.
- pub fn new() -> Self {
- Self {
+ pub fn new() -> Result<Self, error::Error> {
+ Ok(Self {
ta: Arc::new(Mutex::new(AuthGraphTa::new(
- boring::trait_impls(
+ keyexchange::AuthGraphParticipant::new(
+ boring::crypto_trait_impls(),
Box::<boring::test_device::AgDevice>::default(),
- Some(Box::new(StdClock::default())),
- ),
+ keyexchange::MAX_OPENED_SESSIONS,
+ )?,
Role::Both,
))),
- }
+ })
}
}
diff --git a/security/authgraph/default/src/main.rs b/security/authgraph/default/src/main.rs
index 873eb4e..81f2dd6 100644
--- a/security/authgraph/default/src/main.rs
+++ b/security/authgraph/default/src/main.rs
@@ -65,7 +65,8 @@
binder::ProcessState::start_thread_pool();
// Register the service
- let local_ta = LocalTa::new();
+ let local_ta =
+ LocalTa::new().map_err(|e| format!("Failed to create the TA because: {e:?}"))?;
let service = service::AuthGraphService::new_as_binder(Arc::new(Mutex::new(local_ta)));
let service_name = format!("{}/{}", SERVICE_NAME, SERVICE_INSTANCE);
binder::add_service(&service_name, service.as_binder()).map_err(|e| {
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index aa7bf28..be29f59 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -974,8 +974,8 @@
* time in milliseconds. This value is used when generating attestation or self signed
* certificates. ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
* this tag is not provided to generateKey or importKey. For importWrappedKey, there is no way
- * to specify the value of this tag for the wrapped key, so a value of 0 must be used for
- * certificate generation.
+ * to specify the value of this tag for a wrapped asymmetric key, so a value of 0 is suggested
+ * for certificate generation.
*/
CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
@@ -983,8 +983,9 @@
* Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
* milliseconds. This value is used when generating attestation or self signed certificates.
* ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
- * importKey. For importWrappedKey, there is no way to specify the value of this tag for the
- * wrapped key, so a value of 253402300799000 is used for certificate generation.
+ * importKey. For importWrappedKey, there is no way to specify the value of this tag for a
+ * wrapped asymmetric key, so a value of 253402300799000 is suggested for certificate
+ * generation.
*/
CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 822770d..d3f6ae3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1792,6 +1792,12 @@
std::string empty_boot_key(32, '\0');
std::string verified_boot_key_str((const char*)verified_boot_key.data(),
verified_boot_key.size());
+ if (get_vsr_api_level() >= __ANDROID_API_V__) {
+ // The attestation should contain the SHA-256 hash of the verified boot
+ // key. However, this was not checked for earlier versions of the KeyMint
+ // HAL so only be strict for VSR-V and above.
+ EXPECT_LE(verified_boot_key.size(), 32);
+ }
EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
if (!strcmp(property_value, "green")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index a8f17dd..d4adab5 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -4123,13 +4123,13 @@
* when the EC_CURVE is not explicitly specified.
*/
TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
- if (AidlVersion() < 4) {
+ if (get_vsr_api_level() < __ANDROID_API_V__) {
/*
- * The KeyMint spec before V4 was not clear as to whether EC_CURVE was optional on import of
- * EC keys. However, this was not checked at the time so we can only be strict about
- * checking this for implementations of KeyMint version 4 and above.
+ * The KeyMint spec was previously not clear as to whether EC_CURVE was optional on import
+ * of EC keys. However, this was not checked at the time so we can only be strict about
+ * checking this for implementations at VSR-V or later.
*/
- GTEST_SKIP() << "Skipping EC_CURVE on import only strict since KeyMint v4";
+ GTEST_SKIP() << "Skipping EC_CURVE on import only strict >= VSR-V";
}
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index c9a156d..9f7322a 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -114,6 +114,12 @@
const auto& vbKey = rot->asArray()->get(pos++);
ASSERT_TRUE(vbKey);
ASSERT_TRUE(vbKey->asBstr());
+ if (get_vsr_api_level() >= __ANDROID_API_V__) {
+ // The attestation should contain the SHA-256 hash of the verified boot
+ // key. However, this not was checked for earlier versions of the KeyMint
+ // HAL so only be strict for VSR-V and above.
+ ASSERT_LE(vbKey->asBstr()->value().size(), 32);
+ }
const auto& deviceLocked = rot->asArray()->get(pos++);
ASSERT_TRUE(deviceLocked);
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 34f7ce4..6edbfc1 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -520,6 +520,15 @@
std::to_string(info.versionNumber) + ").";
}
}
+ // Bypasses the device info validation since the device info in AVF is currently
+ // empty. Check b/299256925 for more information.
+ //
+ // TODO(b/300911665): This check is temporary and will be replaced once the markers
+ // on the DICE chain become available. We need to determine if the CSR is from the
+ // RKP VM using the markers on the DICE chain.
+ if (info.uniqueId == "AVF Remote Provisioning 1") {
+ return std::move(parsed);
+ }
std::string error;
std::string tmp;
diff --git a/security/rkp/README.md b/security/rkp/README.md
index 15ea817..71f70cb 100644
--- a/security/rkp/README.md
+++ b/security/rkp/README.md
@@ -190,3 +190,30 @@
* [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
* [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
+### Support for Android Virtualization Framework
+
+The Android Virtualization Framwork (AVF) relies on RKP to provision keys for VMs. A
+privileged vm, the RKP VM, is reponsible for generating and managing the keys for client
+VMs that run virtualized workloads. See the following for more background information on the
+RKP VM:
+* [rkp-vm]: https://android.googlesource.com/platform/packages/modules/Virtualization/+/main/service_vm/README.md#rkp-vm-remote-key-provisioning-virtual-machine
+* [rkp-service]: https://source.android.com/docs/core/ota/modular-system/remote-key-provisioning#stack-architecture
+
+It is important to distinquish the RKP VM from other components, such as KeyMint. An
+[RKP VM marker](https://pigweed.googlesource.com/open-dice/+/HEAD/docs/android.md#configuration-descriptor)
+(key `-70006) is used for this purpose. The existence or absence of this marker is used to
+identify the type of component decribed by a given DICE chain.
+
+The following describes which certificate types may be request based on the RKP VM marker:
+1. "rkp-vm": If a DICE chain has zero or more certificates without the RKP VM
+ marker followed by one or more certificates with the marker, then that chain
+ describes an RKP VM. If there are further certificates without the RKP VM
+ marker, then the chain does not describe an RKP VM.
+
+ Implementations must include the first RPK VM marker as early as possible
+ after the point of divergence between TEE and non-TEE components in the DICE
+ chain, prior to loading the Android Bootloader (ABL).
+2. "widevine" or "keymint": If there are no certificates with the RKP VM
+ marker then it describes a TEE component.
+3. None: Any component described by a DICE chain that does not match the above
+ two categories.
\ No newline at end of file
diff --git a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
index 61404d4..3c43238 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
+++ b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
@@ -14,8 +14,9 @@
; be extended without requiring a version bump of the HAL. Custom certificate types may
; be used, but the provisioning server may reject the request for an unknown certificate
; type. The currently defined certificate types are:
-; - "widevine"
-; - "keymint"
+; * "widevine" -- Widevine content protection system
+; * "keymint" -- KeyMint HAL
+; * "rkp-vm" -- See "Support for Android Virtualization Framework" in the README.md file.
CertificateType = tstr
KeysToSign = [ * PublicKey ] ; Please see PublicKey.cddl for the PublicKey definition.
@@ -112,6 +113,7 @@
? -70003 : int / tstr, ; Component version
? -70004 : null, ; Resettable
? -70005 : uint, ; Security version
+ ? -70006 : null, ; RKP VM marker
}
; Each entry in the DICE chain is a DiceChainEntryPayload signed by the key from the previous
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 62463eb..a1de93e 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -55,6 +55,8 @@
constexpr uint8_t MIN_CHALLENGE_SIZE = 0;
constexpr uint8_t MAX_CHALLENGE_SIZE = 64;
+const string RKP_VM_INSTANCE_NAME =
+ "android.hardware.security.keymint.IRemotelyProvisionedComponent/avf";
#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name); \
@@ -181,7 +183,12 @@
provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
}
ASSERT_NE(provisionable_, nullptr);
- ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
+ auto status = provisionable_->getHardwareInfo(&rpcHardwareInfo);
+ if (GetParam() == RKP_VM_INSTANCE_NAME &&
+ status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "The RKP VM is not supported on this system.";
+ }
+ ASSERT_TRUE(status.isOk());
}
static vector<string> build_params() {
@@ -207,7 +214,11 @@
ASSERT_NE(rpc, nullptr);
RpcHardwareInfo hwInfo;
- ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
+ auto status = rpc->getHardwareInfo(&hwInfo);
+ if (hal == RKP_VM_INSTANCE_NAME && status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "The RKP VM is not supported on this system.";
+ }
+ ASSERT_TRUE(status.isOk());
if (hwInfo.versionNumber >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
ASSERT_TRUE(hwInfo.uniqueId);
diff --git a/security/secretkeeper/aidl/Android.bp b/security/secretkeeper/aidl/Android.bp
new file mode 100644
index 0000000..c77d299
--- /dev/null
+++ b/security/secretkeeper/aidl/Android.bp
@@ -0,0 +1,36 @@
+// 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+ name: "android.hardware.security.secretkeeper",
+ vendor_available: true,
+ srcs: ["android/hardware/security/secretkeeper/*.aidl"],
+ stability: "vintf",
+ backend: {
+ ndk: {
+ enabled: true,
+ },
+ rust: {
+ enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
+ },
+ },
+}
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..2eb33c5
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.secretkeeper;
+@VintfStability
+interface ISecretkeeper {
+ byte[] processSecretManagementRequest(in byte[] request);
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..af715a9
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package android.hardware.security.secretkeeper;
+
+@VintfStability
+/**
+ * Secretkeeper service definition.
+ *
+ * An ISecretkeeper instance provides secure storage of secrets on behalf of other components in
+ * Android, in particular for protected virtual machine instances. From the perspective of security
+ * privilege, Secretkeeper must be implemented in an environment with privilege higher than any of
+ * its clients. Since AVF based protected Virtual Machines are one set of its clients, the
+ * implementation of ISecretkeeper should live in a secure environment, such as:
+ * - A trusted execution environment such as ARM TrustZone.
+ * - A completely separate, purpose-built and certified secure CPU.
+ *
+ * TODO(b/291224769): Extend the HAL interface to include:
+ * 1. Session setup api: This is used to perform cryptographic operations that allow shared keys to
+ * be exchanged between session participants, typically (but not necessarily) a pVM instance and
+ * Secretkeeper. This session setup is based on public key cryptography.
+ * 2. Dice policy operation - These allow sealing of the secrets with a class of Dice chains.
+ * Typical operations are (securely) updating the dice policy sealing the Secrets above. These
+ * operations are core to AntiRollback protected secrets - ie, ensuring secrets of a pVM are only
+ * accessible to same or higher versions of the images.
+ * 3. Maintenance api: This is required for removing the Secretkeeper entries for obsolete pvMs.
+ */
+interface ISecretkeeper {
+ /**
+ * processSecretManagementRequest method is used for interacting with the Secret Management API
+ *
+ * Secret Management API: The clients can use this API to store (& get) 32 bytes of data.
+ * The API is a CBOR based protocol, which follows request/response model.
+ * See SecretManagement.cddl for the API spec.
+ *
+ * Further, the requests (from client) & responses (from service) must be encrypted into
+ * ProtectedRequestPacket & ProtectedResponsePacket using symmetric keys agreed between
+ * the client & service. This cryptographic protection is required because the messages are
+ * ferried via Android, which is allowed to be outside the TCB of clients (for example protected
+ * Virtual Machines). For this, service (& client) must implement a key exchange protocol, which
+ * is critical for establishing the secure channel.
+ *
+ * Secretkeeper database should guarantee the following properties:
+ * 1. Confidentiality: No entity (of security privilege lower than Secretkeeper) should
+ * be able to get a client's data in clear.
+ *
+ * 2. Integrity: The data is protected against malicious Android OS tampering with database.
+ * ie, if Android (userspace & kernel) tampers with the client's secret, the Secretkeeper
+ * service must be able to detect it & return error when clients requests for their secrets.
+ * Note: the integrity requirements also include Antirollback protection ie, reverting the
+ * database into an old state should be detected.
+ *
+ * 3. The data is persistent across device boot.
+ * Note: Denial of service is not in scope. A malicious Android may be able to delete data,
+ * but for ideal Android, the data should be persistent.
+ *
+ * @param CBOR-encoded ProtectedRequestPacket. See SecretManagement.cddl for its definition.
+ * @return CBOR-encoded ProtectedResponsePacket. See SecretManagement.cddl for its definition
+ */
+ byte[] processSecretManagementRequest(in byte[] request);
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
new file mode 100644
index 0000000..5631937
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -0,0 +1,116 @@
+; CDDL for the Secret Management API.
+; Also see processSecretManagementRequest method in ISecretkeeper.aidl
+
+; ProtectedRequestPacket is used by client for accessing Secret Management API
+; in Secretkeeper service. The service returns ProtectedResponsePacket of the corresponding type.
+
+; ProtectedRequestPacket & ProtectedResponsePacket are encrypted wrappers
+; on RequestPacket & ResponsePacket using symmetric keys agreed between Secretkeeper & clients
+; (these are referred to as KeySourceToSink & KeySinkToSource)
+;
+; The API operation required is encoded using 'Opcode', the arguments using 'Params'
+; and returned values as 'Result'.
+
+ProtectedRequestPacket =
+ ProtectedGetVersionRequest / ProtectedStoreSecretRequest / ProtectedGetSecretRequest
+ProtectedResponsePacket =
+ ProtectedGetVersionResponse / ProtectedStoreSecretResponse / ProtectedGetSecretResponse
+
+ProtectedGetVersionRequest = ProtectedRequestPacket<GetVersionRequestPacket>
+ProtectedGetVersionResponse = ProtectedResponsePacket<GetVersionResponsePacket>
+ProtectedStoreSecretRequest = ProtectedRequestPacket<StoreSecretRequestPacket>
+ProtectedStoreSecretResponse = ProtectedResponsePacket<StoreSecretResponsePacket>
+ProtectedGetSecretRequest = ProtectedRequestPacket<GetSecretRequestPacket>
+ProtectedGetSecretResponse = ProtectedResponsePacket<GetSecretResponsePacket>
+
+GetVersionRequestPacket = RequestPacket<GetVersionOpcode, GetVersionParams>
+GetVersionResponsePacket = ResponsePacket<GetVersionResult>
+StoreSecretRequestPacket = RequestPacket<StoreSecretOpcode, StoreSecretParams>
+StoreSecretResponsePacket = ResponsePacket<StoreSecretResult>
+GetSecretRequestPacket = RequestPacket<GetOpcode, GetSecretParams>
+GetSecretResponsePacket = ResponsePacket<GetSecretResult>
+
+RequestPacket<Opcode, Params> = [
+ Opcode,
+ Params
+]
+ResponsePacket<Result> = ResponsePacketError / ResponsePacketSuccess<Result>
+
+ResponsePacketSuccess = [
+ 0, ; Indicates successful Response
+ result : Result
+]
+ResponsePacketError = [
+ error_code: ErrorCode, ; Indicate the error
+ error_message: tstr ; Additional human-readable context
+]
+
+Opcode = &(
+ GetVersionOpcode: 1, ; Get version of the SecretManagement API
+ StoreSecretOpcode: 2, ; Store a secret
+ GetSecretOpcode: 3, ; Get the secret
+)
+
+GetVersionParams = ()
+GetVersionResult = (version : uint)
+
+StoreSecretParams = (
+ id : bstr .size 64 ; Unique identifier of the secret
+ secret : bstr .size 32,
+ sealing_policy : bstr .cbor DicePolicy, ; See DicePolicy.cddl for definition of DicePolicy
+)
+StoreSecretResult = ()
+
+GetSecretParams = (
+ id : bstr .size 64 ; Unique identifier of the secret
+ ; Use this to update the sealing policy associated with a secret during GetSecret operation.
+ updated_sealing_policy : bstr .cbor DicePolicy / nil,
+)
+GetSecretResult = (secret : bstr .size 32)
+
+
+ProtectedRequestPacket<Payload, Key> = CryptoPayload<Payload, KeySourceToSink>
+ProtectedResponsePacket<Payload, Key> = ProtectedResponseError
+ / ProtectedResponseSuccess<Payload>
+
+ProtectedResponseSuccess<Payload> = [
+ 0, ; Indicates successful crypto operations. Note: Payload
+ ; may contain Error from functional layer.
+ message: CryptoPayload<Payload, KeySinkToSource> ; message is the encrypted payload
+]
+
+ProtectedResponseError = [
+ error_code: CryptoErrorCode, ; Indicates the error. This is in cleartext & will be
+ ; visible to Android. These are errors from crypto
+ ; layer & indicates the request could not even be read
+ message: tstr ; Additional human-readable context
+]
+
+CryptoPayload<Payload, Key> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
+ protected: bstr .cbor {
+ 1 : 3, ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
+ 4 : bstr ; key identifier, uniquely identifies the session
+ ; TODO(b/291228560): Refer to the Key Exchange spec.
+ },
+ unprotected: {
+ 5 : bstr .size 12 ; IV
+ },
+ ciphertext : bstr ; AES-GCM-256(Key, bstr .cbor Payload)
+ ; AAD for the encryption is CBOR-serialized
+ ; Enc_structure (RFC 9052 s5.3) with empty external_aad.
+]
+
+; TODO(b/291224769): Create a more exhaustive set of CryptoErrorCode
+CryptoErrorCode = &(
+ CryptoErrorCode_SessionExpired: 1,
+)
+
+; TODO(b/291224769): Create a more exhaustive set of ErrorCodes
+ErrorCode = &(
+ ; Use this as if no other error code can be used.
+ ErrorCode_UnexpectedServerError: 1,
+ ; Indicate the Request was malformed & hence couldnt be served.
+ ErrorCode_RequestMalformed: 2,
+)
+
+; INCLUDE DicePolicy.cddl for: DicePolicy
\ No newline at end of file
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
new file mode 100644
index 0000000..6818298
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_test {
+ name: "VtsSecretkeeperTargetTest",
+ srcs: ["secretkeeper_test_client.rs"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ rustlibs: [
+ "libsecretkeeper_comm_nostd",
+ "android.hardware.security.secretkeeper-V1-rust",
+ "libbinder_rs",
+ "liblog_rust",
+ ],
+ require_root: true,
+}
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
new file mode 100644
index 0000000..28923f7
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.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.
+ */
+
+#[cfg(test)]
+use binder::StatusCode;
+use log::warn;
+use secretkeeper_comm::data_types::error::SecretkeeperError;
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::{
+ GetVersionRequest, GetVersionResponse,
+};
+use secretkeeper_comm::data_types::response::Response;
+use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
+
+const SECRETKEEPER_IDENTIFIER: &str =
+ "android.hardware.security.secretkeeper.ISecretkeeper/nonsecure";
+const CURRENT_VERSION: u64 = 1;
+
+fn get_connection() -> Option<binder::Strong<dyn ISecretkeeper>> {
+ match binder::get_interface(SECRETKEEPER_IDENTIFIER) {
+ Ok(sk) => Some(sk),
+ Err(StatusCode::NAME_NOT_FOUND) => None,
+ Err(e) => {
+ panic!(
+ "unexpected error while fetching connection to Secretkeeper {:?}",
+ e
+ );
+ }
+ }
+}
+
+// TODO(b/2797757): Add tests that match different HAL defined objects (like request/response)
+// with expected bytes.
+
+#[test]
+fn secret_management_get_version() {
+ let secretkeeper = match get_connection() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+ let request = GetVersionRequest {};
+ let request_packet = request.serialize_to_packet();
+ let request_bytes = request_packet.into_bytes().unwrap();
+
+ // TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
+ // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
+
+ let response_bytes = secretkeeper
+ .processSecretManagementRequest(&request_bytes)
+ .unwrap();
+
+ let response_packet = ResponsePacket::from_bytes(&response_bytes).unwrap();
+ assert_eq!(
+ response_packet.response_type().unwrap(),
+ ResponseType::Success
+ );
+ let get_version_response =
+ *GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
+ assert_eq!(get_version_response.version(), CURRENT_VERSION);
+}
+
+#[test]
+fn secret_management_malformed_request() {
+ let secretkeeper = match get_connection() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+ let request = GetVersionRequest {};
+ let request_packet = request.serialize_to_packet();
+ let mut request_bytes = request_packet.into_bytes().unwrap();
+
+ // Deform the request
+ request_bytes[0] = !request_bytes[0];
+
+ // TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
+ // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
+
+ let response_bytes = secretkeeper
+ .processSecretManagementRequest(&request_bytes)
+ .unwrap();
+
+ let response_packet = ResponsePacket::from_bytes(&response_bytes).unwrap();
+ assert_eq!(
+ response_packet.response_type().unwrap(),
+ ResponseType::Error
+ );
+ let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
+ assert_eq!(err, SecretkeeperError::RequestMalformed);
+}
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
new file mode 100644
index 0000000..1c39fa6
--- /dev/null
+++ b/security/secretkeeper/default/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+ name: "android.hardware.security.secretkeeper-service.nonsecure",
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["secretkeeper.rc"],
+ vintf_fragments: ["secretkeeper.xml"],
+ rustlibs: [
+ "android.hardware.security.secretkeeper-V1-rust",
+ "libandroid_logger",
+ "libbinder_rs",
+ "liblog_rust",
+ "libsecretkeeper_comm_nostd",
+ ],
+ srcs: [
+ "src/main.rs",
+ ],
+}
diff --git a/security/secretkeeper/default/secretkeeper.rc b/security/secretkeeper/default/secretkeeper.rc
new file mode 100644
index 0000000..f39f9b7
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.rc
@@ -0,0 +1,5 @@
+service vendor.secretkeeper /vendor/bin/hw/android.hardware.security.secretkeeper-service.nonsecure
+ interface aidl android.hardware.security.secretkeeper.ISecretkeeper/nonsecure
+ class hal
+ user nobody
+ group nobody
diff --git a/security/secretkeeper/default/secretkeeper.xml b/security/secretkeeper/default/secretkeeper.xml
new file mode 100644
index 0000000..40aebe0
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.xml
@@ -0,0 +1,28 @@
+<manifest version="1.0" type="device">
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+ <hal format="aidl">
+ <name>android.hardware.security.secretkeeper</name>
+ <version>1</version>
+ <interface>
+ <name>ISecretkeeper</name>
+ <instance>nonsecure</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/security/secretkeeper/default/src/main.rs b/security/secretkeeper/default/src/main.rs
new file mode 100644
index 0000000..2d367c5
--- /dev/null
+++ b/security/secretkeeper/default/src/main.rs
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+use binder::{BinderFeatures, Interface};
+use log::{error, info, Level};
+use secretkeeper_comm::data_types::error::SecretkeeperError;
+use secretkeeper_comm::data_types::packet::{RequestPacket, ResponsePacket};
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::{
+ GetVersionRequest, GetVersionResponse, Opcode,
+};
+use secretkeeper_comm::data_types::response::Response;
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
+ BnSecretkeeper, BpSecretkeeper, ISecretkeeper,
+};
+
+const CURRENT_VERSION: u64 = 1;
+
+#[derive(Debug, Default)]
+pub struct NonSecureSecretkeeper;
+
+impl Interface for NonSecureSecretkeeper {}
+
+impl ISecretkeeper for NonSecureSecretkeeper {
+ fn processSecretManagementRequest(&self, request: &[u8]) -> binder::Result<Vec<u8>> {
+ Ok(self.process_opaque_request(request))
+ }
+}
+
+impl NonSecureSecretkeeper {
+ // A set of requests to Secretkeeper are 'opaque' - encrypted bytes with inner structure
+ // described by CDDL. They need to be decrypted, deserialized and processed accordingly.
+ fn process_opaque_request(&self, request: &[u8]) -> Vec<u8> {
+ // TODO(b/291224769) The request will need to be decrypted & response need to be encrypted
+ // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
+ self.process_opaque_request_unhandled_error(request)
+ .unwrap_or_else(
+ // SecretkeeperError is also a valid 'Response', serialize to a response packet.
+ |sk_err| {
+ Response::serialize_to_packet(&sk_err)
+ .into_bytes()
+ .expect("Panicking due to serialization failing")
+ },
+ )
+ }
+
+ fn process_opaque_request_unhandled_error(
+ &self,
+ request: &[u8],
+ ) -> Result<Vec<u8>, SecretkeeperError> {
+ let request_packet = RequestPacket::from_bytes(request).map_err(|e| {
+ error!("Failed to get Request packet from bytes: {:?}", e);
+ SecretkeeperError::RequestMalformed
+ })?;
+ let response_packet = match request_packet
+ .opcode()
+ .map_err(|_| SecretkeeperError::RequestMalformed)?
+ {
+ Opcode::GetVersion => Self::process_get_version_request(request_packet)?,
+ _ => todo!("TODO(b/291224769): Unimplemented operations"),
+ };
+
+ response_packet
+ .into_bytes()
+ .map_err(|_| SecretkeeperError::UnexpectedServerError)
+ }
+
+ fn process_get_version_request(
+ request: RequestPacket,
+ ) -> Result<ResponsePacket, SecretkeeperError> {
+ // Deserialization really just verifies the structural integrity of the request such
+ // as args being empty.
+ let _request = GetVersionRequest::deserialize_from_packet(request)
+ .map_err(|_| SecretkeeperError::RequestMalformed)?;
+ let response = GetVersionResponse::new(CURRENT_VERSION);
+ Ok(response.serialize_to_packet())
+ }
+}
+
+fn main() {
+ // Initialize Android logging.
+ android_logger::init_once(
+ android_logger::Config::default()
+ .with_tag("NonSecureSecretkeeper")
+ .with_min_level(Level::Info)
+ .with_log_id(android_logger::LogId::System),
+ );
+ // Redirect panic messages to logcat.
+ std::panic::set_hook(Box::new(|panic_info| {
+ error!("{}", panic_info);
+ }));
+
+ let service = NonSecureSecretkeeper::default();
+ let service_binder = BnSecretkeeper::new_binder(service, BinderFeatures::default());
+ let service_name = format!(
+ "{}/nonsecure",
+ <BpSecretkeeper as ISecretkeeper>::get_descriptor()
+ );
+ binder::add_service(&service_name, service_binder.as_binder()).unwrap_or_else(|e| {
+ panic!(
+ "Failed to register service {} because of {:?}.",
+ service_name, e
+ );
+ });
+ info!("Registered Binder service, joining threadpool.");
+ binder::ProcessState::join_thread_pool();
+}
diff --git a/tests/multithread/1.0/default/Multithread.h b/tests/multithread/1.0/default/Multithread.h
index 0d4a007..7df75cc 100644
--- a/tests/multithread/1.0/default/Multithread.h
+++ b/tests/multithread/1.0/default/Multithread.h
@@ -33,7 +33,7 @@
std::condition_variable mCv;
std::mutex mCvMutex;
- static constexpr auto kTimeoutDuration = 100ms;
+ static constexpr auto kTimeoutDuration = 1000ms;
};
extern "C" IMultithread* HIDL_FETCH_IMultithread(const char* name);
diff --git a/threadnetwork/aidl/Android.bp b/threadnetwork/aidl/Android.bp
index c621b81..7e674e0 100644
--- a/threadnetwork/aidl/Android.bp
+++ b/threadnetwork/aidl/Android.bp
@@ -15,9 +15,6 @@
apex_available: [
"//apex_available:platform",
"com.android.tethering",
- // Keep the threadnetwork apex to make it buildable on udc-mainline-prod.
- // TODO: remove it after moving ot-daemon into tethering.
- "com.android.threadnetwork",
],
min_sdk_version: "30",
},