Merge "Add gralloc tests for locking without CPU usage" into main
diff --git a/Android.bp b/Android.bp
index fc6babe..baf3291 100644
--- a/Android.bp
+++ b/Android.bp
@@ -63,8 +63,8 @@
"libbase",
// All the following are dependencies of any HAL definition library.
"libcutils",
- "liblog",
"libhidlbase",
+ "liblog",
"libutils",
],
cflags: [
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index b67b9d2..4902497 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -44,7 +44,7 @@
"android/hardware/audio/common/SinkMetadata.aidl",
"android/hardware/audio/common/SourceMetadata.aidl",
],
- frozen: true,
+ frozen: false,
backend: {
cpp: {
enabled: true,
@@ -89,7 +89,7 @@
}
// Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_common = "android.hardware.audio.common-V3"
+latest_android_hardware_audio_common = "android.hardware.audio.common-V4"
// Modules that depend on android.hardware.audio.common directly can include
// the following cc_defaults to avoid explicitly managing dependency versions
@@ -198,11 +198,11 @@
// IMPORTANT: Update latest_android_hardware_audio_core every time you
// add the latest frozen version to versions_with_info
],
- frozen: true,
+ frozen: false,
}
// Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_core = "android.hardware.audio.core-V2"
+latest_android_hardware_audio_core = "android.hardware.audio.core-V3"
// Modules that depend on android.hardware.audio.core directly can include
// the following cc_defaults to avoid explicitly managing dependency versions
@@ -260,11 +260,11 @@
// IMPORTANT: Update latest_android_hardware_audio_core_sounddose every time you
// add the latest frozen version to versions_with_info
],
- frozen: true,
+ frozen: false,
}
// Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V2"
+latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V3"
// Modules that depend on android.hardware.audio.core.sounddose directly can include
// the following cc_defaults to avoid explicitly managing dependency versions
@@ -368,11 +368,11 @@
},
],
- frozen: true,
+ frozen: false,
}
-latest_android_hardware_audio_effect = "android.hardware.audio.effect-V2"
+latest_android_hardware_audio_effect = "android.hardware.audio.effect-V3"
cc_defaults {
name: "latest_android_hardware_audio_effect_ndk_shared",
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index b431340..6241f44 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -26,6 +26,7 @@
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
#include <aidl/android/media/audio/common/AudioInputFlags.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioMode.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <aidl/android/media/audio/common/PcmType.h>
@@ -191,4 +192,15 @@
return frameCountFromDurationUs(durationMs * 1000, sampleRateHz);
}
+constexpr bool hasMmapFlag(const ::aidl::android::media::audio::common::AudioIoFlags& flags) {
+ return (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::input &&
+ isBitPositionFlagSet(
+ flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::input>(),
+ ::aidl::android::media::audio::common::AudioInputFlags::MMAP_NOIRQ)) ||
+ (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::output &&
+ isBitPositionFlagSet(
+ flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::output>(),
+ ::aidl::android::media::audio::common::AudioOutputFlags::MMAP_NOIRQ));
+}
+
} // namespace aidl::android::hardware::audio::common
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 0d6151e..543efd1 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -36,6 +36,7 @@
using aidl::android::hardware::audio::common::frameCountFromDurationMs;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::isValidAudioMode;
using aidl::android::hardware::audio::common::SinkMetadata;
@@ -205,35 +206,31 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
const auto& flags = portConfigIt->flags.value();
- if ((flags.getTag() == AudioIoFlags::Tag::input &&
- !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
- AudioInputFlags::MMAP_NOIRQ)) ||
- (flags.getTag() == AudioIoFlags::Tag::output &&
- !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
- AudioOutputFlags::MMAP_NOIRQ))) {
- StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
- mVendorDebug.forceTransientBurst,
- mVendorDebug.forceSynchronousDrain};
- std::shared_ptr<ISoundDose> soundDose;
- if (!getSoundDose(&soundDose).isOk()) {
- LOG(ERROR) << __func__ << ": could not create sound dose instance";
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
- StreamContext temp(
- std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
- std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
- portConfigIt->format.value(), portConfigIt->channelMask.value(),
- portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
- portConfigIt->ext.get<AudioPortExt::mix>().handle,
- std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
- asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
- if (temp.isValid()) {
- *out_context = std::move(temp);
- } else {
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
+ StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
+ mVendorDebug.forceTransientBurst,
+ mVendorDebug.forceSynchronousDrain};
+ std::unique_ptr<StreamContext::DataMQ> dataMQ = nullptr;
+ std::shared_ptr<IStreamCallback> streamAsyncCallback = nullptr;
+ std::shared_ptr<ISoundDose> soundDose;
+ if (!getSoundDose(&soundDose).isOk()) {
+ LOG(ERROR) << __func__ << ": could not create sound dose instance";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ if (!hasMmapFlag(flags)) {
+ dataMQ = std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames);
+ streamAsyncCallback = asyncCallback;
+ }
+ StreamContext temp(
+ std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
+ std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
+ portConfigIt->format.value(), portConfigIt->channelMask.value(),
+ portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
+ portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(dataMQ),
+ streamAsyncCallback, outEventCallback, mSoundDose.getInstance(), params);
+ if (temp.isValid()) {
+ *out_context = std::move(temp);
} else {
- // TODO: Implement simulation of MMAP buffer allocation
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
return ndk::ScopedAStatus::ok();
}
@@ -373,6 +370,13 @@
return kLatencyMs;
}
+ndk::ScopedAStatus Module::createMmapBuffer(
+ const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
+ ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
+ LOG(ERROR) << __func__ << ": " << mType << ": is not implemented";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
std::vector<AudioRoute*> Module::getAudioRoutesForAudioPortImpl(int32_t portId) {
std::vector<AudioRoute*> result;
auto& routes = getConfig().routes;
@@ -866,6 +870,9 @@
RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
nullptr, nullptr, &context));
context.fillDescriptor(&_aidl_return->desc);
+ if (hasMmapFlag(context.getFlags())) {
+ RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
+ }
std::shared_ptr<StreamIn> stream;
RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
getMicrophoneInfos(), &stream));
@@ -913,6 +920,9 @@
isNonBlocking ? in_args.callback : nullptr,
in_args.eventCallback, &context));
context.fillDescriptor(&_aidl_return->desc);
+ if (hasMmapFlag(context.getFlags())) {
+ RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
+ }
std::shared_ptr<StreamOut> stream;
RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
in_args.offloadInfo, &stream));
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 31b0645..8f5e839 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -30,6 +30,7 @@
using aidl::android::hardware::audio::common::AudioOffloadMetadata;
using aidl::android::hardware::audio::common::getChannelCount;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
@@ -84,7 +85,7 @@
LOG(ERROR) << "frame size is invalid";
return false;
}
- if (mDataMQ && !mDataMQ->isValid()) {
+ if (!hasMmapFlag(mFlags) && mDataMQ && !mDataMQ->isValid()) {
LOG(ERROR) << "data FMQ is invalid";
return false;
}
@@ -116,17 +117,19 @@
std::string StreamWorkerCommonLogic::init() {
if (mContext->getCommandMQ() == nullptr) return "Command MQ is null";
if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null";
- StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
- if (dataMQ == nullptr) return "Data MQ is null";
- if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
- return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize());
- }
- mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize();
- mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
- if (mDataBuffer == nullptr) {
- return "Failed to allocate data buffer for element count " +
- std::to_string(dataMQ->getQuantumCount()) +
- ", size in bytes: " + std::to_string(mDataBufferSize);
+ if (!hasMmapFlag(mContext->getFlags())) {
+ StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
+ if (dataMQ == nullptr) return "Data MQ is null";
+ if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
+ return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize());
+ }
+ mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize();
+ mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
+ if (mDataBuffer == nullptr) {
+ return "Failed to allocate data buffer for element count " +
+ std::to_string(dataMQ->getQuantumCount()) +
+ ", size in bytes: " + std::to_string(mDataBufferSize);
+ }
}
if (::android::status_t status = mDriver->init(); status != STATUS_OK) {
return "Failed to initialize the driver: " + std::to_string(status);
@@ -136,16 +139,26 @@
void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
bool isConnected) const {
+ static const StreamDescriptor::Position kUnknownPosition = {
+ .frames = StreamDescriptor::Position::UNKNOWN,
+ .timeNs = StreamDescriptor::Position::UNKNOWN};
reply->status = STATUS_OK;
if (isConnected) {
reply->observable.frames = mContext->getFrameCount();
reply->observable.timeNs = ::android::uptimeNanos();
- if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
- return;
+ if (auto status = mDriver->refinePosition(&reply->observable); status != ::android::OK) {
+ reply->observable = kUnknownPosition;
+ }
+ } else {
+ reply->observable = reply->hardware = kUnknownPosition;
+ }
+ if (hasMmapFlag(mContext->getFlags())) {
+ if (auto status = mDriver->getMmapPositionAndLatency(&reply->hardware, &reply->latencyMs);
+ status != ::android::OK) {
+ reply->hardware = kUnknownPosition;
+ reply->latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
}
}
- reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
- reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
}
void StreamWorkerCommonLogic::populateReplyWrongState(
@@ -224,7 +237,9 @@
mState == StreamDescriptor::State::ACTIVE ||
mState == StreamDescriptor::State::PAUSED ||
mState == StreamDescriptor::State::DRAINING) {
- if (!read(fmqByteCount, &reply)) {
+ if (hasMmapFlag(mContext->getFlags())) {
+ populateReply(&reply, mIsConnected);
+ } else if (!read(fmqByteCount, &reply)) {
mState = StreamDescriptor::State::ERROR;
}
if (mState == StreamDescriptor::State::IDLE ||
@@ -470,7 +485,9 @@
if (mState != StreamDescriptor::State::ERROR &&
mState != StreamDescriptor::State::TRANSFERRING &&
mState != StreamDescriptor::State::TRANSFER_PAUSED) {
- if (!write(fmqByteCount, &reply)) {
+ if (hasMmapFlag(mContext->getFlags())) {
+ populateReply(&reply, mIsConnected);
+ } else if (!write(fmqByteCount, &reply)) {
mState = StreamDescriptor::State::ERROR;
}
std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
@@ -657,6 +674,7 @@
const std::shared_ptr<StreamCommonInterface>& delegate) {
mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
if (!mWorker->start()) {
+ LOG(ERROR) << __func__ << ": Worker start error: " << mWorker->getError();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
if (auto flags = getContext().getFlags();
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index 5278e4f..27f48e2 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -1,39 +1,39 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.audio.core</name>
- <version>2</version>
+ <version>3</version>
<fqname>IModule/default</fqname>
</hal>
<hal format="aidl">
<name>android.hardware.audio.core</name>
- <version>2</version>
+ <version>3</version>
<fqname>IModule/r_submix</fqname>
</hal>
<hal format="aidl">
<name>android.hardware.audio.core</name>
- <version>2</version>
+ <version>3</version>
<fqname>IModule/bluetooth</fqname>
</hal>
<hal format="aidl">
<name>android.hardware.audio.core</name>
- <version>2</version>
+ <version>3</version>
<fqname>IConfig/default</fqname>
</hal>
<!-- Uncomment when these modules present in the configuration
<hal format="aidl">
<name>android.hardware.audio.core</name>
- <version>1</version>
+ <version>3</version>
<fqname>IModule/stub</fqname>
</hal>
<hal format="aidl">
<name>android.hardware.audio.core</name>
- <version>1</version>
+ <version>3</version>
<fqname>IModule/usb</fqname>
</hal>
-->
<hal format="aidl">
<name>android.hardware.audio.effect</name>
- <version>2</version>
+ <version>3</version>
<fqname>IFactory/default</fqname>
</hal>
</manifest>
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index a326217..00eeb4e 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -205,6 +205,9 @@
virtual std::unique_ptr<Configuration> initializeConfig();
virtual int32_t getNominalLatencyMs(
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
+ virtual ndk::ScopedAStatus createMmapBuffer(
+ const ::aidl::android::hardware::audio::core::StreamContext& context,
+ ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
// Utility and helper functions accessible to subclasses.
static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 21e63f9..6b45866 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -177,6 +177,11 @@
virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
return ::android::OK;
}
+ // Implement 'getMmapPositionAndLatency' is necessary if driver can support mmap stream.
+ virtual ::android::status_t getMmapPositionAndLatency(StreamDescriptor::Position* /*position*/,
+ int32_t* /*latency*/) {
+ return ::android::OK;
+ }
virtual void shutdown() = 0; // This function is only called once.
};
@@ -241,6 +246,7 @@
virtual bool start() = 0;
virtual pid_t getTid() = 0;
virtual void stop() = 0;
+ virtual std::string getError() = 0;
};
template <class WorkerLogic>
@@ -260,6 +266,7 @@
}
pid_t getTid() override { return WorkerImpl::getTid(); }
void stop() override { return WorkerImpl::stop(); }
+ std::string getError() override { return WorkerImpl::getError(); }
};
class StreamInWorkerLogic : public StreamWorkerCommonLogic {
diff --git a/audio/aidl/sounddose/Android.bp b/audio/aidl/sounddose/Android.bp
index de3ed64..8b2d74b 100644
--- a/audio/aidl/sounddose/Android.bp
+++ b/audio/aidl/sounddose/Android.bp
@@ -56,11 +56,11 @@
// IMPORTANT: Update latest_android_hardware_audio_sounddose every time you
// add the latest frozen version to versions_with_info
],
- frozen: true,
+ frozen: false,
}
// Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V2"
+latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V3"
// Modules that depend on android.hardware.audio.sounddose directly can include
// the following cc_defaults to avoid explicitly managing dependency versions
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index d576c7c..bbc4caf 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -56,6 +56,7 @@
using namespace android;
using aidl::android::hardware::audio::common::AudioOffloadMetadata;
using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isAnyBitPositionFlagSet;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::isTelephonyDeviceType;
@@ -637,19 +638,39 @@
mCommandMQ(new CommandMQ(descriptor.command)),
mReplyMQ(new ReplyMQ(descriptor.reply)),
mBufferSizeFrames(descriptor.bufferSizeFrames),
- mDataMQ(maybeCreateDataMQ(descriptor)) {}
+ mDataMQ(maybeCreateDataMQ(descriptor)),
+ mIsMmapped(isMmapped(descriptor)),
+ mSharedMemoryFd(maybeGetMmapFd(descriptor)) {
+ if (isMmapped()) {
+ mSharedMemory = (int8_t*)mmap(nullptr, getBufferSizeBytes(), PROT_READ | PROT_WRITE,
+ MAP_SHARED, mSharedMemoryFd, 0);
+ if (mSharedMemory == MAP_FAILED) {
+ PLOG(ERROR) << __func__ << ": mmap() failed.";
+ mSharedMemory = nullptr;
+ }
+ }
+ }
+ ~StreamContext() {
+ if (mSharedMemory != nullptr) {
+ munmap(mSharedMemory, getBufferSizeBytes());
+ }
+ }
void checkIsValid() const {
EXPECT_NE(0UL, mFrameSizeBytes);
ASSERT_NE(nullptr, mCommandMQ);
EXPECT_TRUE(mCommandMQ->isValid());
ASSERT_NE(nullptr, mReplyMQ);
EXPECT_TRUE(mReplyMQ->isValid());
- if (mDataMQ != nullptr) {
- EXPECT_TRUE(mDataMQ->isValid());
- EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
- mFrameSizeBytes * mBufferSizeFrames)
- << "Data MQ actual buffer size is "
- "less than the buffer size as specified by the descriptor";
+ if (isMmapped()) {
+ ASSERT_NE(nullptr, mSharedMemory);
+ } else {
+ if (mDataMQ != nullptr) {
+ EXPECT_TRUE(mDataMQ->isValid());
+ EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
+ mFrameSizeBytes * mBufferSizeFrames)
+ << "Data MQ actual buffer size is "
+ "less than the buffer size as specified by the descriptor";
+ }
}
}
size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
@@ -658,6 +679,8 @@
DataMQ* getDataMQ() const { return mDataMQ.get(); }
size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+ bool isMmapped() const { return mIsMmapped; }
+ int8_t* getMmapMemory() const { return mSharedMemory; }
private:
static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
@@ -667,12 +690,26 @@
}
return nullptr;
}
+ static bool isMmapped(const StreamDescriptor& descriptor) {
+ using Tag = StreamDescriptor::AudioBuffer::Tag;
+ return descriptor.audio.getTag() == Tag::mmap;
+ }
+ static int32_t maybeGetMmapFd(const StreamDescriptor& descriptor) {
+ using Tag = StreamDescriptor::AudioBuffer::Tag;
+ if (descriptor.audio.getTag() == Tag::mmap) {
+ return descriptor.audio.get<Tag::mmap>().sharedMemory.fd.get();
+ }
+ return -1;
+ }
const size_t mFrameSizeBytes;
std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<ReplyMQ> mReplyMQ;
const size_t mBufferSizeFrames;
std::unique_ptr<DataMQ> mDataMQ;
+ const bool mIsMmapped;
+ const int32_t mSharedMemoryFd;
+ int8_t* mSharedMemory = nullptr;
};
struct StreamEventReceiver {
@@ -868,12 +905,15 @@
mDataMQ(context.getDataMQ()),
mData(context.getBufferSizeBytes()),
mDriver(driver),
- mEventReceiver(eventReceiver) {}
+ mEventReceiver(eventReceiver),
+ mIsMmapped(context.isMmapped()),
+ mSharedMemory(context.getMmapMemory()) {}
StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
StreamLogicDriver* getDriver() const { return mDriver; }
StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
+ bool isMmapped() const { return mIsMmapped; }
std::string init() override {
LOG(DEBUG) << __func__;
@@ -914,6 +954,22 @@
LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
return false;
}
+ bool readDataFromMmap(size_t readCount) {
+ if (mSharedMemory != nullptr) {
+ std::memcpy(mData.data(), mSharedMemory, readCount);
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from mmap failed";
+ return false;
+ }
+ bool writeDataToMmap() {
+ if (mSharedMemory != nullptr) {
+ std::memcpy(mSharedMemory, mData.data(), mData.size());
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to mmap failed";
+ return false;
+ }
private:
StreamContext::CommandMQ* mCommandMQ;
@@ -923,6 +979,8 @@
StreamLogicDriver* const mDriver;
StreamEventReceiver* const mEventReceiver;
int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
+ const bool mIsMmapped;
+ int8_t* mSharedMemory = nullptr;
};
class StreamReaderLogic : public StreamCommonLogic {
@@ -970,7 +1028,8 @@
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
}
- if (static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
+ if (!isMmapped() &&
+ static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
LOG(ERROR) << __func__
<< ": the byte count in the reply is not the same as the amount of "
<< "data available in the MQ: " << reply.fmqByteCount
@@ -991,8 +1050,10 @@
return Status::ABORT;
}
const bool acceptedReply = getDriver()->processValidReply(reply);
- if (const size_t readCount = getDataMQ()->availableToRead(); readCount > 0) {
- if (readDataFromMQ(readCount)) {
+ if (const size_t readCount =
+ !isMmapped() ? getDataMQ()->availableToRead() : reply.fmqByteCount;
+ readCount > 0) {
+ if (isMmapped() ? readDataFromMmap(readCount) : readDataFromMQ(readCount)) {
goto checkAcceptedReply;
}
LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
@@ -1028,8 +1089,10 @@
LOG(ERROR) << __func__ << ": no next command";
return Status::ABORT;
}
- if (actualSize != 0 && !writeDataToMQ()) {
- return Status::ABORT;
+ if (actualSize != 0) {
+ if (isMmapped() ? !writeDataToMmap() : !writeDataToMQ()) {
+ return Status::ABORT;
+ }
}
LOG(DEBUG) << "Writing command: " << command.toString();
if (!getCommandMQ()->writeBlocking(&command, 1)) {
@@ -1058,7 +1121,7 @@
return Status::ABORT;
}
// It is OK for the implementation to leave data in the MQ when the stream is paused.
- if (reply.state != StreamDescriptor::State::PAUSED &&
+ if (!isMmapped() && reply.state != StreamDescriptor::State::PAUSED &&
getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
<< "available to write " << getDataMQ()->availableToWrite()
@@ -2904,15 +2967,24 @@
class StreamLogicDefaultDriver : public StreamLogicDriver {
public:
- StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes)
- : mCommands(commands), mFrameSizeBytes(frameSizeBytes) {
+ StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes,
+ bool isMmap)
+ : mCommands(commands), mFrameSizeBytes(frameSizeBytes), mIsMmap(isMmap) {
mCommands->rewind();
}
- // The three methods below is intended to be called after the worker
+ // The five methods below is intended to be called after the worker
// thread has joined, thus no extra synchronization is needed.
bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
- bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
+ bool hasObservableRetrogradePosition() const { return mRetrogradeObservablePosition; }
+ bool hasHardwarePositionIncrease() const {
+ // For non-MMap, always return true to pass the validation.
+ return mIsMmap ? mHardwarePositionIncrease : true;
+ }
+ bool hasHardwareRetrogradePosition() const {
+ // For non-MMap, always return false to pass the validation.
+ return mIsMmap ? mRetrogradeHardwarePosition : false;
+ }
std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
bool done() override { return mCommands->done(); }
@@ -2940,14 +3012,24 @@
bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
bool processValidReply(const StreamDescriptor::Reply& reply) override {
if (reply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
- if (mPreviousFrames.has_value()) {
- if (reply.observable.frames > mPreviousFrames.value()) {
+ if (mPreviousObservableFrames.has_value()) {
+ if (reply.observable.frames > mPreviousObservableFrames.value()) {
mObservablePositionIncrease = true;
- } else if (reply.observable.frames < mPreviousFrames.value()) {
+ } else if (reply.observable.frames < mPreviousObservableFrames.value()) {
mRetrogradeObservablePosition = true;
}
}
- mPreviousFrames = reply.observable.frames;
+ mPreviousObservableFrames = reply.observable.frames;
+ }
+ if (mIsMmap) {
+ if (mPreviousHardwareFrames.has_value()) {
+ if (reply.hardware.frames > mPreviousHardwareFrames.value()) {
+ mHardwarePositionIncrease = true;
+ } else if (reply.hardware.frames < mPreviousHardwareFrames.value()) {
+ mRetrogradeHardwarePosition = true;
+ }
+ }
+ mPreviousHardwareFrames = reply.hardware.frames;
}
auto expected = mCommands->getExpectedStates();
@@ -2974,10 +3056,14 @@
protected:
std::shared_ptr<StateSequence> mCommands;
const size_t mFrameSizeBytes;
+ const bool mIsMmap;
std::optional<StreamDescriptor::State> mPreviousState;
- std::optional<int64_t> mPreviousFrames;
+ std::optional<int64_t> mPreviousObservableFrames;
bool mObservablePositionIncrease = false;
bool mRetrogradeObservablePosition = false;
+ std::optional<int64_t> mPreviousHardwareFrames;
+ bool mHardwarePositionIncrease = false;
+ bool mRetrogradeHardwarePosition = false;
std::string mUnexpectedTransition;
};
@@ -2988,8 +3074,8 @@
static bool skipStreamIoTestForMixPortConfig(const AudioPortConfig& portConfig) {
return (portConfig.flags.value().getTag() == AudioIoFlags::input &&
isAnyBitPositionFlagSet(portConfig.flags.value().template get<AudioIoFlags::input>(),
- {AudioInputFlags::MMAP_NOIRQ, AudioInputFlags::VOIP_TX,
- AudioInputFlags::HW_HOTWORD, AudioInputFlags::HOTWORD_TAP})) ||
+ {AudioInputFlags::VOIP_TX, AudioInputFlags::HW_HOTWORD,
+ AudioInputFlags::HOTWORD_TAP})) ||
(portConfig.flags.value().getTag() == AudioIoFlags::output &&
isAnyBitPositionFlagSet(
portConfig.flags.value().template get<AudioIoFlags::output>(),
@@ -3029,8 +3115,8 @@
void StartWorkerToSendBurstCommands() {
const StreamContext* context = mStream->getStreamContext();
- mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(makeBurstCommands(mIsSync),
- context->getFrameSizeBytes());
+ mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(
+ makeBurstCommands(mIsSync), context->getFrameSizeBytes(), context->isMmapped());
mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
*context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
@@ -3047,10 +3133,13 @@
EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
EXPECT_EQ("", mWorkerDriver->getUnexpectedStateTransition());
if (validatePosition) {
- if (IOTraits<Stream>::is_input) {
+ if (IOTraits<Stream>::is_input &&
+ !mStream->getStreamContext()->isMmapped() /*TODO(b/274456992) remove*/) {
EXPECT_TRUE(mWorkerDriver->hasObservablePositionIncrease());
+ EXPECT_TRUE(mWorkerDriver->hasHardwarePositionIncrease());
}
- EXPECT_FALSE(mWorkerDriver->hasRetrogradeObservablePosition());
+ EXPECT_FALSE(mWorkerDriver->hasObservableRetrogradePosition());
+ EXPECT_FALSE(mWorkerDriver->hasHardwareRetrogradePosition());
}
mWorker.reset();
mWorkerDriver.reset();
@@ -3984,7 +4073,7 @@
}
}
- bool ValidateObservablePosition(const AudioDevice& device) {
+ bool ValidatePosition(const AudioDevice& device) {
return !isTelephonyDeviceType(device.type.type);
}
@@ -3998,7 +4087,8 @@
if (skipStreamIoTestForDevice(stream.getDevice())) return;
ASSERT_EQ("", stream.skipTestReason());
StreamLogicDefaultDriver driver(commandsAndStates,
- stream.getStreamContext()->getFrameSizeBytes());
+ stream.getStreamContext()->getFrameSizeBytes(),
+ stream.getStreamContext()->isMmapped());
typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
stream.getStreamEventReceiver());
@@ -4008,11 +4098,14 @@
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(stream.getDevice())) {
- if (validatePositionIncrease) {
+ if (ValidatePosition(stream.getDevice())) {
+ if (validatePositionIncrease &&
+ !stream.getStreamContext()->isMmapped() /*TODO(b/274456992) remove*/) {
EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_TRUE(driver.hasHardwarePositionIncrease());
}
- EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ EXPECT_FALSE(driver.hasObservableRetrogradePosition());
+ EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
}
}
@@ -4028,7 +4121,8 @@
ASSERT_EQ("", stream.skipTestReason());
ASSERT_NO_FATAL_FAILURE(stream.TeardownPatchSetUpStream(module.get()));
StreamLogicDefaultDriver driver(commandsAndStates,
- stream.getStreamContext()->getFrameSizeBytes());
+ stream.getStreamContext()->getFrameSizeBytes(),
+ stream.getStreamContext()->isMmapped());
typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
stream.getStreamEventReceiver());
ASSERT_NO_FATAL_FAILURE(stream.ReconnectPatch(module.get()));
@@ -4039,11 +4133,14 @@
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(stream.getDevice())) {
- if (validatePositionIncrease) {
+ if (ValidatePosition(stream.getDevice())) {
+ if (validatePositionIncrease &&
+ !stream.getStreamContext()->isMmapped() /*TODO(b/274456992) remove*/) {
EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_TRUE(driver.hasHardwarePositionIncrease());
}
- EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ EXPECT_FALSE(driver.hasObservableRetrogradePosition());
+ EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
}
}
};
diff --git a/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
index c92e852..4170b4c 100644
--- a/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
+++ b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
@@ -33,6 +33,6 @@
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="{MODULE}" />
- <option name="native-test-timeout" value="10m" />
+ <option name="native-test-timeout" value="30m" />
</test>
</configuration>
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index 5fe27f6..e31aae6 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "VtsHalEnvironmentalReverbTest"
#include <android-base/logging.h>
#include <audio_utils/power.h>
+#include <audio_utils/primitives.h>
#include <system/audio.h>
#include <numeric>
@@ -49,6 +50,8 @@
static const TagVectorPair kDiffusionParam = {EnvironmentalReverb::diffusionPm,
{200, 400, 600, 800, 1000}};
+static const TagVectorPair kDensityParam = {EnvironmentalReverb::densityPm,
+ {0, 200, 400, 600, 800, 1000}};
static const std::vector<TagValuePair> kParamsMinimumValue = {
{EnvironmentalReverb::roomLevelMb, kMinRoomLevel},
@@ -350,8 +353,14 @@
mInput.resize(kBufferSize);
generateSineWaveInput(mInput);
}
- void SetUp() override { SetUpReverb(); }
- void TearDown() override { TearDownReverb(); }
+ void SetUp() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ SetUpReverb();
+ }
+ void TearDown() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ TearDownReverb();
+ }
void assertEnergyIncreasingWithParameter(bool bypass) {
createEnvParam(EnvironmentalReverb::bypass, bypass);
@@ -415,12 +424,16 @@
std::tie(mTag, mValue) = std::get<TAG_VALUE_PAIR>(GetParam());
}
void SetUp() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
SetUpReverb();
createEnvParam(EnvironmentalReverb::roomLevelMb, kMinRoomLevel);
ASSERT_NO_FATAL_FAILURE(
setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::roomLevelMb));
}
- void TearDown() override { TearDownReverb(); }
+ void TearDown() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ TearDownReverb();
+ }
EnvironmentalReverb::Tag mTag;
int mValue;
@@ -466,8 +479,14 @@
mInput.resize(kBufferSize);
generateSineWaveInput(mInput);
}
- void SetUp() override { SetUpReverb(); }
- void TearDown() override { TearDownReverb(); }
+ void SetUp() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ SetUpReverb();
+ }
+ void TearDown() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ TearDownReverb();
+ }
float getMean(std::vector<float>& buffer) {
return std::accumulate(buffer.begin(), buffer.end(), 0.0) / buffer.size();
@@ -475,9 +494,7 @@
float getVariance(std::vector<float>& buffer) {
if (isAuxiliary()) {
- for (size_t i = 0; i < buffer.size(); i++) {
- buffer[i] += mInput[i];
- }
+ accumulate_float(buffer.data(), mInput.data(), buffer.size());
}
float mean = getMean(buffer);
float squaredDeltas =
@@ -524,6 +541,78 @@
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDiffusionTest);
+enum ParamDensityTest { DESCRIPTOR, TAG_DENSITY_VALUE, PARAM_DENSITY_VALUE, IS_INPUT_MUTE };
+
+class EnvironmentalReverbDensityTest
+ : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ EnvironmentalReverb::Tag, int, bool>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbDensityTest() : EnvironmentalReverbHelper(std::get<DESCRIPTOR>(GetParam())) {
+ mTag = std::get<TAG_DENSITY_VALUE>(GetParam());
+ mParamValues = std::get<PARAM_DENSITY_VALUE>(GetParam());
+ mIsInputMute = (std::get<IS_INPUT_MUTE>(GetParam()));
+ mInput.resize(kBufferSize);
+ if (mIsInputMute) {
+ std::fill(mInput.begin(), mInput.end(), 0);
+ } else {
+ generateSineWaveInput(mInput);
+ }
+ }
+ void SetUp() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ SetUpReverb();
+ }
+ void TearDown() override {
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ TearDownReverb();
+ }
+
+ EnvironmentalReverb::Tag mTag;
+ int mParamValues;
+ std::vector<float> mInput;
+ bool mIsInputMute;
+};
+
+TEST_P(EnvironmentalReverbDensityTest, DensityOutput) {
+ float inputRmse =
+ audio_utils_compute_energy_mono(mInput.data(), AUDIO_FORMAT_PCM_FLOAT, mInput.size());
+
+ std::vector<float> output(kBufferSize);
+ setParameterAndProcess(mInput, output, mParamValues, mTag);
+
+ if (isAuxiliary() && !mIsInputMute) {
+ accumulate_float(output.data(), mInput.data(), output.size());
+ }
+
+ float outputRmse =
+ audio_utils_compute_energy_mono(output.data(), AUDIO_FORMAT_PCM_FLOAT, output.size());
+ if (inputRmse != 0) {
+ EXPECT_GT(outputRmse, 0);
+ } else {
+ EXPECT_EQ(outputRmse, inputRmse);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
+ ::testing::Combine(
+ testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, getEffectTypeUuidEnvReverb())),
+ testing::Values(kDensityParam.first), testing::ValuesIn(kDensityParam.second),
+ testing::Bool()),
+ [](const testing::TestParamInfo<EnvironmentalReverbDensityTest::ParamType>& info) {
+ auto descriptor = std::get<DESCRIPTOR>(info.param).second;
+ auto tag = std::get<TAG_DENSITY_VALUE>(info.param);
+ auto value = std::get<PARAM_DENSITY_VALUE>(info.param);
+ std::string isInputMute = std::to_string(std::get<IS_INPUT_MUTE>(info.param));
+ std::string name = getPrefix(descriptor) + "_Tag_" + toString(tag) + "_Value_" +
+ std::to_string(value) + "_isInputMute_" + isInputMute;
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDensityTest);
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
diff --git a/automotive/audiocontrol/aidl/Android.bp b/automotive/audiocontrol/aidl/Android.bp
index 0eb17fe..edb29c9 100644
--- a/automotive/audiocontrol/aidl/Android.bp
+++ b/automotive/audiocontrol/aidl/Android.bp
@@ -62,12 +62,12 @@
},
],
- frozen: true,
+ frozen: false,
}
// Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_automotive_audiocontrol = "android.hardware.automotive.audiocontrol-V4"
+latest_android_hardware_automotive_audiocontrol = "android.hardware.automotive.audiocontrol-V5"
cc_defaults {
name: "latest_android_hardware_automotive_audiocontrol_cpp_static",
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
index dfb15c6..5b2f82f 100644
--- a/automotive/evs/aidl/Android.bp
+++ b/automotive/evs/aidl/Android.bp
@@ -44,6 +44,9 @@
ndk: {
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ },
},
versions_with_info: [
{
diff --git a/automotive/evs/aidl/rust_impl/Android.bp b/automotive/evs/aidl/rust_impl/Android.bp
new file mode 100644
index 0000000..ac8b90f
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+rust_binary {
+ name: "android.hardware.automotive.evs-aidl-rust-service",
+ relative_install_path: "hw",
+ vendor: true,
+ srcs: ["src/*.rs"],
+ crate_root: "src/main.rs",
+ vintf_fragments: ["manifest_evs-rust-service.xml"],
+ init_rc: ["evs-rust-service.rc"],
+ rustlibs: [
+ "android.hardware.automotive.evs-V2-rust",
+ "libbinder_rs",
+ "liblog_rust",
+ ],
+}
diff --git a/automotive/evs/aidl/rust_impl/README.md b/automotive/evs/aidl/rust_impl/README.md
new file mode 100644
index 0000000..bf00aed
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/README.md
@@ -0,0 +1,21 @@
+# Rust Skeleton EVS HAL implementation.
+
+WARNING: This is not a reference EVS HAL implementation and therefore does not
+provide any actual functionality.
+
+This folder contains a skeleton EVS HAL implementation in Rust to demonstrate
+how vendors could implement their EVS HAL in Rust. To compile and run this
+implementation, please include below package to the device build script:
+
+* `android.hardware.automotive.evs-aidl-rust-service`
+
+Please note that this service will attempt to register the service as
+`IEvsEnumerator/rust/0` and therefore is also required to be declared in the
+service context by adding below line to a proper `service_contexts` file:
+
+> android.hardware.automotive.evs.IEvsEnumerator/rust/0 u:object_r:hal_evs_service:s0
+
+This implementation intentionally returns `binder::StatusCode::UNKNOWN_ERROR`
+for any API call except deprecated API for ultrasonics; the process will be
+panicked on these methods instead. Hence, this implementation does not comply
+with VTS tests and vendors must replace each method with actual implementation.
diff --git a/automotive/evs/aidl/rust_impl/evs-rust-service.rc b/automotive/evs/aidl/rust_impl/evs-rust-service.rc
new file mode 100644
index 0000000..3741b21
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/evs-rust-service.rc
@@ -0,0 +1,8 @@
+service vendor.evs-hal-rust-default /vendor/bin/hw/android.hardware.automotive.evs-aidl-rust-service
+ class early_hal
+ priority -20
+ user graphics
+ group automotive_evs camera
+ onrestart restart cardisplayproxyd
+ onrestart restart evsmanagerd
+ disabled
diff --git a/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml
new file mode 100644
index 0000000..813cbb2
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml
@@ -0,0 +1,7 @@
+<manifest version="2.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.automotive.evs</name>
+ <version>2</version>
+ <fqname>IEvsEnumerator/rust/0</fqname>
+ </hal>
+</manifest>
diff --git a/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs
new file mode 100644
index 0000000..72b2d53
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs
@@ -0,0 +1,113 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::{
+ CameraDesc::CameraDesc, DisplayState::DisplayState, IEvsCamera::IEvsCamera,
+ IEvsDisplay::IEvsDisplay, IEvsEnumerator::IEvsEnumerator,
+ IEvsEnumeratorStatusCallback::IEvsEnumeratorStatusCallback,
+ IEvsUltrasonicsArray::IEvsUltrasonicsArray, Stream::Stream,
+ UltrasonicsArrayDesc::UltrasonicsArrayDesc,
+};
+
+pub struct DefaultEvsHal {}
+
+impl binder::Interface for DefaultEvsHal {}
+
+impl IEvsEnumerator for DefaultEvsHal {
+ fn closeCamera(
+ &self,
+ _: &binder::Strong<(dyn IEvsCamera + 'static)>,
+ ) -> std::result::Result<(), binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn closeDisplay(
+ &self,
+ _: &binder::Strong<(dyn IEvsDisplay + 'static)>,
+ ) -> std::result::Result<(), binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn closeUltrasonicsArray(
+ &self,
+ _: &binder::Strong<(dyn IEvsUltrasonicsArray + 'static)>,
+ ) -> std::result::Result<(), binder::Status> {
+ unimplemented!()
+ }
+
+ fn getCameraList(&self) -> std::result::Result<std::vec::Vec<CameraDesc>, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn getDisplayIdList(&self) -> std::result::Result<std::vec::Vec<u8>, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn getDisplayState(&self) -> std::result::Result<DisplayState, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn getStreamList(
+ &self,
+ _: &CameraDesc,
+ ) -> std::result::Result<std::vec::Vec<Stream>, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn getUltrasonicsArrayList(
+ &self,
+ ) -> std::result::Result<std::vec::Vec<UltrasonicsArrayDesc>, binder::Status> {
+ unimplemented!()
+ }
+
+ fn isHardware(&self) -> std::result::Result<bool, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn openCamera(
+ &self,
+ _: &str,
+ _: &Stream,
+ ) -> std::result::Result<binder::Strong<(dyn IEvsCamera + 'static)>, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn openDisplay(
+ &self,
+ _: i32,
+ ) -> std::result::Result<binder::Strong<(dyn IEvsDisplay + 'static)>, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn openUltrasonicsArray(
+ &self,
+ _: &str,
+ ) -> std::result::Result<binder::Strong<(dyn IEvsUltrasonicsArray + 'static)>, binder::Status>
+ {
+ unimplemented!()
+ }
+
+ fn registerStatusCallback(
+ &self,
+ _: &binder::Strong<(dyn IEvsEnumeratorStatusCallback + 'static)>,
+ ) -> std::result::Result<(), binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+
+ fn getDisplayStateById(&self, _: i32) -> std::result::Result<DisplayState, binder::Status> {
+ Err(binder::StatusCode::UNKNOWN_ERROR.into())
+ }
+}
diff --git a/automotive/evs/aidl/rust_impl/src/main.rs b/automotive/evs/aidl/rust_impl/src/main.rs
new file mode 100644
index 0000000..df312c0
--- /dev/null
+++ b/automotive/evs/aidl/rust_impl/src/main.rs
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+mod default_evs_hal;
+
+use crate::default_evs_hal::DefaultEvsHal;
+
+use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::IEvsEnumerator::BnEvsEnumerator;
+
+use log::info;
+
+fn main() {
+ binder::ProcessState::start_thread_pool();
+
+ let service = DefaultEvsHal {};
+
+ // Register HAL implementation as rust/0 instance.
+ let service_name = "android.hardware.automotive.evs.IEvsEnumerator/rust/0";
+ let service_binder = BnEvsEnumerator::new_binder(service, binder::BinderFeatures::default());
+
+ binder::add_service(service_name, service_binder.as_binder())
+ .expect(format!("Failed to register {}.", service_name).as_str());
+ info!("EVS Hardware Enumerator is ready");
+
+ binder::ProcessState::join_thread_pool();
+
+ // In normal operation, we don't expect the thread pool to exit.
+ info!("EVS Hardware Enumerator is shutting down");
+}
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 94a5882..76d44f8 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -290,7 +290,8 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "ericjeong@google.com",
+ "shanyu@google.com",
],
componentid: 533764,
hotlists: [
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 77629a9..d848774 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -45,6 +45,9 @@
"name": "FakeVehicleHardwareTest"
},
{
+ "name": "GRPCVehicleHardwareUnitTest"
+ },
+ {
"name": "CarServiceUnitTest",
"options" : [
{
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 79d3e77..ec69894 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -327,6 +327,8 @@
static android::base::Result<float> safelyParseFloat(int index, const std::string& s);
static android::base::Result<int32_t> parsePropId(const std::vector<std::string>& options,
size_t index);
+ static android::base::Result<int32_t> parseAreaId(const std::vector<std::string>& options,
+ size_t index, int32_t propId);
};
} // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 4f060e2..54dcca2 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -1902,6 +1902,37 @@
return safelyParseInt<int32_t>(index, propIdStr);
}
+// Parses areaId option ("-a"). It can be an Integer or a string in the form of "AREA_1" or
+// "AREA_1 | AREA_2 | ..."
+Result<int32_t> FakeVehicleHardware::parseAreaId(const std::vector<std::string>& options,
+ size_t index, int32_t propId) {
+ const std::string& areaIdStr = options[index];
+ auto result = safelyParseInt<int32_t>(index, areaIdStr);
+ if (result.ok()) {
+ return result;
+ }
+
+ // Check for pattern matching "AREA_1 | AREA_2 | AREA_3".
+ std::regex pattern(R"(^\w+(?:( )?\|( )?\w+)*$)");
+ std::smatch match;
+ int32_t areaId = 0;
+ if (!std::regex_match(areaIdStr, match, pattern)) {
+ return result;
+ }
+ pattern = R"(\w+)";
+
+ std::sregex_iterator end;
+ for (std::sregex_iterator it(areaIdStr.begin(), areaIdStr.end(), pattern); it != end; it++) {
+ // Parse each areas contained in this areaId.
+ auto result = stringToArea(it->str(), propId);
+ if (!result.ok()) {
+ return result;
+ }
+ areaId |= result.value();
+ }
+ return areaId;
+}
+
std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
return getErrorMsg(result);
@@ -1958,6 +1989,7 @@
prop.status = VehiclePropertyStatus::AVAILABLE;
optionIndex++;
std::unordered_set<std::string> parsedOptions;
+ int32_t areaIdIndex = -1;
while (optionIndex < options.size()) {
std::string argType = options[optionIndex];
@@ -2032,13 +2064,7 @@
if (argValuesSize != 1) {
return Error() << "Expect exact one value when using \"-a\"\n";
}
- auto int32Result = safelyParseInt<int32_t>(currentIndex, argValues[0]);
- if (!int32Result.ok()) {
- return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n",
- argValues[0].c_str(),
- getErrorMsg(int32Result).c_str());
- }
- prop.areaId = int32Result.value();
+ areaIdIndex = currentIndex;
} else if (EqualsIgnoreCase(argType, "-t")) {
if (argValuesSize != 1) {
return Error() << "Expect exact one value when using \"-t\"\n";
@@ -2055,6 +2081,17 @@
}
}
+ if (areaIdIndex != -1) {
+ auto int32Result = parseAreaId(options, areaIdIndex, prop.prop);
+ if (!int32Result.ok()) {
+ return Error() << StringPrintf(
+ "Area ID: \"%s\" is not a valid int or "
+ "one or more area names: %s\n",
+ options[areaIdIndex].c_str(), getErrorMsg(int32Result).c_str());
+ }
+ prop.areaId = int32Result.value();
+ }
+
return prop;
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 0924360..8dbba19 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -77,6 +77,7 @@
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateShutdownParam;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaSeat;
using ::aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
@@ -2781,6 +2782,8 @@
std::vector<SetPropTestCase> GenSetPropParams() {
std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
+ std::string testVendorProperty =
+ std::to_string(toInt(TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY));
return {
{"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, true},
{"success_set_with_name", {"--set", "INFO_MAKE", "-s", CAR_MAKE}, true},
@@ -2889,6 +2892,14 @@
{"--set", infoMakeProperty, "-a", "-s", CAR_MAKE},
false,
"Expect exact one value"},
+ {"fail_invalid_area_name",
+ {"--set", testVendorProperty, "-a", "ROW_1_LEFT|NO_SUCH_AREA", "-f", "1.234"},
+ false,
+ "not a valid int or one or more area names"},
+ {"fail_invalid_area_format",
+ {"--set", testVendorProperty, "-a", "ROW_1_LEFT|||ROW_2_LEFT", "-f", "1.234"},
+ false,
+ "not a valid int or one or more area names"},
};
}
@@ -2933,6 +2944,86 @@
ASSERT_EQ(3.402823466E+38f, value.value.floatValues[2]);
}
+TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameAreaId) {
+ int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT);
+ getHardware()->dump(
+ {"--set", "HVAC_TEMPERATURE_SET", "-a", std::to_string(areaId), "-f", "22.345"});
+
+ VehiclePropValue requestProp;
+ requestProp.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
+ requestProp.areaId = areaId;
+ auto result = getValue(requestProp);
+
+ ASSERT_TRUE(result.ok());
+ VehiclePropValue value = result.value();
+ ASSERT_EQ(value.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+ ASSERT_EQ(value.areaId, areaId);
+ ASSERT_EQ(1u, value.value.floatValues.size());
+ ASSERT_EQ(22.345f, value.value.floatValues[0]);
+}
+
+TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameAreaName) {
+ int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT);
+ getHardware()->dump({"--set", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT", "-f", "22.345"});
+
+ VehiclePropValue requestProp;
+ requestProp.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
+ requestProp.areaId = areaId;
+ auto result = getValue(requestProp);
+
+ ASSERT_TRUE(result.ok());
+ VehiclePropValue value = result.value();
+ ASSERT_EQ(value.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+ ASSERT_EQ(value.areaId, areaId);
+ ASSERT_EQ(1u, value.value.floatValues.size());
+ ASSERT_EQ(22.345f, value.value.floatValues[0]);
+}
+
+TEST_F(FakeVehicleHardwareTest, GetPropertyWithPropertyNameAreaName) {
+ auto result = getHardware()->dump({"--get", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT"});
+
+ // Default value is 17
+ ASSERT_THAT(result.buffer, ContainsRegex("17"));
+
+ getHardware()->dump({"--set", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT", "-f", "22"});
+ result = getHardware()->dump({"--get", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT"});
+
+ ASSERT_THAT(result.buffer, ContainsRegex("22"));
+}
+
+TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameTwoAreasInOneId) {
+ int32_t propId = toInt(TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY);
+ std::string testVendorProperty = std::to_string(propId);
+ getHardware()->dump({"--set", testVendorProperty, "-a", "ROW_1_LEFT|ROW_2_LEFT|ROW_2_CENTER",
+ "-f", "1.234"});
+
+ VehiclePropValue requestProp;
+ requestProp.prop = propId;
+ int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT) | toInt(VehicleAreaSeat::ROW_2_LEFT) |
+ toInt(VehicleAreaSeat::ROW_2_CENTER);
+ requestProp.areaId = areaId;
+ auto result = getValue(requestProp);
+
+ ASSERT_TRUE(result.ok());
+ VehiclePropValue value = result.value();
+ ASSERT_EQ(value.prop, propId);
+ ASSERT_EQ(value.areaId, areaId);
+ ASSERT_EQ(1u, value.value.floatValues.size());
+ ASSERT_EQ(1.234f, value.value.floatValues[0]);
+
+ // Ignore space between two areas.
+ getHardware()->dump({"--set", testVendorProperty, "-a",
+ "ROW_1_LEFT | ROW_2_LEFT | ROW_2_CENTER", "-f", "2.345"});
+ result = getValue(requestProp);
+
+ ASSERT_TRUE(result.ok());
+ value = result.value();
+ ASSERT_EQ(value.prop, propId);
+ ASSERT_EQ(value.areaId, areaId);
+ ASSERT_EQ(1u, value.value.floatValues.size());
+ ASSERT_EQ(2.345f, value.value.floatValues[0]);
+}
+
struct OptionsTestCase {
std::string name;
std::vector<std::string> options;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index f44573a..73bb521 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -20,6 +20,7 @@
#include <android-base/logging.h>
#include <grpc++/grpc++.h>
+#include <utils/SystemClock.h>
#include <cstdlib>
#include <mutex>
@@ -28,11 +29,16 @@
namespace android::hardware::automotive::vehicle::virtualization {
-static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
- // TODO(chenhaosjtuacm): get secured credentials here
+namespace {
+
+constexpr size_t MAX_RETRY_COUNT = 5;
+
+std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
return ::grpc::InsecureChannelCredentials();
}
+} // namespace
+
GRPCVehicleHardware::GRPCVehicleHardware(std::string service_addr)
: mServiceAddr(std::move(service_addr)),
mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
@@ -40,11 +46,13 @@
mValuePollingThread([this] { ValuePollingLoop(); }) {}
// Only used for unit testing.
-GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub)
- : mServiceAddr(""),
- mGrpcChannel(nullptr),
- mGrpcStub(std::move(stub)),
- mValuePollingThread([] {}) {}
+GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub,
+ bool startValuePollingLoop)
+ : mServiceAddr(""), mGrpcChannel(nullptr), mGrpcStub(std::move(stub)) {
+ if (startValuePollingLoop) {
+ mValuePollingThread = std::thread([this] { ValuePollingLoop(); });
+ }
+}
GRPCVehicleHardware::~GRPCVehicleHardware() {
{
@@ -52,7 +60,9 @@
mShuttingDownFlag.store(true);
}
mShutdownCV.notify_all();
- mValuePollingThread.join();
+ if (mValuePollingThread.joinable()) {
+ mValuePollingThread.join();
+ }
}
std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConfigs() const {
@@ -109,36 +119,117 @@
aidlvhal::StatusCode GRPCVehicleHardware::getValues(
std::shared_ptr<const GetValuesCallback> callback,
const std::vector<aidlvhal::GetValueRequest>& requests) const {
- ::grpc::ClientContext context;
+ std::vector<aidlvhal::GetValueResult> results;
+ auto status = getValuesWithRetry(requests, &results, /*retryCount=*/0);
+ if (status != aidlvhal::StatusCode::OK) {
+ return status;
+ }
+ if (!results.empty()) {
+ (*callback)(std::move(results));
+ }
+ return status;
+}
+
+aidlvhal::StatusCode GRPCVehicleHardware::getValuesWithRetry(
+ const std::vector<aidlvhal::GetValueRequest>& requests,
+ std::vector<aidlvhal::GetValueResult>* results, size_t retryCount) const {
+ if (retryCount == MAX_RETRY_COUNT) {
+ LOG(ERROR) << __func__ << ": GRPC GetValues Failed, failed to get the latest value after "
+ << retryCount << " retries";
+ return aidlvhal::StatusCode::TRY_AGAIN;
+ }
+
proto::VehiclePropValueRequests protoRequests;
- proto::GetValueResults protoResults;
+ std::unordered_map<int64_t, const aidlvhal::GetValueRequest*> requestById;
for (const auto& request : requests) {
auto& protoRequest = *protoRequests.add_requests();
protoRequest.set_request_id(request.requestId);
proto_msg_converter::aidlToProto(request.prop, protoRequest.mutable_value());
+ requestById[request.requestId] = &request;
}
+
// TODO(chenhaosjtuacm): Make it Async.
+ ::grpc::ClientContext context;
+ proto::GetValueResults protoResults;
auto grpc_status = mGrpcStub->GetValues(&context, protoRequests, &protoResults);
if (!grpc_status.ok()) {
LOG(ERROR) << __func__ << ": GRPC GetValues Failed: " << grpc_status.error_message();
return aidlvhal::StatusCode::INTERNAL_ERROR;
}
- std::vector<aidlvhal::GetValueResult> results;
+
+ std::vector<aidlvhal::GetValueRequest> retryRequests;
for (const auto& protoResult : protoResults.results()) {
- auto& result = results.emplace_back();
- result.requestId = protoResult.request_id();
- result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
- if (protoResult.has_value()) {
- aidlvhal::VehiclePropValue value;
- proto_msg_converter::protoToAidl(protoResult.value(), &value);
- result.prop = std::move(value);
+ int64_t requestId = protoResult.request_id();
+ auto it = requestById.find(requestId);
+ if (it == requestById.end()) {
+ LOG(ERROR) << __func__
+ << "Invalid getValue request with unknown request ID: " << requestId
+ << ", ignore";
+ continue;
}
+
+ if (!protoResult.has_value()) {
+ auto& result = results->emplace_back();
+ result.requestId = requestId;
+ result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
+ continue;
+ }
+
+ aidlvhal::VehiclePropValue value;
+ proto_msg_converter::protoToAidl(protoResult.value(), &value);
+
+ // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to reset
+ // the timestamp.
+ // TODO(b/350822044): Remove this once we use timestamp from proxy server.
+ if (!setAndroidTimestamp(&value)) {
+ // This is a rare case when we receive a property update event reflecting a new value
+ // for the property before we receive the get value result. This means that the result
+ // is already outdated, hence we should retry getting the latest value again.
+ LOG(WARNING) << __func__ << "getValue result for propId: " << value.prop
+ << " areaId: " << value.areaId << " is oudated, retry";
+ retryRequests.push_back(*(it->second));
+ continue;
+ }
+
+ auto& result = results->emplace_back();
+ result.requestId = requestId;
+ result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
+ result.prop = std::move(value);
}
- (*callback)(std::move(results));
+
+ if (retryRequests.size() != 0) {
+ return getValuesWithRetry(retryRequests, results, retryCount++);
+ }
return aidlvhal::StatusCode::OK;
}
+bool GRPCVehicleHardware::setAndroidTimestamp(aidlvhal::VehiclePropValue* propValue) const {
+ PropIdAreaId propIdAreaId = {
+ .propId = propValue->prop,
+ .areaId = propValue->areaId,
+ };
+ int64_t now = elapsedRealtimeNano();
+ int64_t externalTimestamp = propValue->timestamp;
+
+ {
+ std::lock_guard lck(mLatestUpdateTimestampsMutex);
+ auto it = mLatestUpdateTimestamps.find(propIdAreaId);
+ if (it == mLatestUpdateTimestamps.end() || externalTimestamp > (it->second).first) {
+ mLatestUpdateTimestamps[propIdAreaId].first = externalTimestamp;
+ mLatestUpdateTimestamps[propIdAreaId].second = now;
+ propValue->timestamp = now;
+ return true;
+ }
+ if (externalTimestamp == (it->second).first) {
+ propValue->timestamp = (it->second).second;
+ return true;
+ }
+ }
+ // externalTimestamp < (it->second).first, the value is outdated.
+ return false;
+}
+
void GRPCVehicleHardware::registerOnPropertyChangeEvent(
std::unique_ptr<const PropertyChangeCallback> callback) {
std::lock_guard lck(mCallbackMutex);
@@ -248,46 +339,61 @@
void GRPCVehicleHardware::ValuePollingLoop() {
while (!mShuttingDownFlag.load()) {
- ::grpc::ClientContext context;
-
- bool rpc_stopped{false};
- std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
- std::unique_lock<std::mutex> lck(mShutdownMutex);
- mShutdownCV.wait(lck, [this, &rpc_stopped]() {
- return rpc_stopped || mShuttingDownFlag.load();
- });
- context.TryCancel();
- });
-
- auto value_stream =
- mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
- LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
- proto::VehiclePropValues protoValues;
- while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
- std::vector<aidlvhal::VehiclePropValue> values;
- for (const auto protoValue : protoValues.values()) {
- values.push_back(aidlvhal::VehiclePropValue());
- proto_msg_converter::protoToAidl(protoValue, &values.back());
- }
- std::shared_lock lck(mCallbackMutex);
- if (mOnPropChange) {
- (*mOnPropChange)(values);
- }
- }
-
- {
- std::lock_guard lck(mShutdownMutex);
- rpc_stopped = true;
- }
- mShutdownCV.notify_all();
- shuttingdown_watcher.join();
-
- auto grpc_status = value_stream->Finish();
- // never reach here until connection lost
- LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
-
+ pollValue();
// try to reconnect
}
}
+void GRPCVehicleHardware::pollValue() {
+ ::grpc::ClientContext context;
+
+ bool rpc_stopped{false};
+ std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
+ std::unique_lock<std::mutex> lck(mShutdownMutex);
+ mShutdownCV.wait(
+ lck, [this, &rpc_stopped]() { return rpc_stopped || mShuttingDownFlag.load(); });
+ context.TryCancel();
+ });
+
+ auto value_stream = mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
+ LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
+ proto::VehiclePropValues protoValues;
+ while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
+ std::vector<aidlvhal::VehiclePropValue> values;
+ for (const auto protoValue : protoValues.values()) {
+ aidlvhal::VehiclePropValue aidlValue = {};
+ proto_msg_converter::protoToAidl(protoValue, &aidlValue);
+
+ // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to
+ // reset the timestamp.
+ // TODO(b/350822044): Remove this once we use timestamp from proxy server.
+ if (!setAndroidTimestamp(&aidlValue)) {
+ LOG(WARNING) << __func__ << ": property event for propId: " << aidlValue.prop
+ << " areaId: " << aidlValue.areaId << " is outdated, ignore";
+ continue;
+ }
+
+ values.push_back(std::move(aidlValue));
+ }
+ if (values.empty()) {
+ continue;
+ }
+ std::shared_lock lck(mCallbackMutex);
+ if (mOnPropChange) {
+ (*mOnPropChange)(values);
+ }
+ }
+
+ {
+ std::lock_guard lck(mShutdownMutex);
+ rpc_stopped = true;
+ }
+ mShutdownCV.notify_all();
+ shuttingdown_watcher.join();
+
+ auto grpc_status = value_stream->Finish();
+ // never reach here until connection lost
+ LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
+}
+
} // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index 9750f62..1edf658 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -20,6 +20,7 @@
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
#include <android-base/result.h>
+#include <android-base/thread_annotations.h>
#include "VehicleServer.grpc.pb.h"
#include "VehicleServer.pb.h"
@@ -33,6 +34,7 @@
#include <shared_mutex>
#include <string>
#include <thread>
+#include <unordered_map>
#include <vector>
namespace android::hardware::automotive::vehicle::virtualization {
@@ -43,9 +45,6 @@
public:
explicit GRPCVehicleHardware(std::string service_addr);
- // Only used for unit testing.
- explicit GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub);
-
~GRPCVehicleHardware();
// Get all the property configs.
@@ -94,7 +93,7 @@
std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
private:
- void ValuePollingLoop();
+ friend class GRPCVehicleHardwareUnitTest;
std::string mServiceAddr;
std::shared_ptr<::grpc::Channel> mGrpcChannel;
@@ -106,6 +105,31 @@
std::mutex mShutdownMutex;
std::condition_variable mShutdownCV;
std::atomic<bool> mShuttingDownFlag{false};
+
+ mutable std::mutex mLatestUpdateTimestampsMutex;
+
+ // A map from [propId, areaId] to the latest timestamp this property is updated.
+ // The key is a tuple, the first element is the external timestamp (timestamp set by VHAL
+ // server), the second element is the Android timestamp (elapsedRealtimeNano).
+ mutable std::unordered_map<PropIdAreaId, std::pair<int64_t, int64_t>,
+ PropIdAreaIdHash> mLatestUpdateTimestamps
+ GUARDED_BY(mLatestUpdateTimestampsMutex);
+
+ // Only used for unit testing.
+ GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub,
+ bool startValuePollingLoop);
+
+ void ValuePollingLoop();
+ void pollValue();
+
+ aidlvhal::StatusCode getValuesWithRetry(const std::vector<aidlvhal::GetValueRequest>& requests,
+ std::vector<aidlvhal::GetValueResult>* results,
+ size_t retryCount) const;
+
+ // Check the external timestamp of propValue against the latest updated external timestamp, if
+ // this is an outdated value, return false. Otherwise, update the external timestamp to the
+ // Android timestamp and return true.
+ bool setAndroidTimestamp(aidlvhal::VehiclePropValue* propValue) const;
};
} // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index a6abfa3..eb98af0 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -40,7 +40,11 @@
GrpcVehicleProxyServer::GrpcVehicleProxyServer(std::string serverAddr,
std::unique_ptr<IVehicleHardware>&& hardware)
- : mServiceAddr(std::move(serverAddr)), mHardware(std::move(hardware)) {
+ : GrpcVehicleProxyServer(std::vector<std::string>({serverAddr}), std::move(hardware)){};
+
+GrpcVehicleProxyServer::GrpcVehicleProxyServer(std::vector<std::string> serverAddrs,
+ std::unique_ptr<IVehicleHardware>&& hardware)
+ : mServiceAddrs(std::move(serverAddrs)), mHardware(std::move(hardware)) {
mHardware->registerOnPropertyChangeEvent(
std::make_unique<const IVehicleHardware::PropertyChangeCallback>(
[this](std::vector<aidlvhal::VehiclePropValue> values) {
@@ -254,7 +258,9 @@
}
::grpc::ServerBuilder builder;
builder.RegisterService(this);
- builder.AddListeningPort(mServiceAddr, getServerCredentials());
+ for (const std::string& serviceAddr : mServiceAddrs) {
+ builder.AddListeningPort(serviceAddr, getServerCredentials());
+ }
mServer = builder.BuildAndStart();
CHECK(mServer) << __func__ << ": failed to create the GRPC server, "
<< "please make sure the configuration and permissions are correct";
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
index dd9e2aa..5ffb531 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
@@ -41,6 +41,9 @@
public:
GrpcVehicleProxyServer(std::string serverAddr, std::unique_ptr<IVehicleHardware>&& hardware);
+ GrpcVehicleProxyServer(std::vector<std::string> serverAddrs,
+ std::unique_ptr<IVehicleHardware>&& hardware);
+
::grpc::Status GetAllPropertyConfig(
::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
::grpc::ServerWriter<proto::VehiclePropConfig>* stream) override;
@@ -116,7 +119,7 @@
static std::atomic<uint64_t> connection_id_counter_;
};
- std::string mServiceAddr;
+ std::vector<std::string> mServiceAddrs;
std::unique_ptr<::grpc::Server> mServer{nullptr};
std::unique_ptr<IVehicleHardware> mHardware;
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index 3bd7e0e..20af231 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
@@ -19,8 +19,10 @@
#include <gmock/gmock.h>
#include <grpc++/grpc++.h>
+#include <grpcpp/test/mock_stream.h>
#include <gtest/gtest.h>
+#include <utils/SystemClock.h>
#include <chrono>
#include <memory>
#include <string>
@@ -31,98 +33,48 @@
using ::testing::_;
using ::testing::DoAll;
+using ::testing::ElementsAre;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
+using ::testing::SizeIs;
+
+using ::grpc::testing::MockClientReader;
using proto::MockVehicleServerStub;
-const std::string kFakeServerAddr = "0.0.0.0:54321";
-
-class FakeVehicleServer : public proto::VehicleServer::Service {
- public:
- ::grpc::Status StartPropertyValuesStream(
- ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
- ::grpc::ServerWriter<proto::VehiclePropValues>* stream) override {
- stream->Write(proto::VehiclePropValues());
- // A fake disconnection.
- return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
- }
-
- // Functions that we do not care.
- ::grpc::Status GetAllPropertyConfig(
- ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
- ::grpc::ServerWriter<proto::VehiclePropConfig>* stream) override {
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetValues(::grpc::ServerContext* context,
- const proto::VehiclePropValueRequests* requests,
- proto::SetValueResults* results) override {
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status GetValues(::grpc::ServerContext* context,
- const proto::VehiclePropValueRequests* requests,
- proto::GetValueResults* results) override {
- return ::grpc::Status::OK;
- }
-};
-
-TEST(GRPCVehicleHardwareUnitTest, Reconnect) {
- auto receivedUpdate = std::make_shared<std::atomic<int>>(0);
- auto vehicleHardware = std::make_unique<GRPCVehicleHardware>(kFakeServerAddr);
- vehicleHardware->registerOnPropertyChangeEvent(
- std::make_unique<const IVehicleHardware::PropertyChangeCallback>(
- [receivedUpdate](const auto&) { receivedUpdate->fetch_add(1); }));
-
- constexpr size_t kServerRestartTimes = 5;
- for (size_t serverStart = 0; serverStart < kServerRestartTimes; ++serverStart) {
- EXPECT_EQ(receivedUpdate->load(), 0);
- auto fakeServer = std::make_unique<FakeVehicleServer>();
- ::grpc::ServerBuilder builder;
- builder.RegisterService(fakeServer.get());
- builder.AddListeningPort(kFakeServerAddr, ::grpc::InsecureServerCredentials());
- auto grpcServer = builder.BuildAndStart();
-
- // Wait until the vehicle hardware received the second update (after one fake
- // disconnection).
- constexpr auto kMaxWaitTime = std::chrono::seconds(5);
- auto startTime = std::chrono::steady_clock::now();
- while (receivedUpdate->load() <= 1 &&
- std::chrono::steady_clock::now() - startTime < kMaxWaitTime)
- ;
-
- grpcServer->Shutdown();
- grpcServer->Wait();
- EXPECT_GT(receivedUpdate->load(), 1);
-
- // Reset for the next round.
- receivedUpdate->store(0);
- }
-}
-
-class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
+class GRPCVehicleHardwareUnitTest : public ::testing::Test {
protected:
NiceMock<MockVehicleServerStub>* mGrpcStub;
std::unique_ptr<GRPCVehicleHardware> mHardware;
void SetUp() override {
auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
- ;
mGrpcStub = stub.get();
- mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
+ // Cannot use make_unique here since the constructor is a private method.
+ mHardware = std::unique_ptr<GRPCVehicleHardware>(
+ new GRPCVehicleHardware(std::move(stub), /*startValuePollingLoop=*/false));
}
void TearDown() override { mHardware.reset(); }
+
+ // Access GRPCVehicleHardware private method.
+ void pollValue() { mHardware->pollValue(); }
+
+ void startValuePollingLoop(std::unique_ptr<proto::VehicleServer::StubInterface> stub) {
+ mHardware = std::unique_ptr<GRPCVehicleHardware>(
+ new GRPCVehicleHardware(std::move(stub), /*startValuePollingLoop=*/true));
+ }
+
+ void generatePropertyUpdateEvent(int32_t propId, int64_t timestamp);
};
MATCHER_P(RepeatedInt32Eq, expected_values, "") {
return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribe) {
proto::VehicleHalCallStatus protoStatus;
protoStatus.set_status_code(proto::StatusCode::OK);
proto::SubscribeRequest actualRequest;
@@ -147,7 +99,7 @@
EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeLegacyServer) {
EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
.WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
@@ -157,7 +109,7 @@
EXPECT_EQ(status, aidlvhal::StatusCode::OK);
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeGrpcFailure) {
EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
.WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
@@ -167,7 +119,7 @@
EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeProtoFailure) {
proto::VehicleHalCallStatus protoStatus;
protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
@@ -181,7 +133,7 @@
EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribe) {
proto::VehicleHalCallStatus protoStatus;
protoStatus.set_status_code(proto::StatusCode::OK);
proto::UnsubscribeRequest actualRequest;
@@ -199,7 +151,7 @@
EXPECT_EQ(actualRequest.area_id(), areaId);
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeLegacyServer) {
EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
.WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
@@ -208,7 +160,7 @@
EXPECT_EQ(status, aidlvhal::StatusCode::OK);
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeGrpcFailure) {
EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
.WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
@@ -217,7 +169,7 @@
EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
}
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeProtoFailure) {
proto::VehicleHalCallStatus protoStatus;
protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
@@ -230,4 +182,264 @@
EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
}
+TEST_F(GRPCVehicleHardwareUnitTest, TestPollValue) {
+ int64_t testTimestamp = 12345;
+ int32_t testPropId = 54321;
+ int64_t startTimestamp = elapsedRealtimeNano();
+
+ // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+ // there.
+ auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+ EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+ EXPECT_CALL(*clientReader, Read(_))
+ .WillOnce([testTimestamp, testPropId](proto::VehiclePropValues* values) {
+ values->Clear();
+ auto value = values->add_values();
+ value->set_timestamp(testTimestamp);
+ value->set_prop(testPropId);
+ return true;
+ })
+ .WillOnce(Return(false));
+ EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+ std::vector<aidlvhal::VehiclePropValue> propertyEvents;
+
+ mHardware->registerOnPropertyChangeEvent(
+ std::make_unique<GRPCVehicleHardware::PropertyChangeCallback>(
+ [&propertyEvents](const std::vector<aidlvhal::VehiclePropValue>& events) {
+ for (const auto& event : events) {
+ propertyEvents.push_back(event);
+ }
+ }));
+
+ pollValue();
+
+ ASSERT_THAT(propertyEvents, SizeIs(1));
+ EXPECT_EQ(propertyEvents[0].prop, testPropId);
+ EXPECT_GT(propertyEvents[0].timestamp, startTimestamp)
+ << "Timestamp must be updated to Android timestamp";
+ EXPECT_LT(propertyEvents[0].timestamp, elapsedRealtimeNano())
+ << "Timestamp must be updated to Android timestamp";
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestPollValueIgnoreOutdatedValue) {
+ int64_t testTimestamp1 = 12345;
+ int32_t value1 = 1324;
+ int64_t testTimestamp2 = 12340;
+ int32_t value2 = 1423;
+ int32_t testPropId = 54321;
+ int64_t startTimestamp = elapsedRealtimeNano();
+
+ // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+ // there.
+ auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+ EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+ EXPECT_CALL(*clientReader, Read(_))
+ .WillOnce([testTimestamp1, value1, testPropId](proto::VehiclePropValues* values) {
+ values->Clear();
+ auto value = values->add_values();
+ value->set_timestamp(testTimestamp1);
+ value->set_prop(testPropId);
+ value->add_int32_values(value1);
+ return true;
+ })
+ .WillOnce([testTimestamp2, value2, testPropId](proto::VehiclePropValues* values) {
+ values->Clear();
+ // This event is outdated, must be ignored.
+ auto value = values->add_values();
+ value->set_timestamp(testTimestamp2);
+ value->set_prop(testPropId);
+ value->add_int32_values(value2);
+ return true;
+ })
+ .WillOnce(Return(false));
+ EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+ std::vector<aidlvhal::VehiclePropValue> propertyEvents;
+
+ mHardware->registerOnPropertyChangeEvent(
+ std::make_unique<GRPCVehicleHardware::PropertyChangeCallback>(
+ [&propertyEvents](const std::vector<aidlvhal::VehiclePropValue>& events) {
+ for (const auto& event : events) {
+ propertyEvents.push_back(event);
+ }
+ }));
+
+ pollValue();
+
+ ASSERT_THAT(propertyEvents, SizeIs(1)) << "Outdated event must be ignored";
+ EXPECT_EQ(propertyEvents[0].prop, testPropId);
+ EXPECT_GT(propertyEvents[0].timestamp, startTimestamp);
+ EXPECT_LT(propertyEvents[0].timestamp, elapsedRealtimeNano());
+ EXPECT_THAT(propertyEvents[0].value.int32Values, ElementsAre(value1));
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestValuePollingLoop) {
+ int64_t testTimestamp = 12345;
+ int32_t testPropId = 54321;
+ auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
+
+ // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+ // there.
+ auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+ EXPECT_CALL(*stub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+ EXPECT_CALL(*clientReader, Read(_))
+ .WillRepeatedly([testTimestamp, testPropId](proto::VehiclePropValues* values) {
+ // Sleep for 10ms and always return the same property event.
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ values->Clear();
+ auto value = values->add_values();
+ value->set_timestamp(testTimestamp);
+ value->set_prop(testPropId);
+ return true;
+ });
+ EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+ startValuePollingLoop(std::move(stub));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ // This must stop the loop and wait for the thread to finish.
+ mHardware.reset();
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestGetValues) {
+ int64_t testRequestId = 1234;
+ int32_t testPropId = 4321;
+ int32_t testValue = 123456;
+ proto::VehiclePropValueRequests gotRequests;
+ EXPECT_CALL(*mGrpcStub, GetValues(_, _, _))
+ .WillOnce([&gotRequests, testRequestId, testPropId, testValue](
+ ::grpc::ClientContext* context,
+ const proto::VehiclePropValueRequests& request,
+ proto::GetValueResults* response) {
+ gotRequests = request;
+ response->Clear();
+ auto* resultPtr = response->add_results();
+ resultPtr->set_request_id(testRequestId);
+ resultPtr->set_status(proto::StatusCode::OK);
+ auto* valuePtr = resultPtr->mutable_value();
+ valuePtr->set_prop(testPropId);
+ valuePtr->add_int32_values(testValue);
+ return ::grpc::Status::OK;
+ });
+
+ std::vector<aidlvhal::GetValueRequest> requests;
+ requests.push_back(aidlvhal::GetValueRequest{.requestId = testRequestId,
+ .prop = {
+ .prop = testPropId,
+ }});
+
+ std::vector<aidlvhal::GetValueResult> gotResults;
+
+ auto status = mHardware->getValues(
+ std::make_shared<GRPCVehicleHardware::GetValuesCallback>(
+ [&gotResults](std::vector<aidlvhal::GetValueResult> results) {
+ for (const auto& result : results) {
+ gotResults.push_back(result);
+ }
+ }),
+ requests);
+
+ ASSERT_EQ(status, aidlvhal::StatusCode::OK);
+ ASSERT_THAT(gotRequests.requests(), SizeIs(1));
+ EXPECT_THAT(gotRequests.requests(0).request_id(), testRequestId);
+ EXPECT_THAT(gotRequests.requests(0).value().prop(), testPropId);
+
+ ASSERT_THAT(gotResults, SizeIs(1));
+ EXPECT_EQ(gotResults[0].requestId, testRequestId);
+ EXPECT_EQ(gotResults[0].status, aidlvhal::StatusCode::OK);
+ EXPECT_EQ(gotResults[0].prop->prop, testPropId);
+ EXPECT_THAT(gotResults[0].prop->value.int32Values, ElementsAre(testValue));
+}
+
+void GRPCVehicleHardwareUnitTest::generatePropertyUpdateEvent(int32_t propId, int64_t timestamp) {
+ // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+ // there.
+ auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+ EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+ EXPECT_CALL(*clientReader, Read(_))
+ .WillOnce([timestamp, propId](proto::VehiclePropValues* values) {
+ values->Clear();
+ auto value = values->add_values();
+ value->set_timestamp(timestamp);
+ value->set_prop(propId);
+ return true;
+ })
+ .WillOnce(Return(false));
+ EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+ pollValue();
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestGetValuesOutdatedRetry) {
+ int64_t startTimestamp = elapsedRealtimeNano();
+ int64_t testRequestId = 1234;
+ int32_t testPropId = 4321;
+ int32_t testValue1 = 123456;
+ int32_t testValue2 = 654321;
+ int32_t testTimestamp1 = 1000;
+ int32_t testTimestamp2 = 2000;
+
+ // A property update event for testTimestamp2 happens before getValues returns.
+ generatePropertyUpdateEvent(testPropId, testTimestamp2);
+
+ // GetValues first returns an outdated result, then an up-to-date result.
+ EXPECT_CALL(*mGrpcStub, GetValues(_, _, _))
+ .WillOnce([testRequestId, testPropId, testValue1, testTimestamp1](
+ ::grpc::ClientContext* context,
+ const proto::VehiclePropValueRequests& request,
+ proto::GetValueResults* response) {
+ response->Clear();
+ auto* resultPtr = response->add_results();
+ resultPtr->set_request_id(testRequestId);
+ resultPtr->set_status(proto::StatusCode::OK);
+ auto* valuePtr = resultPtr->mutable_value();
+ valuePtr->set_prop(testPropId);
+ valuePtr->set_timestamp(testTimestamp1);
+ valuePtr->add_int32_values(testValue1);
+ return ::grpc::Status::OK;
+ })
+ .WillOnce([testRequestId, testPropId, testValue2, testTimestamp2](
+ ::grpc::ClientContext* context,
+ const proto::VehiclePropValueRequests& request,
+ proto::GetValueResults* response) {
+ response->Clear();
+ auto* resultPtr = response->add_results();
+ resultPtr->set_request_id(testRequestId);
+ resultPtr->set_status(proto::StatusCode::OK);
+ auto* valuePtr = resultPtr->mutable_value();
+ valuePtr->set_prop(testPropId);
+ valuePtr->set_timestamp(testTimestamp2);
+ valuePtr->add_int32_values(testValue2);
+ return ::grpc::Status::OK;
+ });
+
+ std::vector<aidlvhal::GetValueRequest> requests;
+ requests.push_back(aidlvhal::GetValueRequest{.requestId = testRequestId,
+ .prop = {
+ .prop = testPropId,
+ }});
+
+ std::vector<aidlvhal::GetValueResult> gotResults;
+
+ auto status = mHardware->getValues(
+ std::make_shared<GRPCVehicleHardware::GetValuesCallback>(
+ [&gotResults](std::vector<aidlvhal::GetValueResult> results) {
+ for (const auto& result : results) {
+ gotResults.push_back(result);
+ }
+ }),
+ requests);
+
+ ASSERT_EQ(status, aidlvhal::StatusCode::OK);
+ ASSERT_THAT(gotResults, SizeIs(1));
+ EXPECT_EQ(gotResults[0].requestId, testRequestId);
+ EXPECT_EQ(gotResults[0].status, aidlvhal::StatusCode::OK);
+ EXPECT_EQ(gotResults[0].prop->prop, testPropId);
+ EXPECT_THAT(gotResults[0].prop->value.int32Values, ElementsAre(testValue2));
+ EXPECT_GT(gotResults[0].prop->timestamp, startTimestamp);
+ EXPECT_LT(gotResults[0].prop->timestamp, elapsedRealtimeNano());
+}
+
} // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index f48bb2a..90a7c46 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -337,6 +337,9 @@
// This is for debug purpose only.
android::base::Result<int32_t> stringToPropId(const std::string& propName);
+// This is for debug purpose only. Converts an area's name to its enum definition.
+android::base::Result<int32_t> stringToArea(const std::string& areaName, int32_t propId);
+
template <typename T>
void roundToNearestResolution(std::vector<T>& arrayToSanitize, float resolution) {
if (resolution == 0) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
index 4d06e4e..7814c99 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -25,7 +25,13 @@
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
using ::aidl::android::hardware::automotive::vehicle::toString;
+using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaDoor;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaSeat;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWheel;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
@@ -44,7 +50,7 @@
return instance;
}
- Result<int32_t> getPropertyId(const std::string& name) {
+ Result<int32_t> getPropertyId(const std::string& name) const {
auto it = mPropertyIdByName.find(name);
if (it == mPropertyIdByName.end()) {
return Error();
@@ -66,6 +72,52 @@
}
};
+class AreaByNameSingleton {
+ public:
+ static AreaByNameSingleton& getInstance() {
+ static AreaByNameSingleton instance;
+ return instance;
+ }
+
+ Result<int32_t> getArea(const std::string& name, int32_t propId) const {
+ VehicleArea areaType = getPropArea(propId);
+
+ auto mapIt = mAreaByNameByAreaType.find(areaType);
+ if (mapIt == mAreaByNameByAreaType.end()) {
+ return Error() << "Invalid area type for property ID: " << propIdToString(propId);
+ }
+
+ const auto& areaByName = mapIt->second;
+ auto it = areaByName.find(name);
+ if (it == areaByName.end()) {
+ return Error() << "Invalid area name for property " << propIdToString(propId) << ": "
+ << name;
+ }
+ return it->second;
+ }
+
+ AreaByNameSingleton(AreaByNameSingleton const&) = delete;
+ void operator=(AreaByNameSingleton const&) = delete;
+
+ private:
+ std::unordered_map<VehicleArea, std::unordered_map<std::string, int32_t>> mAreaByNameByAreaType;
+
+ AreaByNameSingleton() {
+ populateMap(VehicleArea::WINDOW, ndk::internal::enum_values<VehicleAreaWindow>);
+ populateMap(VehicleArea::MIRROR, ndk::internal::enum_values<VehicleAreaMirror>);
+ populateMap(VehicleArea::SEAT, ndk::internal::enum_values<VehicleAreaSeat>);
+ populateMap(VehicleArea::DOOR, ndk::internal::enum_values<VehicleAreaDoor>);
+ populateMap(VehicleArea::WHEEL, ndk::internal::enum_values<VehicleAreaWheel>);
+ }
+
+ template <class T, std::size_t N>
+ void populateMap(VehicleArea areaType, std::array<T, N> values) {
+ for (unsigned int i = 0; i < values.size(); i++) {
+ mAreaByNameByAreaType[areaType].emplace(toString(values[i]), toInt(values[i]));
+ }
+ }
+};
+
} // namespace
Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
@@ -254,6 +306,10 @@
return PropertyIdByNameSingleton::getInstance().getPropertyId(propName);
}
+Result<int32_t> stringToArea(const std::string& areaName, int32_t propId) {
+ return AreaByNameSingleton::getInstance().getArea(areaName, propId);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index fa2a310..b58d0f5 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -31,6 +31,7 @@
#include <android-base/thread_annotations.h>
#include <android/binder_auto_utils.h>
+#include <functional>
#include <memory>
#include <mutex>
#include <shared_mutex>
@@ -138,12 +139,11 @@
// Only used for testing.
int32_t mTestInterfaceVersion = 0;
- // mConfigsByPropId and mConfigFile is lazy initialized.
- mutable std::mutex mConfigInitLock;
- mutable bool mConfigInit GUARDED_BY(mConfigInitLock) = false;
+ mutable std::atomic<bool> mConfigInit = false;
+ mutable std::shared_timed_mutex mConfigLock;
mutable std::unordered_map<int32_t, aidlvhal::VehiclePropConfig> mConfigsByPropId
- GUARDED_BY(mConfigInitLock);
- mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigInitLock);
+ GUARDED_BY(mConfigLock);
+ mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigLock);
std::mutex mLock;
std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
@@ -175,7 +175,10 @@
android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
const std::vector<aidlvhal::SetValueRequest>& requests);
- VhalResult<void> checkSubscribeOptions(const std::vector<aidlvhal::SubscribeOptions>& options);
+ VhalResult<void> checkSubscribeOptions(
+ const std::vector<aidlvhal::SubscribeOptions>& options,
+ const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& configsByPropId)
+ REQUIRES_SHARED(mConfigLock);
VhalResult<void> checkPermissionHelper(const aidlvhal::VehiclePropValue& value,
aidlvhal::VehiclePropertyAccess accessToTest) const;
@@ -184,7 +187,7 @@
VhalResult<void> checkWritePermission(const aidlvhal::VehiclePropValue& value) const;
- android::base::Result<const aidlvhal::VehiclePropConfig*> getConfig(int32_t propId) const;
+ android::base::Result<aidlvhal::VehiclePropConfig> getConfig(int32_t propId) const;
void onBinderDiedWithContext(const AIBinder* clientId);
@@ -196,7 +199,7 @@
bool checkDumpPermission();
- bool getAllPropConfigsFromHardwareLocked() const REQUIRES(mConfigInitLock);
+ bool getAllPropConfigsFromHardwareLocked() const EXCLUDES(mConfigLock);
// The looping handler function to process all onBinderDied or onBinderUnlinked events in
// mBinderEvents.
@@ -209,10 +212,12 @@
int32_t getVhalInterfaceVersion() const;
- // Gets mConfigsByPropId, lazy init it if necessary.
- const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& getConfigsByPropId() const;
- // Gets mConfigFile, lazy init it if necessary.
- const ndk::ScopedFileDescriptor* getConfigFile() const;
+ // Gets mConfigsByPropId, lazy init it if necessary. Note that the reference is only valid in
+ // the scope of the callback and it is guaranteed that read lock is obtained during the
+ // callback.
+ void getConfigsByPropId(
+ std::function<void(const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>&)>
+ callback) const EXCLUDES(mConfigLock);
// Puts the property change events into a queue so that they can handled in batch.
static void batchPropertyChangeEvent(
@@ -239,6 +244,12 @@
static void onBinderUnlinked(void* cookie);
+ static void parseSubscribeOptions(
+ const std::vector<aidlvhal::SubscribeOptions>& options,
+ const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& configsByPropId,
+ std::vector<aidlvhal::SubscribeOptions>& onChangeSubscriptions,
+ std::vector<aidlvhal::SubscribeOptions>& continuousSubscriptions);
+
// Test-only
// Set the default timeout for pending requests.
void setTimeout(int64_t timeoutInNano);
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 9dc039d..e062a28 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -95,6 +95,18 @@
return sampleRateHz;
}
+class SCOPED_CAPABILITY SharedScopedLockAssertion {
+ public:
+ SharedScopedLockAssertion(std::shared_timed_mutex& mutex) ACQUIRE_SHARED(mutex) {}
+ ~SharedScopedLockAssertion() RELEASE() {}
+};
+
+class SCOPED_CAPABILITY UniqueScopedLockAssertion {
+ public:
+ UniqueScopedLockAssertion(std::shared_timed_mutex& mutex) ACQUIRE(mutex) {}
+ ~UniqueScopedLockAssertion() RELEASE() {}
+};
+
} // namespace
DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware)
@@ -355,68 +367,82 @@
}
filteredConfigs.push_back(std::move(config));
}
- for (auto& config : filteredConfigs) {
- mConfigsByPropId[config.prop] = config;
- }
- VehiclePropConfigs vehiclePropConfigs;
- vehiclePropConfigs.payloads = std::move(filteredConfigs);
- auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
- if (!result.ok()) {
- ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
- result.error().message().c_str(), static_cast<int>(result.error().code()));
- mConfigFile = nullptr;
- return false;
+
+ {
+ std::unique_lock<std::shared_timed_mutex> configWriteLock(mConfigLock);
+ UniqueScopedLockAssertion lockAssertion(mConfigLock);
+
+ for (auto& config : filteredConfigs) {
+ mConfigsByPropId[config.prop] = config;
+ }
+ VehiclePropConfigs vehiclePropConfigs;
+ vehiclePropConfigs.payloads = std::move(filteredConfigs);
+ auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
+ if (!result.ok()) {
+ ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
+ result.error().message().c_str(), static_cast<int>(result.error().code()));
+ mConfigFile = nullptr;
+ return false;
+ }
+
+ if (result.value() != nullptr) {
+ mConfigFile = std::move(result.value());
+ }
}
- if (result.value() != nullptr) {
- mConfigFile = std::move(result.value());
- }
+ mConfigInit = true;
return true;
}
-const ScopedFileDescriptor* DefaultVehicleHal::getConfigFile() const {
- std::scoped_lock lockGuard(mConfigInitLock);
+void DefaultVehicleHal::getConfigsByPropId(
+ std::function<void(const std::unordered_map<int32_t, VehiclePropConfig>&)> callback) const {
if (!mConfigInit) {
CHECK(getAllPropConfigsFromHardwareLocked())
<< "Failed to get property configs from hardware";
- mConfigInit = true;
}
- return mConfigFile.get();
-}
-const std::unordered_map<int32_t, VehiclePropConfig>& DefaultVehicleHal::getConfigsByPropId()
- const {
- std::scoped_lock lockGuard(mConfigInitLock);
- if (!mConfigInit) {
- CHECK(getAllPropConfigsFromHardwareLocked())
- << "Failed to get property configs from hardware";
- mConfigInit = true;
- }
- return mConfigsByPropId;
+ std::shared_lock<std::shared_timed_mutex> configReadLock(mConfigLock);
+ SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+ callback(mConfigsByPropId);
}
ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
- const ScopedFileDescriptor* configFile = getConfigFile();
- const auto& configsByPropId = getConfigsByPropId();
- if (configFile != nullptr) {
+ if (!mConfigInit) {
+ CHECK(getAllPropConfigsFromHardwareLocked())
+ << "Failed to get property configs from hardware";
+ }
+
+ std::shared_lock<std::shared_timed_mutex> configReadLock(mConfigLock);
+ SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+ if (mConfigFile != nullptr) {
output->payloads.clear();
- output->sharedMemoryFd.set(dup(configFile->get()));
+ output->sharedMemoryFd.set(dup(mConfigFile->get()));
return ScopedAStatus::ok();
}
- output->payloads.reserve(configsByPropId.size());
- for (const auto& [_, config] : configsByPropId) {
+
+ output->payloads.reserve(mConfigsByPropId.size());
+ for (const auto& [_, config] : mConfigsByPropId) {
output->payloads.push_back(config);
}
return ScopedAStatus::ok();
}
-Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
- const auto& configsByPropId = getConfigsByPropId();
- auto it = configsByPropId.find(propId);
- if (it == configsByPropId.end()) {
- return Error() << "no config for property, ID: " << propId;
- }
- return &(it->second);
+Result<VehiclePropConfig> DefaultVehicleHal::getConfig(int32_t propId) const {
+ Result<VehiclePropConfig> result;
+ getConfigsByPropId([this, &result, propId](const auto& configsByPropId) {
+ SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+ auto it = configsByPropId.find(propId);
+ if (it == configsByPropId.end()) {
+ result = Error() << "no config for property, ID: " << propId;
+ return;
+ }
+ // Copy the VehiclePropConfig
+ result = it->second;
+ });
+ return result;
}
Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
@@ -425,15 +451,15 @@
if (!result.ok()) {
return result.error();
}
- const VehiclePropConfig* config = result.value();
- const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, *config);
+ const VehiclePropConfig& config = result.value();
+ const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, config);
if (!isGlobalProp(propId) && areaConfig == nullptr) {
// Ignore areaId for global property. For non global property, check whether areaId is
// allowed. areaId must appear in areaConfig.
return Error() << "invalid area ID: " << propValue.areaId << " for prop ID: " << propId
<< ", not listed in config";
}
- if (auto result = checkPropValue(propValue, config); !result.ok()) {
+ if (auto result = checkPropValue(propValue, &config); !result.ok()) {
return Error() << "invalid property value: " << propValue.toString()
<< ", error: " << getErrorMsg(result);
}
@@ -659,17 +685,27 @@
ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
VehiclePropConfigs* output) {
std::vector<VehiclePropConfig> configs;
- const auto& configsByPropId = getConfigsByPropId();
- for (int32_t prop : props) {
- auto it = configsByPropId.find(prop);
- if (it != configsByPropId.end()) {
- configs.push_back(it->second);
- } else {
- return ScopedAStatus::fromServiceSpecificErrorWithMessage(
- toInt(StatusCode::INVALID_ARG),
- StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
+ ScopedAStatus status = ScopedAStatus::ok();
+ getConfigsByPropId([this, &configs, &status, &props](const auto& configsByPropId) {
+ SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+ for (int32_t prop : props) {
+ auto it = configsByPropId.find(prop);
+ if (it != configsByPropId.end()) {
+ configs.push_back(it->second);
+ } else {
+ status = ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ toInt(StatusCode::INVALID_ARG),
+ StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
+ return;
+ }
}
+ });
+
+ if (!status.isOk()) {
+ return status;
}
+
return vectorToStableLargeParcelable(std::move(configs), output);
}
@@ -691,8 +727,8 @@
}
VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
- const std::vector<SubscribeOptions>& options) {
- const auto& configsByPropId = getConfigsByPropId();
+ const std::vector<SubscribeOptions>& options,
+ const std::unordered_map<int32_t, VehiclePropConfig>& configsByPropId) {
for (const auto& option : options) {
int32_t propId = option.propId;
auto it = configsByPropId.find(propId);
@@ -757,23 +793,15 @@
}
}
}
+
return {};
}
-ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
- const std::vector<SubscribeOptions>& options,
- [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
- // TODO(b/205189110): Use shared memory file count.
- if (callback == nullptr) {
- return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
- }
- if (auto result = checkSubscribeOptions(options); !result.ok()) {
- ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
- return toScopedAStatus(result);
- }
- std::vector<SubscribeOptions> onChangeSubscriptions;
- std::vector<SubscribeOptions> continuousSubscriptions;
- const auto& configsByPropId = getConfigsByPropId();
+void DefaultVehicleHal::parseSubscribeOptions(
+ const std::vector<SubscribeOptions>& options,
+ const std::unordered_map<int32_t, VehiclePropConfig>& configsByPropId,
+ std::vector<SubscribeOptions>& onChangeSubscriptions,
+ std::vector<SubscribeOptions>& continuousSubscriptions) {
for (const auto& option : options) {
int32_t propId = option.propId;
// We have already validate config exists.
@@ -831,6 +859,34 @@
onChangeSubscriptions.push_back(std::move(optionCopy));
}
}
+}
+
+ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
+ const std::vector<SubscribeOptions>& options,
+ [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
+ // TODO(b/205189110): Use shared memory file count.
+ if (callback == nullptr) {
+ return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+ std::vector<SubscribeOptions> onChangeSubscriptions;
+ std::vector<SubscribeOptions> continuousSubscriptions;
+ ScopedAStatus returnStatus = ScopedAStatus::ok();
+ getConfigsByPropId([this, &returnStatus, &options, &onChangeSubscriptions,
+ &continuousSubscriptions](const auto& configsByPropId) {
+ SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+ if (auto result = checkSubscribeOptions(options, configsByPropId); !result.ok()) {
+ ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
+ returnStatus = toScopedAStatus(result);
+ return;
+ }
+ parseSubscribeOptions(options, configsByPropId, onChangeSubscriptions,
+ continuousSubscriptions);
+ });
+
+ if (!returnStatus.isOk()) {
+ return returnStatus;
+ }
{
// Lock to make sure onBinderDied would not be called concurrently.
@@ -891,13 +947,13 @@
return StatusError(StatusCode::INVALID_ARG) << getErrorMsg(result);
}
- const VehiclePropConfig* config = result.value();
- const VehicleAreaConfig* areaConfig = getAreaConfig(value, *config);
+ const VehiclePropConfig& config = result.value();
+ const VehicleAreaConfig* areaConfig = getAreaConfig(value, config);
if (areaConfig == nullptr && !isGlobalProp(propId)) {
return StatusError(StatusCode::INVALID_ARG) << "no config for area ID: " << value.areaId;
}
- if (!hasRequiredAccess(config->access, accessToTest) &&
+ if (!hasRequiredAccess(config.access, accessToTest) &&
(areaConfig == nullptr || !hasRequiredAccess(areaConfig->access, accessToTest))) {
return StatusError(StatusCode::ACCESS_DENIED)
<< StringPrintf("Property %" PRId32 " does not have the following access: %" PRId32,
@@ -966,7 +1022,6 @@
}
DumpResult result = mVehicleHardware->dump(options);
if (result.refreshPropertyConfigs) {
- std::scoped_lock lockGuard(mConfigInitLock);
getAllPropConfigsFromHardwareLocked();
}
dprintf(fd, "%s", (result.buffer + "\n").c_str());
@@ -974,11 +1029,16 @@
return STATUS_OK;
}
dprintf(fd, "Vehicle HAL State: \n");
- const auto& configsByPropId = getConfigsByPropId();
+ std::unordered_map<int32_t, VehiclePropConfig> configsByPropIdCopy;
+ getConfigsByPropId([this, &configsByPropIdCopy](const auto& configsByPropId) {
+ SharedScopedLockAssertion lockAssertion(mConfigLock);
+
+ configsByPropIdCopy = configsByPropId;
+ });
{
std::scoped_lock<std::mutex> lockGuard(mLock);
dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
- dprintf(fd, "Containing %zu property configs\n", configsByPropId.size());
+ dprintf(fd, "Containing %zu property configs\n", configsByPropIdCopy.size());
dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
diff --git a/bluetooth/a2dp/1.0/Android.bp b/bluetooth/a2dp/1.0/Android.bp
deleted file mode 100644
index 6ffbefa..0000000
--- a/bluetooth/a2dp/1.0/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "hardware_interfaces_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-hidl_interface {
- name: "android.hardware.bluetooth.a2dp@1.0",
- root: "android.hardware",
- srcs: [
- "types.hal",
- "IBluetoothAudioHost.hal",
- "IBluetoothAudioOffload.hal",
- ],
- interfaces: [
- "android.hidl.base@1.0",
- ],
- gen_java: false,
- apex_available: [
- "//apex_available:platform",
- "com.android.btservices",
- ],
-}
diff --git a/bluetooth/a2dp/1.0/IBluetoothAudioHost.hal b/bluetooth/a2dp/1.0/IBluetoothAudioHost.hal
deleted file mode 100644
index 666419d..0000000
--- a/bluetooth/a2dp/1.0/IBluetoothAudioHost.hal
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.a2dp@1.0;
-
-/**
- * HAL interface for Bluetooth A2DP Offload functionality where
- * the encoding of the A2DP data packets is offloaded to platform
- * specific encoders. The A2DP control path is maintained in the
- * Bluetooth stack.
- *
- * This interface is from HAL server to HAL client.
- *
- * The HAL server must call into the IBluetoothAudioHost to initiate
- * the start, suspend and stop of the streaming operation. These
- * calls return immediately and the results, if any, are send over
- * the IBluetoothAudioOffload interface.
- */
-
-interface IBluetoothAudioHost {
- /**
- * Invoked when the start stream is requested from HAL server
- * to HAL client. This indicates that the HAL server
- * has initialized the platform for streaming use case, and the
- * HAL client can proceed with the streaming procedure. The
- * result of the operation must be provided by the HAL
- * client using the IBluetoothAudioOffload interface.
- */
- oneway startStream();
-
- /**
- * Invoked when the suspend stream is requested from HAL server
- * to HAL client. This indicates that the HAL server
- * wants to suspend the streaming procedure. The result of the
- * operation must be provided by the HAL client using the
- * IBluetoothAudioOffload interface.
- */
- oneway suspendStream();
-
- /**
- * Invoked when the stop stream is requested from HAL server
- * to HAL client. This indicates that the HAL server wants to
- * stop and reset the streaming procedure. There is no result
- * provided by the HAL client for this call.
- */
- oneway stopStream();
-
-};
diff --git a/bluetooth/a2dp/1.0/IBluetoothAudioOffload.hal b/bluetooth/a2dp/1.0/IBluetoothAudioOffload.hal
deleted file mode 100644
index 52a580f..0000000
--- a/bluetooth/a2dp/1.0/IBluetoothAudioOffload.hal
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.a2dp@1.0;
-
-import IBluetoothAudioHost;
-
-/**
- * HAL interface for Bluetooth A2DP Offload functionality where
- * the encoding of the A2DP data packets is offloaded to platform
- * specific encoders. The A2DP control path is maintained in the
- * Bluetooth stack.
- *
- * This interface is from HAL client to HAL server.
- *
- * The HAL client must provide the handle of IBluetoothAudioHost as well
- * as codec configuration to the HAL server, when its connected to an
- * active A2DP Sink device. HAL Server, based on the feedback from the Audio
- * framework must call into the commands provided by the IBluetoothAudioHost.
- * HAL client must call into IBluetoothAudioOffload to provide the status of
- * these commands. Once the device becomes inactive, the HAL client must
- * call the endSession to terminate the session with the HAL server.
- */
-interface IBluetoothAudioOffload {
-
- /**
- * Indicates that the HAL client is connected to an A2DP Sink device
- * and is ready to stream audio. This function is also used to register
- * the BluetoothAudioHost interface and the provide the current negotiated
- * codec.
- *
- * |endSession| must be called to unregister the interface.
- *
- * @param hostIf interface used to request stream control
- * @param codecConfig Codec configuration as negotiated with the A2DP Sink
- * device
- * @return status one of the following
- * SUCCESS if HAL server successfully initializes the platform with the
- * given codec configuration
- * UNSUPPORTED_CODEC_CONFIGURATION if HAL server cannot initialize the
- * platform with the given codec configuration
- * FAILURE if HAL server cannot initialize the platform for any other
- * reason
- */
- startSession(IBluetoothAudioHost hostIf, CodecConfiguration codecConfig) generates (Status status);
-
- /**
- * Updates status for start stream request. The HAL client may need
- * to communicate to Bluetooth Controller and remote Sink device, in which
- * case it must update with PENDING status. Once the operation is
- * completed, it must return with either SUCCESS or FAILURE.
- *
- * @param status SUCCESS, FAILURE or PENDING
- */
- oneway streamStarted(Status status);
-
- /**
- * Updates status for suspend stream request. The HAL client may need
- * to communicate to Bluetooth Controller and remote device, in which case
- * it must update with PENDING status. Once the operation is completed, it
- * must return with either SUCCESS or FAILURE.
- *
- * @param status SUCCESS, FAILURE or PENDING
- */
- oneway streamSuspended(Status status);
-
- /**
- * Ends the current A2DP offload session and unregisters the
- * BluetoothAudioHost interface.
- */
- oneway endSession();
-};
diff --git a/bluetooth/a2dp/1.0/default/Android.bp b/bluetooth/a2dp/1.0/default/Android.bp
deleted file mode 100644
index f368dd4..0000000
--- a/bluetooth/a2dp/1.0/default/Android.bp
+++ /dev/null
@@ -1,22 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "hardware_interfaces_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_library_shared {
- name: "android.hardware.bluetooth.a2dp@1.0-impl.mock",
- relative_install_path: "hw",
- vendor: true,
- srcs: [
- "BluetoothAudioOffload.cpp",
- ],
- shared_libs: [
- "libhidlbase",
- "libutils",
- "android.hardware.bluetooth.a2dp@1.0",
- ],
-}
diff --git a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp
deleted file mode 100644
index 9abb88d..0000000
--- a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BluetoothAudioOffload.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace a2dp {
-namespace V1_0 {
-namespace implementation {
-
-IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(
- const char* /* name */) {
- return new BluetoothAudioOffload();
-}
-
-// Methods from
-// ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
-Return<::android::hardware::bluetooth::a2dp::V1_0::Status>
-BluetoothAudioOffload::startSession(
- const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>&
- hostIf __unused,
- const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration&
- codecConfig __unused) {
- /**
- * Initialize the audio platform if codecConfiguration is supported.
- * Save the the IBluetoothAudioHost interface, so that it can be used
- * later to send stream control commands to the HAL client, based on
- * interaction with Audio framework.
- */
- return ::android::hardware::bluetooth::a2dp::V1_0::Status::FAILURE;
-}
-
-Return<void> BluetoothAudioOffload::streamStarted(
- ::android::hardware::bluetooth::a2dp::V1_0::Status status __unused) {
- /**
- * Streaming on control path has started,
- * HAL server should start the streaming on data path.
- */
- return Void();
-}
-
-Return<void> BluetoothAudioOffload::streamSuspended(
- ::android::hardware::bluetooth::a2dp::V1_0::Status status __unused) {
- /**
- * Streaming on control path has suspend,
- * HAL server should suspend the streaming on data path.
- */
- return Void();
-}
-
-Return<void> BluetoothAudioOffload::endSession() {
- /**
- * Cleanup the audio platform as remote A2DP Sink device is no
- * longer active
- */
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace a2dp
-} // namespace bluetooth
-} // namespace hardware
-} // namespace android
diff --git a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h b/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h
deleted file mode 100644
index 16a83c2..0000000
--- a/bluetooth/a2dp/1.0/default/BluetoothAudioOffload.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_BLUETOOTH_A2DP_V1_0_BLUETOOTHAUDIOOFFLOAD_H
-#define ANDROID_HARDWARE_BLUETOOTH_A2DP_V1_0_BLUETOOTHAUDIOOFFLOAD_H
-
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace a2dp {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-struct BluetoothAudioOffload : public IBluetoothAudioOffload {
- BluetoothAudioOffload() {}
- // Methods from
- // ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload follow.
- Return<::android::hardware::bluetooth::a2dp::V1_0::Status> startSession(
- const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>&
- hostIf,
- const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration&
- codecConfig) override;
- Return<void> streamStarted(
- ::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
- Return<void> streamSuspended(
- ::android::hardware::bluetooth::a2dp::V1_0::Status status) override;
- Return<void> endSession() override;
-};
-
-extern "C" IBluetoothAudioOffload* HIDL_FETCH_IBluetoothAudioOffload(
- const char* name);
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace a2dp
-} // namespace bluetooth
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_BLUETOOTH_A2DP_V1_0_BLUETOOTHAUDIOOFFLOAD_H
diff --git a/bluetooth/a2dp/1.0/types.hal b/bluetooth/a2dp/1.0/types.hal
deleted file mode 100644
index 6a430f0..0000000
--- a/bluetooth/a2dp/1.0/types.hal
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.a2dp@1.0;
-
-enum Status : uint8_t {
- SUCCESS,
- FAILURE,
- /** codec configuration not supported by the audio platform */
- UNSUPPORTED_CODEC_CONFIGURATION ,
- /** operation is pending */
- PENDING,
-};
-
-enum CodecType : uint32_t {
- UNKNOWN = 0x00,
- SBC = 0x01,
- AAC = 0x02,
- APTX = 0x04,
- APTX_HD = 0x08,
- LDAC = 0x10,
-};
-enum SampleRate : uint32_t {
- RATE_UNKNOWN = 0x00,
- RATE_44100 = 0x01,
- RATE_48000 = 0x02,
- RATE_88200 = 0x04,
- RATE_96000 = 0x08,
- RATE_176400 = 0x10,
- RATE_192000 = 0x20,
-};
-enum BitsPerSample : uint8_t {
- BITS_UNKNOWN = 0x00,
- BITS_16 = 0x01,
- BITS_24 = 0x02,
- BITS_32 = 0x04,
-};
-enum ChannelMode : uint8_t {
- UNKNOWN = 0x00,
- MONO = 0x01,
- STEREO = 0x02,
-};
-struct CodecConfiguration {
- /** Bluetooth A2DP codec */
- CodecType codecType;
- /** Sampling rate for encoder */
- SampleRate sampleRate;
- /** Bits per sample for encoder */
- BitsPerSample bitsPerSample;
- /** Channel mode for encoder */
- ChannelMode channelMode;
- /**
- * The encoded audio bitrate in bits / second.
- * 0x00000000 - The audio bitrate is not specified / unused
- * 0x00000001 - 0x00FFFFFF - Encoded audio bitrate in bits/second
- * 0x01000000 - 0xFFFFFFFF - Reserved
- */
- uint32_t encodedAudioBitrate;
- /** Peer MTU (in octets) */
- uint16_t peerMtu;
- union CodecSpecific {
- /**
- * SBC Codec specific information
- * Refer to SBC Codec specific information elements in A2DP v1.3
- * Profile Specification.
- */
- struct SbcData {
- /** Block length: 4 bits | Subbands: 2 bits | Allocation Method: 2 bits */
- uint8_t codecParameters;
- /** Minimum bitpool value */
- uint8_t minBitpool;
- /** Maximum bitpool value */
- uint8_t maxBitpool;
- } sbcData;
- struct LdacData {
- /**
- * LDAC bitrate index value:
- * 0x00 - High
- * 0x01 - Mid
- * 0x02 - Low
- * 0x7F - ABR (Adaptive Bit Rate)
- */
- uint8_t bitrateIndex;
- } ldacData;
- } codecSpecific;
-};
diff --git a/bluetooth/a2dp/1.0/vts/OWNERS b/bluetooth/a2dp/1.0/vts/OWNERS
deleted file mode 100644
index d3aab51..0000000
--- a/bluetooth/a2dp/1.0/vts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 27441
-include platform/packages/modules/Bluetooth:/OWNERS
-
-cheneyni@google.com
diff --git a/bluetooth/a2dp/1.0/vts/functional/Android.bp b/bluetooth/a2dp/1.0/vts/functional/Android.bp
deleted file mode 100644
index 0d393bc..0000000
--- a/bluetooth/a2dp/1.0/vts/functional/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "hardware_interfaces_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_test {
- name: "VtsHalBluetoothA2dpV1_0TargetTest",
- defaults: ["VtsHalTargetTestDefaults"],
- srcs: ["VtsHalBluetoothA2dpV1_0TargetTest.cpp"],
- static_libs: [
- "android.hardware.bluetooth@1.0",
- "android.hardware.bluetooth.a2dp@1.0",
- "libbluetooth-types",
- ],
- test_suites: ["general-tests", "vts"],
-}
diff --git a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp b/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp
deleted file mode 100644
index f7fdf31..0000000
--- a/bluetooth/a2dp/1.0/vts/functional/VtsHalBluetoothA2dpV1_0TargetTest.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "bluetooth_a2dp_hidl_hal_test"
-
-#include <android-base/logging.h>
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioHost.h>
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
-#include <gtest/gtest.h>
-#include <hardware/bluetooth.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/ServiceManagement.h>
-#include <utils/Log.h>
-
-#include <VtsHalHidlTargetCallbackBase.h>
-
-using ::android::sp;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::a2dp::V1_0::BitsPerSample;
-using ::android::hardware::bluetooth::a2dp::V1_0::ChannelMode;
-using ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration;
-using ::android::hardware::bluetooth::a2dp::V1_0::CodecType;
-using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
-using ::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
-using ::android::hardware::bluetooth::a2dp::V1_0::SampleRate;
-using ::android::hardware::bluetooth::a2dp::V1_0::Status;
-
-// The main test class for Bluetooth A2DP HIDL HAL.
-class BluetoothA2dpHidlTest : public ::testing::TestWithParam<std::string> {
- public:
- virtual void SetUp() override {
- // currently test passthrough mode only
- audio_offload = IBluetoothAudioOffload::getService(GetParam());
- ASSERT_NE(audio_offload, nullptr);
-
- audio_host = new BluetoothAudioHost(*this);
- ASSERT_NE(audio_host, nullptr);
-
- codec.codecType = CodecType::AAC;
- codec.sampleRate = SampleRate::RATE_44100;
- codec.bitsPerSample = BitsPerSample::BITS_16;
- codec.channelMode = ChannelMode::STEREO;
- codec.encodedAudioBitrate = 320000;
- codec.peerMtu = 1000;
- }
-
- virtual void TearDown() override {}
-
- // A simple test implementation of IBluetoothAudioHost.
- class BluetoothAudioHost
- : public ::testing::VtsHalHidlTargetCallbackBase<BluetoothA2dpHidlTest>,
- public IBluetoothAudioHost {
- BluetoothA2dpHidlTest& parent_;
-
- public:
- BluetoothAudioHost(BluetoothA2dpHidlTest& parent) : parent_(parent){};
- virtual ~BluetoothAudioHost() = default;
-
- Return<void> startStream() override {
- parent_.audio_offload->streamStarted(Status::SUCCESS);
- return Void();
- };
-
- Return<void> suspendStream() override {
- parent_.audio_offload->streamSuspended(Status::SUCCESS);
- return Void();
- };
-
- Return<void> stopStream() override { return Void(); };
- };
-
- // audio_host is for the Audio HAL to send stream start/suspend/stop commands
- // to Bluetooth
- sp<IBluetoothAudioHost> audio_host;
- // audio_offload is for the Bluetooth HAL to report session started/ended and
- // handled audio stream started/suspended
- sp<IBluetoothAudioOffload> audio_offload;
- // codec is the currently used codec
- CodecConfiguration codec;
-};
-
-// Empty test: Initialize()/Close() are called in SetUp()/TearDown().
-TEST_P(BluetoothA2dpHidlTest, InitializeAndClose) {}
-
-// Test start and end session
-TEST_P(BluetoothA2dpHidlTest, StartAndEndSession) {
- EXPECT_EQ(Status::SUCCESS, audio_offload->startSession(audio_host, codec));
- audio_offload->endSession();
-}
-
-INSTANTIATE_TEST_SUITE_P(
- PerInstance, BluetoothA2dpHidlTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(
- IBluetoothAudioOffload::descriptor)),
- android::hardware::PrintInstanceNameToString);
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothA2dpHidlTest);
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index f273c7a..ae55fa9 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -85,12 +85,12 @@
},
],
- frozen: true,
+ frozen: false,
}
// Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_bluetooth_audio = "android.hardware.bluetooth.audio-V4"
+latest_android_hardware_bluetooth_audio = "android.hardware.bluetooth.audio-V5"
cc_defaults {
name: "latest_android_hardware_bluetooth_audio_ndk_shared",
diff --git a/bluetooth/audio/aidl/default/bluetooth_audio.xml b/bluetooth/audio/aidl/default/bluetooth_audio.xml
index 3561dd1..767bf8f 100644
--- a/bluetooth/audio/aidl/default/bluetooth_audio.xml
+++ b/bluetooth/audio/aidl/default/bluetooth_audio.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.bluetooth.audio</name>
- <version>4</version>
+ <version>5</version>
<fqname>IBluetoothAudioProviderFactory/default</fqname>
</hal>
</manifest>
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index e83cb9e..110a628 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -195,6 +195,17 @@
}
}
+static std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+ const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+ CodecSpecificConfigurationLtv::Tag tag) {
+ for (const auto ltv : configurationLtvs) {
+ if (ltv.getTag() == tag) {
+ return ltv;
+ }
+ }
+ return std::nullopt;
+}
+
class BluetoothAudioPort : public BnBluetoothAudioPort {
public:
BluetoothAudioPort() {}
@@ -2393,17 +2404,6 @@
return capability;
}
- std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
- const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
- CodecSpecificConfigurationLtv::Tag tag) {
- for (const auto ltv : configurationLtvs) {
- if (ltv.getTag() == tag) {
- return ltv;
- }
- }
- return std::nullopt;
- }
-
bool IsAseRequirementSatisfiedWithUnknownChannelCount(
const std::vector<std::optional<AseDirectionRequirement>>&
ase_requirements,
@@ -2560,6 +2560,67 @@
return (num_of_satisfied_ase_requirements == ase_requirements.size());
}
+ static void VerifyCodecParameters(
+ ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+ LeAudioAseConfigurationSetting::AseDirectionConfiguration config) {
+ ASSERT_NE(config.aseConfiguration.codecConfiguration.size(), 0lu);
+ ASSERT_TRUE(config.qosConfiguration.has_value());
+
+ int32_t frame_blocks = 1; // by default 1 if not set
+ int8_t frame_duration = 0;
+ int32_t octets_per_frame = 0;
+ std::bitset<32> allocation_bitmask = 0;
+
+ for (auto const& param : config.aseConfiguration.codecConfiguration) {
+ if (param.getTag() ==
+ ::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU) {
+ frame_blocks = param
+ .get<::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::
+ codecFrameBlocksPerSDU>()
+ .value;
+ } else if (param.getTag() ==
+ ::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::frameDuration) {
+ frame_duration = static_cast<int8_t>(
+ param.get<::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::frameDuration>());
+ } else if (param.getTag() ==
+ ::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame) {
+ octets_per_frame = static_cast<int32_t>(
+ param
+ .get<::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::
+ octetsPerCodecFrame>()
+ .value);
+ } else if (param.getTag() == ::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::
+ audioChannelAllocation) {
+ allocation_bitmask = static_cast<int32_t>(
+ param
+ .get<::aidl::android::hardware::bluetooth::audio::
+ CodecSpecificConfigurationLtv::Tag::
+ audioChannelAllocation>()
+ .bitmask);
+ }
+ }
+
+ ASSERT_NE(frame_blocks, 0);
+ ASSERT_NE(frame_duration, 0);
+ ASSERT_NE(octets_per_frame, 0);
+
+ auto const num_channels_per_cis = allocation_bitmask.count();
+ ASSERT_NE(num_channels_per_cis, 0);
+
+ // Verify if QoS takes the codec frame blocks per SDU into the account
+ ASSERT_TRUE(config.qosConfiguration->sduIntervalUs >=
+ frame_blocks * frame_duration);
+ ASSERT_TRUE(config.qosConfiguration->maxSdu >=
+ (frame_blocks * num_channels_per_cis * octets_per_frame));
+ }
+
void VerifyIfRequirementsSatisfied(
const std::vector<LeAudioConfigurationRequirement>& requirements,
const std::vector<LeAudioAseConfigurationSetting>& configurations) {
@@ -2592,32 +2653,52 @@
continue;
}
+ bool sink_req_satisfied = false;
+ if (req.sinkAseRequirement) {
+ ASSERT_TRUE(conf.sinkAseConfiguration.has_value());
+ sink_req_satisfied = IsAseRequirementSatisfied(
+ *req.sinkAseRequirement, *conf.sinkAseConfiguration);
+
+ ASSERT_NE(conf.sinkAseConfiguration->size(), 0lu);
+ for (auto const& cfg : conf.sinkAseConfiguration.value()) {
+ ASSERT_TRUE(cfg.has_value());
+ VerifyCodecParameters(cfg.value());
+ }
+ }
+
+ bool source_req_satisfied = false;
+ if (req.sourceAseRequirement) {
+ ASSERT_TRUE(conf.sourceAseConfiguration.has_value());
+ source_req_satisfied = IsAseRequirementSatisfied(
+ *req.sourceAseRequirement, *conf.sourceAseConfiguration);
+
+ ASSERT_NE(conf.sourceAseConfiguration->size(), 0lu);
+ for (auto const& cfg : conf.sourceAseConfiguration.value()) {
+ ASSERT_TRUE(cfg.has_value());
+ VerifyCodecParameters(cfg.value());
+ }
+ }
+
if (req.sinkAseRequirement && req.sourceAseRequirement) {
if (!conf.sinkAseConfiguration || !conf.sourceAseConfiguration) {
continue;
}
- if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
- *conf.sinkAseConfiguration) ||
- !IsAseRequirementSatisfied(*req.sourceAseRequirement,
- *conf.sourceAseConfiguration)) {
+ if (!sink_req_satisfied || !source_req_satisfied) {
continue;
}
num_of_satisfied_requirements +=
std::bitset<32>(req.audioContext.bitmask).count();
-
break;
} else if (req.sinkAseRequirement) {
- if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
- *conf.sinkAseConfiguration)) {
+ if (!sink_req_satisfied) {
continue;
}
num_of_satisfied_requirements +=
std::bitset<32>(req.audioContext.bitmask).count();
break;
} else if (req.sourceAseRequirement) {
- if (!IsAseRequirementSatisfied(*req.sourceAseRequirement,
- *conf.sourceAseConfiguration)) {
+ if (!source_req_satisfied) {
continue;
}
num_of_satisfied_requirements +=
@@ -4089,17 +4170,6 @@
return media_audio_context;
}
- std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
- const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
- CodecSpecificConfigurationLtv::Tag tag) {
- for (const auto ltv : configurationLtvs) {
- if (ltv.getTag() == tag) {
- return ltv;
- }
- }
- return std::nullopt;
- }
-
std::optional<CodecSpecificConfigurationLtv::SamplingFrequency>
GetBisSampleFreq(const LeAudioBisConfiguration& bis_conf) {
auto sample_freq_ltv = GetConfigurationLtv(
diff --git a/broadcastradio/aidl/vts/Android.bp b/broadcastradio/aidl/vts/Android.bp
index 78c377d..9cfca42 100644
--- a/broadcastradio/aidl/vts/Android.bp
+++ b/broadcastradio/aidl/vts/Android.bp
@@ -44,4 +44,5 @@
"general-tests",
"vts",
],
+ disable_framework: true,
}
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index 8f7d19d..b59c92e 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -10,6 +10,7 @@
aidl_interface {
name: "android.hardware.camera.common",
+ host_supported: true,
vendor_available: true,
srcs: ["android/hardware/camera/common/*.aidl"],
frozen: true,
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 78aefac..f3a3681 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -10,6 +10,7 @@
aidl_interface {
name: "android.hardware.camera.device",
+ host_supported: true,
vendor_available: true,
srcs: ["android/hardware/camera/device/*.aidl"],
frozen: true,
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
index 62a19cf..63ae320 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
@@ -575,6 +575,11 @@
* This can be called at any point after 'processCaptureRequest' in response
* to camera clients disabling an active repeating request.
*
+ * Note: The frame number parameter is the latest possible frame number at which the
+ * ongoing repeating request will end. It is possible that the repeating request may end
+ * before the specified frame number due to reasons such as the camera client abandoning
+ * buffers, which is timing dependent.
+ *
* Performance requirements:
* The call must not be blocked for extensive periods and should be extremely lightweight. There
* must be no frame rate degradation or frame jitter introduced.
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index ae8ba14..a9c1a1a 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -10,6 +10,7 @@
aidl_interface {
name: "android.hardware.camera.metadata",
+ host_supported: true,
vendor_available: true,
srcs: ["android/hardware/camera/metadata/*.aidl"],
frozen: true,
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index 38a8936..c055caa 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -10,6 +10,7 @@
aidl_interface {
name: "android.hardware.camera.provider",
+ host_supported: true,
vendor_available: true,
srcs: [
"android/hardware/camera/provider/*.aidl",
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
index 9b36406..87c9e02 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
@@ -1,5 +1,5 @@
<manifest version="1.0" type="device">
- <hal format="hidl">
+ <hal format="hidl" max-level="7">
<name>android.hardware.cas</name>
<transport>hwbinder</transport>
<version>1.2</version>
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.xml b/cas/1.2/default/android.hardware.cas@1.2-service.xml
index 9b36406..87c9e02 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.xml
@@ -1,5 +1,5 @@
<manifest version="1.0" type="device">
- <hal format="hidl">
+ <hal format="hidl" max-level="7">
<name>android.hardware.cas</name>
<transport>hwbinder</transport>
<version>1.2</version>
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 1f5742d..904a3d9 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -20,16 +20,18 @@
backend: {
java: {
sdk_version: "module_current",
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
},
cpp: {
enabled: false,
},
ndk: {
apex_available: [
+ "//apex_available:anyapex",
"//apex_available:platform",
- "com.android.btservices",
- "com.android.media.swcodec",
- "com.android.neuralnetworks",
],
min_sdk_version: "29",
},
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 56700fa..aba5d6b 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -24,9 +24,8 @@
"libcutils",
],
apex_available: [
+ "//apex_available:anyapex",
"//apex_available:platform",
- "com.android.neuralnetworks",
- "com.android.media.swcodec",
],
min_sdk_version: "29",
}
diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index 0e714a4..ee62163 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -1,7 +1,7 @@
<compatibility-matrix version="1.0" type="framework" level="202504">
<hal format="aidl">
<name>android.hardware.audio.core</name>
- <version>1-2</version>
+ <version>1-3</version>
<interface>
<name>IModule</name>
<instance>default</instance>
@@ -20,7 +20,7 @@
</hal>
<hal format="aidl">
<name>android.hardware.audio.effect</name>
- <version>1-2</version>
+ <version>1-3</version>
<interface>
<name>IFactory</name>
<instance>default</instance>
@@ -28,7 +28,7 @@
</hal>
<hal format="aidl">
<name>android.hardware.audio.sounddose</name>
- <version>1-2</version>
+ <version>1-3</version>
<interface>
<name>ISoundDoseFactory</name>
<instance>default</instance>
@@ -44,7 +44,7 @@
</hal>
<hal format="aidl">
<name>android.hardware.automotive.audiocontrol</name>
- <version>2-4</version>
+ <version>2-5</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
@@ -132,7 +132,7 @@
</hal>
<hal format="aidl">
<name>android.hardware.bluetooth.audio</name>
- <version>3-4</version>
+ <version>3-5</version>
<interface>
<name>IBluetoothAudioProviderFactory</name>
<instance>default</instance>
@@ -542,7 +542,7 @@
</hal>
<hal format="aidl">
<name>android.hardware.soundtrigger3</name>
- <version>1-2</version>
+ <version>1-3</version>
<interface>
<name>ISoundTriggerHw</name>
<instance>default</instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 08ef49b..fca9e1c 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -164,6 +164,7 @@
// AIDL
"android.hardware.audio.core.sounddose@1",
"android.hardware.audio.core.sounddose@2",
+ "android.hardware.audio.core.sounddose@3",
// Deprecated HALs.
"android.hardware.bluetooth.audio@1",
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 4f5c3d9..c28da4c 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -24,15 +24,18 @@
java: {
enabled: true,
platform_apis: true,
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
},
cpp: {
enabled: false,
},
ndk: {
apex_available: [
+ "//apex_available:anyapex",
"//apex_available:platform",
- "com.android.media.swcodec",
- "com.android.neuralnetworks",
],
min_sdk_version: "29",
},
diff --git a/keymaster/3.0/default/Android.bp b/keymaster/3.0/default/Android.bp
new file mode 100644
index 0000000..4018cc0
--- /dev/null
+++ b/keymaster/3.0/default/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "hardware_interfaces_license",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.keymaster@3.0-impl",
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["KeymasterDevice.cpp"],
+ shared_libs: [
+ "android.hardware.keymaster@3.0",
+ "libcrypto",
+ "libhardware",
+ "libhidlbase",
+ "libkeymaster_portable",
+ "libkeymaster3device",
+ "liblog",
+ "libpuresoftkeymasterdevice",
+ "libsoftkeymasterdevice",
+ "libutils",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.keymaster@3.0-service",
+ relative_install_path: "hw",
+ proprietary: true,
+ init_rc: ["android.hardware.keymaster@3.0-service.rc"],
+ srcs: ["service.cpp"],
+ shared_libs: [
+ "android.hardware.keymaster@3.0",
+ "libbase",
+ "libcutils",
+ "libdl",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk
deleted file mode 100644
index 053ad67..0000000
--- a/keymaster/3.0/default/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.keymaster@3.0-impl
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SRC_FILES := \
- KeymasterDevice.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libsoftkeymasterdevice \
- libcrypto \
- libkeymaster_portable \
- libpuresoftkeymasterdevice \
- libkeymaster3device \
- libhidlbase \
- libutils \
- libhardware \
- android.hardware.keymaster@3.0
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE := android.hardware.keymaster@3.0-service
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_INIT_RC := android.hardware.keymaster@3.0-service.rc
-LOCAL_SRC_FILES := \
- service.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libcutils \
- libdl \
- libbase \
- libutils \
- libhardware \
- libhidlbase \
- android.hardware.keymaster@3.0
-
-include $(BUILD_EXECUTABLE)
diff --git a/security/keymint/support/fuzzer/Android.bp b/security/keymint/support/fuzzer/Android.bp
index 1b1a580..2fa82ec 100644
--- a/security/keymint/support/fuzzer/Android.bp
+++ b/security/keymint/support/fuzzer/Android.bp
@@ -48,6 +48,20 @@
],
}
+cc_defaults {
+ name: "keymint_remote_fuzzer_defaults",
+ static_libs: [
+ "libkeymint_remote_prov_support",
+ "android.hardware.security.rkp-V3-ndk",
+ ],
+ shared_libs: [
+ "libcppbor",
+ "libcppcose_rkp",
+ "libjsoncpp",
+ "libkeymaster_portable",
+ ],
+}
+
cc_fuzz {
name: "keymint_attestation_fuzzer",
srcs: [
@@ -67,3 +81,25 @@
"keymint_fuzzer_defaults",
],
}
+
+cc_fuzz {
+ name: "keymint_remote_prov_fuzzer",
+ srcs: [
+ "keymint_remote_prov_fuzzer.cpp",
+ ],
+ defaults: [
+ "keymint_fuzzer_defaults",
+ "keymint_remote_fuzzer_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "keymint_rkpsupport_fuzzer",
+ srcs: [
+ "keymint_rkpsupport_fuzzer.cpp",
+ ],
+ defaults: [
+ "keymint_fuzzer_defaults",
+ "keymint_remote_fuzzer_defaults",
+ ],
+}
diff --git a/security/keymint/support/fuzzer/README.md b/security/keymint/support/fuzzer/README.md
index d41af08..4cf6927 100644
--- a/security/keymint/support/fuzzer/README.md
+++ b/security/keymint/support/fuzzer/README.md
@@ -12,6 +12,8 @@
## Table of contents
+ [keymint_attestation_fuzzer](#KeyMintAttestation)
+ [keymint_authSet_fuzzer](#KeyMintAuthSet)
++ [keymint_remote_prov_fuzzer](#KeyMintRemoteProv)
++ [keymint_rkpsupport_fuzzer](#KeyMintRemoteKeyProvSupport)
# <a name="KeyMintAttestation"></a> Fuzzer for KeyMintAttestation
KeyMintAttestation supports the following parameters:
@@ -77,3 +79,53 @@
$ adb sync data
$ adb shell /data/fuzz/arm64/keymint_authSet_fuzzer/keymint_authSet_fuzzer
```
+
+# <a name="KeyMintRemoteProv"></a> Fuzzer for KeyMintRemoteProv
+KeyMintRemoteProv supports the following parameters:
+1. ChallengeSize(parameter name: "challengeSize")
+2. Challenge(parameter name: "challenge")
+3. NumKeys(parameter name: "numKeys")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`challengeSize`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`challenge`| `std::vector<uint8_t>` |Value obtained from FuzzedDataProvider|
+|`numKeys`| `uint8_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_remote_prov_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_remote_prov_fuzzer/keymint_remote_prov_fuzzer
+```
+
+# <a name="KeyMintRemoteKeyProvSupport"></a> Fuzzer for KeyMintRemoteKeyProvSupport
+KeyMintRemoteKeyProvSupport supports the following parameters:
+1. SupportedEekCurve(parameter name: "supportedEekCurve")
+2. Length(parameter name: "length")
+3. SerialNumberProp(parameter name: "serialNoProp")
+4. InstanceName(parameter name: "instanceName")
+5. Value(parameter name: "value")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`supportedEekCurve`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`length`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`serialNoProp`| `string` |Value obtained from FuzzedDataProvider|
+|`instanceName`| `string` |Value obtained from FuzzedDataProvider|
+|`value`| `uint8_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_rkpsupport_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_rkpsupport_fuzzer/keymint_rkpsupport_fuzzer
+```
diff --git a/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp
new file mode 100644
index 0000000..6bd986c
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <android/binder_manager.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <remote_prov/remote_prov_utils.h>
+#include <utils/Log.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace cppcose;
+using namespace aidl::android::hardware::security::keymint;
+using namespace aidl::android::hardware::security::keymint::remote_prov;
+
+constexpr size_t kMinSize = 0;
+constexpr size_t kSupportedNumKeys = 4;
+constexpr size_t kChallengeSize = 64;
+constexpr size_t kMaxBytes = 128;
+const std::string kServiceName =
+ "android.hardware.security.keymint.IRemotelyProvisionedComponent/default";
+
+std::shared_ptr<IRemotelyProvisionedComponent> gRPC = nullptr;
+
+class KeyMintRemoteProv {
+ public:
+ KeyMintRemoteProv(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+ private:
+ std::vector<uint8_t> ExtractPayloadValue(const MacedPublicKey& macedPubKey);
+ FuzzedDataProvider mFdp;
+};
+
+std::vector<uint8_t> KeyMintRemoteProv::ExtractPayloadValue(const MacedPublicKey& macedPubKey) {
+ std::vector<uint8_t> payloadValue;
+
+ auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+ if (coseMac0) {
+ // The payload is a bstr holding an encoded COSE_Key
+ auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+ if (payload != nullptr) {
+ payloadValue = payload->value();
+ }
+ }
+ return payloadValue;
+}
+
+void KeyMintRemoteProv::process() {
+ std::vector<MacedPublicKey> keysToSign = std::vector<MacedPublicKey>(
+ mFdp.ConsumeIntegralInRange<uint8_t>(kMinSize, kSupportedNumKeys));
+ cppbor::Array cborKeysToSign;
+ for (auto& key : keysToSign) {
+ // TODO: b/350649166 - Randomize keysToSign
+ std::vector<uint8_t> privateKeyBlob;
+ gRPC->generateEcdsaP256KeyPair(false /* testMode */, &key, &privateKeyBlob);
+
+ std::vector<uint8_t> payloadValue = ExtractPayloadValue(key);
+ cborKeysToSign.add(cppbor::EncodedItem(payloadValue));
+ }
+
+ uint8_t challengeSize = mFdp.ConsumeIntegralInRange<uint8_t>(kMinSize, kChallengeSize);
+ std::vector<uint8_t> challenge = mFdp.ConsumeBytes<uint8_t>(challengeSize);
+
+ std::vector<uint8_t> csr;
+ gRPC->generateCertificateRequestV2(keysToSign, challenge, &csr);
+
+ while (mFdp.remaining_bytes()) {
+ auto invokeProvAPI = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() { verifyFactoryCsr(cborKeysToSign, csr, gRPC.get(), challenge); },
+ [&]() { verifyProductionCsr(cborKeysToSign, csr, gRPC.get(), challenge); },
+ [&]() { isCsrWithProperDiceChain(csr); },
+ });
+ invokeProvAPI();
+ }
+}
+
+extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str()));
+ gRPC = IRemotelyProvisionedComponent::fromBinder(binder);
+ LOG_ALWAYS_FATAL_IF(!gRPC, "Failed to get IRemotelyProvisionedComponent instance.");
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMintRemoteProv kmRemoteProv(data, size);
+ kmRemoteProv.process();
+ return 0;
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp
new file mode 100644
index 0000000..778d48f
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <fuzzer/FuzzedDataProvider.h>
+#include <remote_prov/remote_prov_utils.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace aidl::android::hardware::security::keymint::remote_prov;
+
+constexpr size_t kMaxBytes = 128;
+
+class KeyMintRemoteKeyProvSupport {
+ public:
+ KeyMintRemoteKeyProvSupport(const uint8_t* data, size_t size) : mFdp(data, size) {}
+ void process();
+
+ private:
+ FuzzedDataProvider mFdp;
+};
+
+void KeyMintRemoteKeyProvSupport::process() {
+ while (mFdp.remaining_bytes()) {
+ auto invokeProvAPI = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ std::vector<uint8_t> eekId;
+ if (mFdp.ConsumeBool()) {
+ eekId = mFdp.ConsumeBytes<uint8_t>(kMaxBytes);
+ }
+ generateEekChain(mFdp.ConsumeIntegral<uint8_t>() /* supportedEekCurve */,
+ mFdp.ConsumeIntegral<uint8_t>() /* length */, eekId);
+ },
+ [&]() { getProdEekChain(mFdp.ConsumeIntegral<uint8_t>() /* supportedEekCurve */); },
+ [&]() {
+ std::string serialNoProp = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ std::string instanceName = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ cppbor::Array array;
+ array.add(mFdp.ConsumeIntegral<uint8_t>() /* value */);
+ jsonEncodeCsrWithBuild(instanceName, array, serialNoProp);
+ },
+ });
+ invokeProvAPI();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMintRemoteKeyProvSupport keymintRKPSupport(data, size);
+ keymintRKPSupport.process();
+ return 0;
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index b74fd59..6638775 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -65,9 +65,9 @@
return privKey;
}
-ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey) {
+ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey, const int nid) {
// Extract public key.
- auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(nid));
if (group.get() == nullptr) {
return "Error creating EC group by curve name";
}
@@ -123,11 +123,12 @@
int keyType = EVP_PKEY_base_id(pubKey.get());
switch (keyType) {
case EVP_PKEY_EC: {
+ int nid = EVP_PKEY_bits(pubKey.get()) == 384 ? NID_secp384r1 : NID_X9_62_prime256v1;
auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pubKey.get()));
if (ecKey.get() == nullptr) {
return "Failed to get ec key";
- }
- return ecKeyGetPublicKey(ecKey.get());
+ }
+ return ecKeyGetPublicKey(ecKey.get(), nid);
}
case EVP_PKEY_ED25519: {
bytevec rawPubKey;
@@ -165,7 +166,7 @@
auto privKey = ecKeyGetPrivateKey(ec_key.get());
if (!privKey) return privKey.moveMessage();
- auto pubKey = ecKeyGetPublicKey(ec_key.get());
+ auto pubKey = ecKeyGetPublicKey(ec_key.get(), NID_X9_62_prime256v1);
if (!pubKey) return pubKey.moveMessage();
return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
@@ -824,7 +825,7 @@
}
if (i == chain.size() - 1) {
auto key = getRawPublicKey(pubKey);
- if (!key) key.moveMessage();
+ if (!key) return key.moveMessage();
rawPubKey = key.moveValue();
}
}
diff --git a/sensors/aidl/default/include/sensors-impl/Sensors.h b/sensors/aidl/default/include/sensors-impl/Sensors.h
index 2adbc9d..c90db69 100644
--- a/sensors/aidl/default/include/sensors-impl/Sensors.h
+++ b/sensors/aidl/default/include/sensors-impl/Sensors.h
@@ -97,9 +97,13 @@
return;
}
if (mEventQueue->write(&events.front(), events.size())) {
+ if (mEventQueueFlag == nullptr) {
+ // Don't take the wake lock if we can't wake the receiver to avoid holding it
+ // indefinitely.
+ return;
+ }
mEventQueueFlag->wake(
static_cast<uint32_t>(BnSensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS));
-
if (wakeup) {
// Keep track of the number of outstanding WAKE_UP events in order to properly hold
// a wake lock until the framework has secured a wake lock
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index af9a5fc..b8b6915 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -35,7 +35,7 @@
sdk_version: "module_current",
},
},
- frozen: true,
+ frozen: false,
versions_with_info: [
{
version: "1",
@@ -52,7 +52,7 @@
}
// Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V2"
+latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V3"
// Modules that depend on android.hardware.soundtrigger3 directly can include
// the following java_defaults to avoid explicitly managing dependency versions
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
index 0306dca..9d6fdbc 100644
--- a/tests/extension/vibrator/aidl/Android.bp
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -37,6 +37,12 @@
java: {
enabled: false,
},
+ ndk: {
+ enabled: true,
+ },
+ cpp: {
+ enabled: false,
+ },
},
frozen: true,
versions_with_info: [
diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp
index 284ac74..00510b7 100644
--- a/tests/extension/vibrator/aidl/client/Android.bp
+++ b/tests/extension/vibrator/aidl/client/Android.bp
@@ -16,16 +16,10 @@
srcs: [
// system code has the option to use the unstable C++ libbinder API
// or the NDK one. For maximum code portability, using the ndk client
- // makes the most sense, but both are provided here as an example.
- "test-cpp-client.cpp",
+ // makes the most sense.
"test-ndk-client.cpp",
],
shared_libs: [
- "libbinder",
- "libutils",
- "android.hardware.vibrator-V2-cpp",
- "android.hardware.tests.extension.vibrator-V1-cpp",
-
"libbinder_ndk",
"android.hardware.vibrator-V2-ndk",
"android.hardware.tests.extension.vibrator-V1-ndk",
diff --git a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
deleted file mode 100644
index 015a345..0000000
--- a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/hardware/tests/extension/vibrator/ICustomVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
-#include <gtest/gtest.h>
-
-using android::checked_interface_cast;
-using android::IBinder;
-using android::IInterface;
-using android::OK;
-using android::sp;
-using android::waitForVintfService;
-using android::hardware::tests::extension::vibrator::Directionality;
-using android::hardware::tests::extension::vibrator::ICustomVibrator;
-using android::hardware::vibrator::IVibrator;
-
-TEST(Cpp, CallRootMethod) {
- sp<IVibrator> vib = waitForVintfService<IVibrator>();
- ASSERT_NE(nullptr, vib.get());
- ASSERT_TRUE(vib->off().isOk());
-}
-
-TEST(Cpp, CallExtMethod) {
- // normally you would want to cache this
- sp<IVibrator> vib = waitForVintfService<IVibrator>();
- ASSERT_NE(nullptr, vib.get());
-
- // getting the extension
- sp<IBinder> ext;
- ASSERT_EQ(OK, IInterface::asBinder(vib)->getExtension(&ext));
- sp<ICustomVibrator> cvib = checked_interface_cast<ICustomVibrator>(ext);
- ASSERT_NE(nullptr, cvib.get());
-
- // calling extension method
- ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk());
-}
diff --git a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
index c846495..4dd86e8 100644
--- a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
+++ b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp
@@ -28,7 +28,7 @@
static const std::string kInstance = std::string() + IVibrator::descriptor + "/default";
TEST(Ndk, CallRootMethod) {
- SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+ SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str()));
ASSERT_NE(nullptr, vibBinder.get());
std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
ASSERT_NE(nullptr, vib.get());
@@ -38,7 +38,7 @@
TEST(Ndk, CallExtMethod) {
// normally you would want to cache this
//
- SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+ SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str()));
ASSERT_NE(nullptr, vibBinder.get());
std::shared_ptr<IVibrator> vib = IVibrator::fromBinder(vibBinder);
ASSERT_NE(nullptr, vib.get());
diff --git a/tests/msgq/1.0/ITestMsgQ.hal b/tests/msgq/1.0/ITestMsgQ.hal
index 0cf9c7c..62bef0a 100644
--- a/tests/msgq/1.0/ITestMsgQ.hal
+++ b/tests/msgq/1.0/ITestMsgQ.hal
@@ -18,8 +18,8 @@
interface ITestMsgQ {
enum EventFlagBits : uint32_t {
- FMQ_NOT_EMPTY = 1 << 0,
- FMQ_NOT_FULL = 1 << 1,
+ FMQ_NOT_FULL = 1 << 0,
+ FMQ_NOT_EMPTY = 1 << 1,
};
/**
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index b5199e2..fe76450 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -20,6 +20,12 @@
java: {
sdk_version: "system_current",
},
+ ndk: {
+ enabled: true,
+ },
+ cpp: {
+ enabled: false,
+ },
},
versions: [
"1",
diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp
index b6d2fb2..166b30b 100644
--- a/vibrator/aidl/vts/Android.bp
+++ b/vibrator/aidl/vts/Android.bp
@@ -17,10 +17,10 @@
tidy_timeout_srcs: ["VtsHalVibratorTargetTest.cpp"],
srcs: ["VtsHalVibratorTargetTest.cpp"],
shared_libs: [
- "libbinder",
+ "libbinder_ndk",
],
static_libs: [
- "android.hardware.vibrator-V2-cpp",
+ "android.hardware.vibrator-V2-ndk",
],
test_suites: [
"general-tests",
@@ -36,10 +36,10 @@
],
srcs: ["VtsHalVibratorManagerTargetTest.cpp"],
shared_libs: [
- "libbinder",
+ "libbinder_ndk",
],
static_libs: [
- "android.hardware.vibrator-V2-cpp",
+ "android.hardware.vibrator-V2-ndk",
],
test_suites: [
"general-tests",
diff --git a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
index e8ed26a..3c2a360 100644
--- a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
@@ -15,42 +15,40 @@
*/
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorManager.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <android/hardware/vibrator/IVibratorManager.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <cmath>
#include <future>
-using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::binder::Status;
-using android::hardware::vibrator::BnVibratorCallback;
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
-using android::hardware::vibrator::Effect;
-using android::hardware::vibrator::EffectStrength;
-using android::hardware::vibrator::IVibrator;
-using android::hardware::vibrator::IVibratorManager;
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::BnVibratorCallback;
+using aidl::android::hardware::vibrator::CompositeEffect;
+using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::Effect;
+using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
using std::chrono::high_resolution_clock;
-const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
- android::enum_range<Effect>().end()};
-const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
- android::enum_range<EffectStrength>().end()};
-const std::vector<CompositePrimitive> kPrimitives{android::enum_range<CompositePrimitive>().begin(),
- android::enum_range<CompositePrimitive>().end()};
+const std::vector<Effect> kEffects{ndk::enum_range<Effect>().begin(),
+ ndk::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
+ ndk::enum_range<EffectStrength>().end()};
+const std::vector<CompositePrimitive> kPrimitives{ndk::enum_range<CompositePrimitive>().begin(),
+ ndk::enum_range<CompositePrimitive>().end()};
class CompletionCallback : public BnVibratorCallback {
public:
CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
- Status onComplete() override {
+ ndk::ScopedAStatus onComplete() override {
mCallback();
- return Status::ok();
+ return ndk::ScopedAStatus::ok();
}
private:
@@ -60,55 +58,50 @@
class VibratorAidl : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- manager = android::waitForDeclaredService<IVibratorManager>(String16(GetParam().c_str()));
+ auto serviceName = GetParam().c_str();
+ manager = IVibratorManager::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(serviceName)));
ASSERT_NE(manager, nullptr);
- ASSERT_TRUE(manager->getCapabilities(&capabilities).isOk());
- EXPECT_TRUE(manager->getVibratorIds(&vibratorIds).isOk());
+ EXPECT_OK(manager->getCapabilities(&capabilities));
+ EXPECT_OK(manager->getVibratorIds(&vibratorIds));
}
- sp<IVibratorManager> manager;
+ std::shared_ptr<IVibratorManager> manager;
int32_t capabilities;
std::vector<int32_t> vibratorIds;
};
-inline bool isUnknownOrUnsupported(Status status) {
- return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
- status.transactionError() == android::UNKNOWN_TRANSACTION;
-}
-
TEST_P(VibratorAidl, ValidateExistingVibrators) {
- sp<IVibrator> vibrator;
- for (auto& id : vibratorIds) {
- EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ std::shared_ptr<IVibrator> vibrator;
+ for (int32_t id : vibratorIds) {
+ EXPECT_OK(manager->getVibrator(id, &vibrator));
ASSERT_NE(vibrator, nullptr);
}
}
TEST_P(VibratorAidl, GetVibratorWithInvalidId) {
int32_t invalidId = *max_element(vibratorIds.begin(), vibratorIds.end()) + 1;
- sp<IVibrator> vibrator;
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- manager->getVibrator(invalidId, &vibrator).exceptionCode());
+ std::shared_ptr<IVibrator> vibrator;
+ EXPECT_ILLEGAL_ARGUMENT(manager->getVibrator(invalidId, &vibrator));
ASSERT_EQ(vibrator, nullptr);
}
TEST_P(VibratorAidl, ValidatePrepareSyncedExistingVibrators) {
if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
if (vibratorIds.empty()) return;
- EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
- EXPECT_TRUE(manager->cancelSynced().isOk());
+ EXPECT_OK(manager->prepareSynced(vibratorIds));
+ EXPECT_OK(manager->cancelSynced());
}
TEST_P(VibratorAidl, PrepareSyncedEmptySetIsInvalid) {
if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
std::vector<int32_t> emptyIds;
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, manager->prepareSynced(emptyIds).exceptionCode());
+ EXPECT_ILLEGAL_ARGUMENT(manager->prepareSynced(emptyIds));
}
TEST_P(VibratorAidl, PrepareSyncedNotSupported) {
if (!(capabilities & IVibratorManager::CAP_SYNC)) {
- Status status = manager->prepareSynced(vibratorIds);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->prepareSynced(vibratorIds));
}
}
@@ -117,15 +110,14 @@
if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
uint32_t durationMs = 250;
- EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
- sp<IVibrator> vibrator;
- for (auto& id : vibratorIds) {
- EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ EXPECT_OK(manager->prepareSynced(vibratorIds));
+ std::shared_ptr<IVibrator> vibrator;
+ for (int32_t id : vibratorIds) {
+ EXPECT_OK(manager->getVibrator(id, &vibrator));
ASSERT_NE(vibrator, nullptr);
- Status status = vibrator->on(durationMs, nullptr);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(durationMs, nullptr));
}
- EXPECT_TRUE(manager->cancelSynced().isOk());
+ EXPECT_OK(manager->cancelSynced());
}
}
@@ -133,16 +125,16 @@
if (vibratorIds.empty()) return;
if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) {
- EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
- sp<IVibrator> vibrator;
- for (auto& id : vibratorIds) {
- EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ EXPECT_OK(manager->prepareSynced(vibratorIds));
+ std::shared_ptr<IVibrator> vibrator;
+ for (int32_t id : vibratorIds) {
+ EXPECT_OK(manager->getVibrator(id, &vibrator));
ASSERT_NE(vibrator, nullptr);
int32_t lengthMs = 0;
- Status status = vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(
+ vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs));
}
- EXPECT_TRUE(manager->cancelSynced().isOk());
+ EXPECT_OK(manager->cancelSynced());
}
}
@@ -157,15 +149,14 @@
effect.scale = 1.0f;
composite.emplace_back(effect);
- EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
- sp<IVibrator> vibrator;
- for (auto& id : vibratorIds) {
- EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ EXPECT_OK(manager->prepareSynced(vibratorIds));
+ std::shared_ptr<IVibrator> vibrator;
+ for (int32_t id : vibratorIds) {
+ EXPECT_OK(manager->getVibrator(id, &vibrator));
ASSERT_NE(vibrator, nullptr);
- Status status = vibrator->compose(composite, nullptr);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr));
}
- EXPECT_TRUE(manager->cancelSynced().isOk());
+ EXPECT_OK(manager->cancelSynced());
}
}
@@ -177,51 +168,58 @@
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
- sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+ [&completionPromise] { completionPromise.set_value(); });
uint32_t durationMs = 250;
std::chrono::milliseconds timeout{durationMs * 2};
- EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
- sp<IVibrator> vibrator;
- for (auto& id : vibratorIds) {
- EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk());
+ EXPECT_OK(manager->prepareSynced(vibratorIds));
+ std::shared_ptr<IVibrator> vibrator;
+ for (int32_t id : vibratorIds) {
+ EXPECT_OK(manager->getVibrator(id, &vibrator));
ASSERT_NE(vibrator, nullptr);
- EXPECT_TRUE(vibrator->on(durationMs, nullptr).isOk());
+ EXPECT_OK(vibrator->on(durationMs, nullptr));
}
- EXPECT_TRUE(manager->triggerSynced(callback).isOk());
+ EXPECT_OK(manager->triggerSynced(callback));
EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
- EXPECT_TRUE(manager->cancelSynced().isOk());
+ EXPECT_OK(manager->cancelSynced());
}
TEST_P(VibratorAidl, TriggerSyncNotSupported) {
if (!(capabilities & IVibratorManager::CAP_SYNC)) {
- Status status = manager->triggerSynced(nullptr);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(nullptr));
}
}
TEST_P(VibratorAidl, TriggerCallbackNotSupported) {
if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
if (!(capabilities & IVibratorManager::CAP_TRIGGER_CALLBACK)) {
- sp<CompletionCallback> callback = new CompletionCallback([] {});
- EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
- Status status = manager->triggerSynced(callback);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
- EXPECT_TRUE(manager->cancelSynced().isOk());
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+ EXPECT_OK(manager->prepareSynced(vibratorIds));
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(callback));
+ EXPECT_OK(manager->cancelSynced());
}
}
+std::vector<std::string> FindVibratorManagerNames() {
+ std::vector<std::string> names;
+ constexpr auto callback = [](const char* instance, void* context) {
+ std::string fullName = std::string(IVibratorManager::descriptor) + "/" + instance;
+ static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+ };
+ AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor,
+ static_cast<void*>(&names), callback);
+ return names;
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl);
-INSTANTIATE_TEST_SUITE_P(
- Vibrator, VibratorAidl,
- testing::ValuesIn(android::getAidlHalInstanceNames(IVibratorManager::descriptor)),
- android::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(FindVibratorManagerNames()),
+ android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- ProcessState::self()->setThreadPoolMaxThreadCount(1);
- ProcessState::self()->startThreadPool();
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index db474d6..65a1e84 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -15,38 +15,37 @@
*/
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <android/hardware/vibrator/IVibratorManager.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorManager.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <cmath>
#include <future>
-using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::binder::Status;
-using android::hardware::vibrator::ActivePwle;
-using android::hardware::vibrator::BnVibratorCallback;
-using android::hardware::vibrator::Braking;
-using android::hardware::vibrator::BrakingPwle;
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
-using android::hardware::vibrator::Effect;
-using android::hardware::vibrator::EffectStrength;
-using android::hardware::vibrator::IVibrator;
-using android::hardware::vibrator::IVibratorManager;
-using android::hardware::vibrator::PrimitivePwle;
+#include "test_utils.h"
+
+using aidl::android::hardware::vibrator::ActivePwle;
+using aidl::android::hardware::vibrator::BnVibratorCallback;
+using aidl::android::hardware::vibrator::Braking;
+using aidl::android::hardware::vibrator::BrakingPwle;
+using aidl::android::hardware::vibrator::CompositeEffect;
+using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::Effect;
+using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
+using aidl::android::hardware::vibrator::PrimitivePwle;
using std::chrono::high_resolution_clock;
using namespace ::std::chrono_literals;
-const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
- android::enum_range<Effect>().end()};
-const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
- android::enum_range<EffectStrength>().end()};
+const std::vector<Effect> kEffects{ndk::enum_range<Effect>().begin(),
+ ndk::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
+ ndk::enum_range<EffectStrength>().end()};
const std::vector<Effect> kInvalidEffects = {
static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
@@ -59,8 +58,7 @@
};
const std::vector<CompositePrimitive> kCompositePrimitives{
- android::enum_range<CompositePrimitive>().begin(),
- android::enum_range<CompositePrimitive>().end()};
+ ndk::enum_range<CompositePrimitive>().begin(), ndk::enum_range<CompositePrimitive>().end()};
const std::vector<CompositePrimitive> kRequiredPrimitives = {
CompositePrimitive::CLICK, CompositePrimitive::LIGHT_TICK,
@@ -74,14 +72,36 @@
};
// Timeout to wait for vibration callback completion.
-static constexpr auto VIBRATION_CALLBACK_TIMEOUT = 100ms;
+static constexpr std::chrono::milliseconds VIBRATION_CALLBACK_TIMEOUT = 100ms;
+
+static std::vector<std::string> findVibratorManagerNames() {
+ std::vector<std::string> names;
+ constexpr auto callback = [](const char* instance, void* context) {
+ auto fullName = std::string(IVibratorManager::descriptor) + "/" + instance;
+ static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+ };
+ AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor,
+ static_cast<void*>(&names), callback);
+ return names;
+}
+
+static std::vector<std::string> findUnmanagedVibratorNames() {
+ std::vector<std::string> names;
+ constexpr auto callback = [](const char* instance, void* context) {
+ auto fullName = std::string(IVibrator::descriptor) + "/" + instance;
+ static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
+ };
+ AServiceManager_forEachDeclaredInstance(IVibrator::descriptor, static_cast<void*>(&names),
+ callback);
+ return names;
+}
class CompletionCallback : public BnVibratorCallback {
public:
CompletionCallback(const std::function<void()> &callback) : mCallback(callback) {}
- Status onComplete() override {
+ ndk::ScopedAStatus onComplete() override {
mCallback();
- return Status::ok();
+ return ndk::ScopedAStatus::ok();
}
private:
@@ -93,88 +113,87 @@
virtual void SetUp() override {
int32_t managerIdx = std::get<0>(GetParam());
int32_t vibratorId = std::get<1>(GetParam());
- auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
if (managerIdx < 0) {
// Testing a unmanaged vibrator, using vibratorId as index from registered HALs
- auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
- ASSERT_LT(vibratorId, vibratorAidlNames.size());
- auto vibratorName = String16(vibratorAidlNames[vibratorId].c_str());
- vibrator = android::waitForDeclaredService<IVibrator>(vibratorName);
+ std::vector<std::string> vibratorNames = findUnmanagedVibratorNames();
+ ASSERT_LT(vibratorId, vibratorNames.size());
+ vibrator = IVibrator::fromBinder(ndk::SpAIBinder(
+ AServiceManager_waitForService(vibratorNames[vibratorId].c_str())));
} else {
// Testing a managed vibrator, using vibratorId to retrieve it from the manager
- ASSERT_LT(managerIdx, managerAidlNames.size());
- auto managerName = String16(managerAidlNames[managerIdx].c_str());
- auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
- auto vibratorResult = vibratorManager->getVibrator(vibratorId, &vibrator);
- ASSERT_TRUE(vibratorResult.isOk());
+ std::vector<std::string> managerNames = findVibratorManagerNames();
+ ASSERT_LT(managerIdx, managerNames.size());
+ auto vibratorManager = IVibratorManager::fromBinder(ndk::SpAIBinder(
+ AServiceManager_waitForService(managerNames[managerIdx].c_str())));
+ EXPECT_OK(vibratorManager->getVibrator(vibratorId, &vibrator))
+ << "\n For vibrator id: " << vibratorId;
}
ASSERT_NE(vibrator, nullptr);
- ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk());
+ EXPECT_OK(vibrator->getCapabilities(&capabilities));
}
virtual void TearDown() override {
// Reset vibrator state between tests.
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->off());
}
- sp<IVibrator> vibrator;
+ std::shared_ptr<IVibrator> vibrator;
int32_t capabilities;
};
-inline bool isUnknownOrUnsupported(Status status) {
- return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
- status.transactionError() == android::UNKNOWN_TRANSACTION;
-}
-
-static float getResonantFrequencyHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getResonantFrequencyHz(const std::shared_ptr<IVibrator>& vibrator,
+ int32_t capabilities) {
float resonantFrequencyHz;
- Status status = vibrator->getResonantFrequency(&resonantFrequencyHz);
+ ndk::ScopedAStatus status = vibrator->getResonantFrequency(&resonantFrequencyHz);
if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
+ EXPECT_OK(std::move(status));
EXPECT_GT(resonantFrequencyHz, 0);
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
return resonantFrequencyHz;
}
-static float getFrequencyResolutionHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyResolutionHz(const std::shared_ptr<IVibrator>& vibrator,
+ int32_t capabilities) {
float freqResolutionHz;
- Status status = vibrator->getFrequencyResolution(&freqResolutionHz);
+ ndk::ScopedAStatus status = vibrator->getFrequencyResolution(&freqResolutionHz);
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+ EXPECT_OK(std::move(status));
EXPECT_GT(freqResolutionHz, 0);
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
return freqResolutionHz;
}
-static float getFrequencyMinimumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyMinimumHz(const std::shared_ptr<IVibrator>& vibrator,
+ int32_t capabilities) {
float freqMinimumHz;
- Status status = vibrator->getFrequencyMinimum(&freqMinimumHz);
+ ndk::ScopedAStatus status = vibrator->getFrequencyMinimum(&freqMinimumHz);
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ EXPECT_OK(std::move(status));
float resonantFrequencyHz = getResonantFrequencyHz(vibrator, capabilities);
EXPECT_GT(freqMinimumHz, 0);
EXPECT_LE(freqMinimumHz, resonantFrequencyHz);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
return freqMinimumHz;
}
-static float getFrequencyMaximumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+static float getFrequencyMaximumHz(const std::shared_ptr<IVibrator>& vibrator,
+ int32_t capabilities) {
std::vector<float> bandwidthAmplitudeMap;
- Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+ ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ EXPECT_OK(std::move(status));
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) *
@@ -191,7 +210,8 @@
return 1.0;
}
-static ActivePwle composeValidActivePwle(sp<IVibrator> vibrator, int32_t capabilities) {
+static ActivePwle composeValidActivePwle(const std::shared_ptr<IVibrator>& vibrator,
+ int32_t capabilities) {
float frequencyHz;
if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
frequencyHz = getResonantFrequencyHz(vibrator, capabilities);
@@ -212,9 +232,9 @@
}
TEST_P(VibratorAidl, OnThenOffBeforeTimeout) {
- EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
+ EXPECT_OK(vibrator->on(2000, nullptr /*callback*/));
sleep(1);
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->off());
}
TEST_P(VibratorAidl, OnWithCallback) {
@@ -223,26 +243,25 @@
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
- sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+ [&completionPromise] { completionPromise.set_value(); });
uint32_t durationMs = 250;
auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT;
- EXPECT_TRUE(vibrator->on(durationMs, callback).isOk());
+ EXPECT_OK(vibrator->on(durationMs, callback));
EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->off());
}
TEST_P(VibratorAidl, OnCallbackNotSupported) {
if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) {
- sp<CompletionCallback> callback = new CompletionCallback([] {});
- Status status = vibrator->on(250, callback);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(250, callback));
}
}
TEST_P(VibratorAidl, ValidateEffect) {
std::vector<Effect> supported;
- ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+ EXPECT_OK(vibrator->getSupportedEffects(&supported));
for (Effect effect : kEffects) {
bool isEffectSupported =
@@ -250,15 +269,18 @@
for (EffectStrength strength : kEffectStrengths) {
int32_t lengthMs = 0;
- Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+ ndk::ScopedAStatus status =
+ vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
if (isEffectSupported) {
- EXPECT_TRUE(status.isOk()) << toString(effect) << " " << toString(strength);
+ EXPECT_OK(std::move(status))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
EXPECT_GT(lengthMs, 0);
usleep(lengthMs * 1000);
+ EXPECT_OK(vibrator->off());
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status))
- << status << " " << toString(effect) << " " << toString(strength);
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
}
}
}
@@ -269,7 +291,7 @@
return;
std::vector<Effect> supported;
- ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+ EXPECT_OK(vibrator->getSupportedEffects(&supported));
for (Effect effect : kEffects) {
bool isEffectSupported =
@@ -278,25 +300,26 @@
for (EffectStrength strength : kEffectStrengths) {
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
- sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+ [&completionPromise] { completionPromise.set_value(); });
int lengthMs = 0;
- Status status = vibrator->perform(effect, strength, callback, &lengthMs);
+ ndk::ScopedAStatus status = vibrator->perform(effect, strength, callback, &lengthMs);
if (isEffectSupported) {
- EXPECT_TRUE(status.isOk());
+ EXPECT_OK(std::move(status))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
EXPECT_GT(lengthMs, 0);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
}
- if (!status.isOk())
- continue;
+ if (lengthMs <= 0) continue;
auto timeout = std::chrono::milliseconds(lengthMs) + VIBRATION_CALLBACK_TIMEOUT;
EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->off());
}
}
}
@@ -307,10 +330,10 @@
for (Effect effect : kEffects) {
for (EffectStrength strength : kEffectStrengths) {
- sp<CompletionCallback> callback = new CompletionCallback([] {});
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>([] {});
int lengthMs;
- Status status = vibrator->perform(effect, strength, callback, &lengthMs);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->perform(effect, strength, callback, &lengthMs))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
}
}
}
@@ -319,53 +342,52 @@
for (Effect effect : kInvalidEffects) {
for (EffectStrength strength : kEffectStrengths) {
int32_t lengthMs;
- Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
- EXPECT_TRUE(isUnknownOrUnsupported(status))
- << status << toString(effect) << " " << toString(strength);
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(
+ vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
}
}
for (Effect effect : kEffects) {
for (EffectStrength strength : kInvalidEffectStrengths) {
int32_t lengthMs;
- Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
- EXPECT_TRUE(isUnknownOrUnsupported(status))
- << status << " " << toString(effect) << " " << toString(strength);
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(
+ vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
}
}
}
TEST_P(VibratorAidl, ChangeVibrationAmplitude) {
if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
- EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.1f).exceptionCode());
- EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
- EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.5f).exceptionCode());
+ EXPECT_OK(vibrator->setAmplitude(0.1f));
+ EXPECT_OK(vibrator->on(2000, nullptr /*callback*/));
+ EXPECT_OK(vibrator->setAmplitude(0.5f));
sleep(1);
- EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
+ EXPECT_OK(vibrator->setAmplitude(1.0f));
sleep(1);
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->off());
}
}
TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) {
if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode());
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode());
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(1.1).exceptionCode());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(-1));
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(0));
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(1.1));
}
}
TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) {
if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
- Status status = vibrator->setAmplitude(1);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(1));
}
}
TEST_P(VibratorAidl, ChangeVibrationExternalControl) {
if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
- EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+ EXPECT_OK(vibrator->setExternalControl(true));
sleep(1);
- EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+ EXPECT_OK(vibrator->setExternalControl(false));
sleep(1);
}
}
@@ -375,15 +397,15 @@
(capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
- EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+ EXPECT_OK(vibrator->setExternalControl(true));
- Status amplitudeStatus = vibrator->setAmplitude(0.5);
if (supportsExternalAmplitudeControl) {
- EXPECT_TRUE(amplitudeStatus.isOk());
+ EXPECT_OK(vibrator->setAmplitude(0.5));
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(amplitudeStatus)) << amplitudeStatus;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(0.5));
}
- EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+
+ EXPECT_OK(vibrator->setExternalControl(false));
} else {
EXPECT_FALSE(supportsExternalAmplitudeControl);
}
@@ -391,18 +413,16 @@
TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) {
if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
- Status status = vibrator->setExternalControl(true);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setExternalControl(true));
}
}
TEST_P(VibratorAidl, GetSupportedPrimitives) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
std::vector<CompositePrimitive> supported;
+ EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
- EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
-
- for (auto primitive : kCompositePrimitives) {
+ for (CompositePrimitive primitive : kCompositePrimitives) {
bool isPrimitiveSupported =
std::find(supported.begin(), supported.end(), primitive) != supported.end();
bool isPrimitiveRequired =
@@ -417,22 +437,23 @@
TEST_P(VibratorAidl, GetPrimitiveDuration) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
std::vector<CompositePrimitive> supported;
- ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+ EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
- for (auto primitive : kCompositePrimitives) {
+ for (CompositePrimitive primitive : kCompositePrimitives) {
bool isPrimitiveSupported =
std::find(supported.begin(), supported.end(), primitive) != supported.end();
int32_t duration;
- Status status = vibrator->getPrimitiveDuration(primitive, &duration);
-
if (isPrimitiveSupported) {
- EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
+ EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &duration))
+ << "\n For primitive: " << toString(primitive) << " " << duration;
if (primitive != CompositePrimitive::NOOP) {
- ASSERT_GT(duration, 0) << toString(primitive) << " " << duration;
+ ASSERT_GT(duration, 0)
+ << "\n For primitive: " << toString(primitive) << " " << duration;
}
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->getPrimitiveDuration(primitive, &duration))
+ << "\n For primitive: " << toString(primitive);
}
}
}
@@ -446,14 +467,14 @@
std::vector<CompositePrimitive> supported;
int32_t maxDelay, maxSize;
- ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
- EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
- EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+ EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
+ EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay));
+ EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize));
std::vector<CompositeEffect> composite;
for (int i = 0; i < supported.size(); i++) {
- auto primitive = supported[i];
+ CompositePrimitive primitive = supported[i];
float t = static_cast<float>(i + 1) / supported.size();
CompositeEffect effect;
@@ -467,8 +488,8 @@
}
if (composite.size() != 0) {
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->compose(composite, nullptr));
+ EXPECT_OK(vibrator->off());
}
}
@@ -477,12 +498,12 @@
GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported";
}
- auto unsupported = kInvalidPrimitives;
+ std::vector<CompositePrimitive> unsupported(kInvalidPrimitives);
std::vector<CompositePrimitive> supported;
- ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+ EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
- for (auto primitive : kCompositePrimitives) {
+ for (CompositePrimitive primitive : kCompositePrimitives) {
bool isPrimitiveSupported =
std::find(supported.begin(), supported.end(), primitive) != supported.end();
@@ -491,16 +512,15 @@
}
}
- for (auto primitive : unsupported) {
+ for (CompositePrimitive primitive : unsupported) {
std::vector<CompositeEffect> composite(1);
- for (auto& effect : composite) {
+ for (CompositeEffect& effect : composite) {
effect.delayMs = 0;
effect.primitive = primitive;
effect.scale = 1.0f;
}
- Status status = vibrator->compose(composite, nullptr);
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr));
}
}
@@ -516,18 +536,18 @@
effect.primitive = CompositePrimitive::CLICK;
effect.scale = std::nextafter(0.0f, -1.0f);
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
effect.scale = 0.0f;
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->compose(composite, nullptr));
+ EXPECT_OK(vibrator->off());
effect.scale = 1.0f;
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->compose(composite, nullptr));
+ EXPECT_OK(vibrator->off());
effect.scale = std::nextafter(1.0f, 2.0f);
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
}
TEST_P(VibratorAidl, ComposeDelayBoundary) {
@@ -537,7 +557,7 @@
int32_t maxDelay;
- EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
+ EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay));
std::vector<CompositeEffect> composite(1);
CompositeEffect& effect = composite[0];
@@ -546,19 +566,19 @@
effect.scale = 1.0f;
effect.delayMs = 0;
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->compose(composite, nullptr));
+ EXPECT_OK(vibrator->off());
effect.delayMs = 1;
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->compose(composite, nullptr));
+ EXPECT_OK(vibrator->off());
effect.delayMs = maxDelay;
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->compose(composite, nullptr));
+ EXPECT_OK(vibrator->off());
effect.delayMs = maxDelay + 1;
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
}
TEST_P(VibratorAidl, ComposeSizeBoundary) {
@@ -568,7 +588,7 @@
int32_t maxSize;
- EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
+ EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize));
std::vector<CompositeEffect> composite(maxSize);
CompositeEffect effect;
@@ -578,11 +598,11 @@
effect.scale = 1.0f;
std::fill(composite.begin(), composite.end(), effect);
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->compose(composite, nullptr));
+ EXPECT_OK(vibrator->off());
composite.emplace_back(effect);
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr));
}
TEST_P(VibratorAidl, ComposeCallback) {
@@ -591,18 +611,17 @@
}
std::vector<CompositePrimitive> supported;
+ EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
- ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
-
- for (auto primitive : supported) {
+ for (CompositePrimitive primitive : supported) {
if (primitive == CompositePrimitive::NOOP) {
continue;
}
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
- sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+ [&completionPromise] { completionPromise.set_value(); });
CompositeEffect effect;
std::vector<CompositeEffect> composite;
int32_t durationMs;
@@ -615,50 +634,50 @@
effect.scale = 1.0f;
composite.emplace_back(effect);
- EXPECT_EQ(Status::EX_NONE,
- vibrator->getPrimitiveDuration(primitive, &durationMs).exceptionCode())
- << toString(primitive);
+ EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &durationMs))
+ << "\n For primitive: " << toString(primitive);
duration = std::chrono::milliseconds(durationMs);
start = high_resolution_clock::now();
- EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
- << toString(primitive);
+ EXPECT_OK(vibrator->compose(composite, callback))
+ << "\n For primitive: " << toString(primitive);
EXPECT_EQ(completionFuture.wait_for(duration + VIBRATION_CALLBACK_TIMEOUT),
std::future_status::ready)
- << toString(primitive);
+ << "\n For primitive: " << toString(primitive);
end = high_resolution_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
- EXPECT_GE(elapsed.count(), duration.count()) << toString(primitive);
+ EXPECT_GE(elapsed.count(), duration.count())
+ << "\n For primitive: " << toString(primitive);
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->off()) << "\n For primitive: " << toString(primitive);
}
}
TEST_P(VibratorAidl, AlwaysOn) {
if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
std::vector<Effect> supported;
- ASSERT_TRUE(vibrator->getSupportedAlwaysOnEffects(&supported).isOk());
+ EXPECT_OK(vibrator->getSupportedAlwaysOnEffects(&supported));
for (Effect effect : kEffects) {
bool isEffectSupported =
std::find(supported.begin(), supported.end(), effect) != supported.end();
for (EffectStrength strength : kEffectStrengths) {
- Status status = vibrator->alwaysOnEnable(0, effect, strength);
+ ndk::ScopedAStatus status = vibrator->alwaysOnEnable(0, effect, strength);
if (isEffectSupported) {
- EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
- << toString(effect) << " " << toString(strength);
+ EXPECT_OK(std::move(status))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status))
- << status << " " << toString(effect) << " " << toString(strength);
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status))
+ << "\n For effect: " << toString(effect) << " " << toString(strength);
}
}
}
- EXPECT_EQ(Status::EX_NONE, vibrator->alwaysOnDisable(0).exceptionCode());
+ EXPECT_OK(vibrator->alwaysOnDisable(0));
}
}
@@ -668,12 +687,12 @@
TEST_P(VibratorAidl, GetQFactor) {
float qFactor;
- Status status = vibrator->getQFactor(&qFactor);
+ ndk::ScopedAStatus status = vibrator->getQFactor(&qFactor);
if (capabilities & IVibrator::CAP_GET_Q_FACTOR) {
+ EXPECT_OK(std::move(status));
ASSERT_GT(qFactor, 0);
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
}
@@ -687,9 +706,9 @@
TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) {
std::vector<float> bandwidthAmplitudeMap;
- Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+ ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ EXPECT_OK(std::move(status));
ASSERT_FALSE(bandwidthAmplitudeMap.empty());
int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) -
@@ -702,42 +721,42 @@
ASSERT_LE(e, 1.0);
}
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
}
TEST_P(VibratorAidl, GetPwlePrimitiveDurationMax) {
int32_t durationMs;
- Status status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
+ ndk::ScopedAStatus status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ EXPECT_OK(std::move(status));
ASSERT_NE(durationMs, 0);
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
}
TEST_P(VibratorAidl, GetPwleCompositionSizeMax) {
int32_t maxSize;
- Status status = vibrator->getPwleCompositionSizeMax(&maxSize);
+ ndk::ScopedAStatus status = vibrator->getPwleCompositionSizeMax(&maxSize);
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ EXPECT_OK(std::move(status));
ASSERT_NE(maxSize, 0);
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
}
TEST_P(VibratorAidl, GetSupportedBraking) {
std::vector<Braking> supported;
- Status status = vibrator->getSupportedBraking(&supported);
+ ndk::ScopedAStatus status = vibrator->getSupportedBraking(&supported);
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
bool isDefaultNoneSupported =
std::find(supported.begin(), supported.end(), Braking::NONE) != supported.end();
+ EXPECT_OK(std::move(status));
ASSERT_TRUE(isDefaultNoneSupported);
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
} else {
- EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
}
}
@@ -746,7 +765,7 @@
ActivePwle firstActive = composeValidActivePwle(vibrator, capabilities);
std::vector<Braking> supported;
- ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+ EXPECT_OK(vibrator->getSupportedBraking(&supported));
bool isClabSupported =
std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
BrakingPwle firstBraking;
@@ -765,11 +784,11 @@
secondBraking.braking = Braking::NONE;
secondBraking.duration = 10;
- auto pwleQueue =
- std::vector<PrimitivePwle>{firstActive, firstBraking, secondActive, secondBraking};
+ std::vector<PrimitivePwle> pwleQueue = {firstActive, firstBraking, secondActive,
+ secondBraking};
- EXPECT_EQ(Status::EX_NONE, vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->composePwle(pwleQueue, nullptr));
+ EXPECT_OK(vibrator->off());
}
}
@@ -780,8 +799,8 @@
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
- sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ auto callback = ndk::SharedRefBase::make<CompletionCallback>(
+ [&completionPromise] { completionPromise.set_value(); });
int32_t segmentDurationMaxMs;
vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
uint32_t durationMs = segmentDurationMaxMs * 2 + 100; // Sum of 2 active and 1 braking below
@@ -790,27 +809,25 @@
ActivePwle active = composeValidActivePwle(vibrator, capabilities);
std::vector<Braking> supported;
- ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+ EXPECT_OK(vibrator->getSupportedBraking(&supported));
bool isClabSupported =
std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
BrakingPwle braking;
braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
braking.duration = 100;
- auto pwleQueue = std::vector<PrimitivePwle>{active, braking, active};
+ std::vector<PrimitivePwle> pwleQueue = {active, braking, active};
- EXPECT_TRUE(vibrator->composePwle(pwleQueue, callback).isOk());
+ EXPECT_OK(vibrator->composePwle(pwleQueue, callback));
EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_OK(vibrator->off());
}
TEST_P(VibratorAidl, ComposePwleSegmentBoundary) {
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
std::vector<PrimitivePwle> pwleQueue;
// test empty queue
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
ActivePwle active = composeValidActivePwle(vibrator, capabilities);
@@ -824,9 +841,7 @@
pwleQueue.emplace_back(std::move(pwle));
}
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
}
}
@@ -836,20 +851,16 @@
active.startAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed
active.endAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed
- auto pwleQueueGreater = std::vector<PrimitivePwle>{active};
+ std::vector<PrimitivePwle> pwleQueueGreater = {active};
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr));
active.startAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed
active.endAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed
- auto pwleQueueLess = std::vector<PrimitivePwle>{active};
+ std::vector<PrimitivePwle> pwleQueueLess = {active};
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr));
}
}
@@ -865,20 +876,16 @@
freqMaximumHz + freqResolutionHz; // Frequency greater than allowed
active.endFrequency = freqMaximumHz + freqResolutionHz; // Frequency greater than allowed
- auto pwleQueueGreater = std::vector<PrimitivePwle>{active};
+ std::vector<PrimitivePwle> pwleQueueGreater = {active};
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr));
active.startFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed
active.endFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed
- auto pwleQueueLess = std::vector<PrimitivePwle>{active};
+ std::vector<PrimitivePwle> pwleQueueLess = {active};
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr));
}
}
@@ -890,32 +897,30 @@
vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
active.duration = segmentDurationMaxMs + 10; // Segment duration greater than allowed
- auto pwleQueue = std::vector<PrimitivePwle>{active};
+ std::vector<PrimitivePwle> pwleQueue = {active};
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
- EXPECT_TRUE(vibrator->off().isOk());
+ EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
}
}
std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
std::vector<std::tuple<int32_t, int32_t>> tuples;
- auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
- std::vector<int32_t> vibratorIds;
- for (int i = 0; i < managerAidlNames.size(); i++) {
- auto managerName = String16(managerAidlNames[i].c_str());
- auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
+ std::vector<std::string> managerNames = findVibratorManagerNames();
+ std::vector<int32_t> vibratorIds;
+ for (int i = 0; i < managerNames.size(); i++) {
+ auto vibratorManager = IVibratorManager::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(managerNames[i].c_str())));
if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) {
- for (auto &vibratorId : vibratorIds) {
- tuples.push_back(std::make_tuple(i, vibratorId));
+ for (int32_t vibratorId : vibratorIds) {
+ tuples.emplace_back(i, vibratorId);
}
}
}
- auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor);
- for (int i = 0; i < vibratorAidlNames.size(); i++) {
- tuples.push_back(std::make_tuple(-1, i));
+ std::vector<std::string> vibratorNames = findUnmanagedVibratorNames();
+ for (int i = 0; i < vibratorNames.size(); i++) {
+ tuples.emplace_back(-1, i);
}
return tuples;
@@ -936,7 +941,7 @@
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
- ProcessState::self()->setThreadPoolMaxThreadCount(1);
- ProcessState::self()->startThreadPool();
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}
diff --git a/vibrator/aidl/vts/test_utils.h b/vibrator/aidl/vts/test_utils.h
new file mode 100644
index 0000000..aaf3211
--- /dev/null
+++ b/vibrator/aidl/vts/test_utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef VIBRATOR_HAL_TEST_UTILS_H
+#define VIBRATOR_HAL_TEST_UTILS_H
+
+#include <android/binder_auto_utils.h>
+#include <gtest/gtest.h>
+
+#if !defined(EXPECT_OK)
+#define EXPECT_OK(expression) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::ndk::ScopedAStatus&& _status = (expression); _status.isOk()) \
+ ; \
+ else \
+ ADD_FAILURE() << "Expected STATUS_OK for: " << #expression << "\n Actual: " << _status
+#else
+#error Macro EXPECT_OK already defined unexpectedly
+#endif
+
+#if !defined(EXPECT_UNKNOWN_OR_UNSUPPORTED)
+#define EXPECT_UNKNOWN_OR_UNSUPPORTED(expression) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::ndk::ScopedAStatus&& _status = (expression); \
+ _status.getExceptionCode() == EX_UNSUPPORTED_OPERATION || \
+ _status.getStatus() == STATUS_UNKNOWN_TRANSACTION) \
+ ; \
+ else \
+ ADD_FAILURE() << "Expected STATUS_UNKNOWN_TRANSACTION or EX_UNSUPPORTED_OPERATION for: " \
+ << #expression << "\n Actual: " << _status
+#else
+#error Macro EXPECT_UNKNOWN_OR_UNSUPPORTED already defined unexpectedly
+#endif
+
+#if !defined(EXPECT_ILLEGAL_ARGUMENT)
+#define EXPECT_ILLEGAL_ARGUMENT(expression) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::ndk::ScopedAStatus&& _status = (expression); \
+ _status.getExceptionCode() == EX_ILLEGAL_ARGUMENT) \
+ ; \
+ else \
+ ADD_FAILURE() << "Expected EX_ILLEGAL_ARGUMENT for: " << #expression \
+ << "\n Actual: " << _status
+#else
+#error Macro EXPECT_ILLEGAL_ARGUMENT already defined unexpectedly
+#endif
+
+#endif // VIBRATOR_HAL_TEST_UTILS_H
diff --git a/vibrator/bench/Android.bp b/vibrator/bench/Android.bp
index 87bdab4..b31c719 100644
--- a/vibrator/bench/Android.bp
+++ b/vibrator/bench/Android.bp
@@ -30,12 +30,12 @@
"benchmark.cpp",
],
shared_libs: [
- "android.hardware.vibrator-V2-cpp",
+ "android.hardware.vibrator-V2-ndk",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
"android.hardware.vibrator@1.3",
- "libbinder",
+ "libbinder_ndk",
"libhardware",
"libhidlbase",
"libutils",
diff --git a/vibrator/bench/benchmark.cpp b/vibrator/bench/benchmark.cpp
index 8e8d78f..8fe9cf7 100644
--- a/vibrator/bench/benchmark.cpp
+++ b/vibrator/bench/benchmark.cpp
@@ -16,15 +16,14 @@
#include "benchmark/benchmark.h"
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
#include <future>
-using ::android::enum_range;
-using ::android::sp;
using ::android::hardware::hidl_enum_range;
using ::android::hardware::Return;
using ::android::hardware::details::hidl_enum_values;
@@ -33,10 +32,11 @@
using ::benchmark::kMicrosecond;
using ::benchmark::State;
using ::benchmark::internal::Benchmark;
+using ::ndk::enum_range;
using namespace ::std::chrono_literals;
-namespace Aidl = ::android::hardware::vibrator;
+namespace Aidl = ::aidl::android::hardware::vibrator;
namespace V1_0 = ::android::hardware::vibrator::V1_0;
namespace V1_1 = ::android::hardware::vibrator::V1_1;
namespace V1_2 = ::android::hardware::vibrator::V1_2;
@@ -56,8 +56,8 @@
class BaseBench : public Fixture {
public:
void SetUp(State& /*state*/) override {
- android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
- android::ProcessState::self()->startThreadPool();
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
}
void TearDown(State& /*state*/) override {
@@ -75,7 +75,7 @@
auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
protected:
- sp<I> mVibrator;
+ std::shared_ptr<I> mVibrator;
};
template <typename I>
@@ -83,7 +83,12 @@
public:
void SetUp(State& state) override {
BaseBench<I>::SetUp(state);
- this->mVibrator = I::getService();
+ auto service = I::getService();
+ if (service) {
+ this->mVibrator = std::shared_ptr<I>(service.release());
+ } else {
+ this->mVibrator = nullptr;
+ }
}
protected:
@@ -356,7 +361,9 @@
public:
void SetUp(State& state) override {
BaseBench::SetUp(state);
- this->mVibrator = android::waitForVintfService<Aidl::IVibrator>();
+ auto serviceName = std::string(Aidl::IVibrator::descriptor) + "/default";
+ this->mVibrator = Aidl::IVibrator::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
}
void TearDown(State& state) override {
@@ -373,9 +380,9 @@
return (deviceCapabilities & capabilities) == capabilities;
}
- bool shouldSkipWithError(State& state, const android::binder::Status&& status) {
+ bool shouldSkipWithError(State& state, const ndk::ScopedAStatus&& status) {
if (!status.isOk()) {
- state.SkipWithError(status.toString8().c_str());
+ state.SkipWithError(status.getMessage());
return true;
}
return false;
@@ -407,9 +414,9 @@
HalCallback() = default;
~HalCallback() = default;
- android::binder::Status onComplete() override {
+ ndk::ScopedAStatus onComplete() override {
mPromise.set_value();
- return android::binder::Status::ok();
+ return ndk::ScopedAStatus::ok();
}
std::future<void> getFuture() { return mPromise.get_future(); }
@@ -422,7 +429,9 @@
auto ms = MAX_ON_DURATION_MS;
for (auto _ : state) {
- auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+ auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+ ? ndk::SharedRefBase::make<HalCallback>()
+ : nullptr;
// Grab the future before callback promise is destroyed by the HAL.
auto cbFuture = cb ? cb->getFuture() : std::future<void>();
@@ -445,7 +454,9 @@
auto ms = MAX_ON_DURATION_MS;
for (auto _ : state) {
- auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+ auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+ ? ndk::SharedRefBase::make<HalCallback>()
+ : nullptr;
// Grab the future before callback promise is destroyed by the HAL.
auto cbFuture = cb ? cb->getFuture() : std::future<void>();
@@ -487,7 +498,9 @@
return;
}
- auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+ auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
+ ? ndk::SharedRefBase::make<HalCallback>()
+ : nullptr;
if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
return;
}
@@ -689,8 +702,9 @@
int32_t lengthMs = 0;
for (auto _ : state) {
- auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback()
- : nullptr;
+ auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK)
+ ? ndk::SharedRefBase::make<HalCallback>()
+ : nullptr;
// Grab the future before callback promise is destroyed by the HAL.
auto cbFuture = cb ? cb->getFuture() : std::future<void>();
@@ -803,7 +817,7 @@
effects.push_back(effect);
for (auto _ : state) {
- auto cb = new HalCallback();
+ auto cb = ndk::SharedRefBase::make<HalCallback>();
// Grab the future before callback promise is moved and destroyed by the HAL.
auto cbFuture = cb->getFuture();
diff --git a/wifi/supplicant/1.1/vts/Android.mk b/wifi/supplicant/1.1/vts/Android.mk
deleted file mode 100644
index 6361f9b..0000000
--- a/wifi/supplicant/1.1/vts/Android.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))