Merge changes I81e8ac62,I59af9750,I9a6226a9,I96b51cc9 into main
* changes:
libnetdevice: define default request flags
libnetdevice: implement ipv4 get/set/add operations
libnetdevice: migrate API to std::string_view
libnetdevice: support host
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index d47b0b1..73d7626 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -62,7 +62,6 @@
"ModulePrimary.cpp",
"SoundDose.cpp",
"Stream.cpp",
- "StreamSwitcher.cpp",
"Telephony.cpp",
"XsdcConversion.cpp",
"alsa/Mixer.cpp",
@@ -72,6 +71,7 @@
"bluetooth/DevicePortProxy.cpp",
"bluetooth/ModuleBluetooth.cpp",
"bluetooth/StreamBluetooth.cpp",
+ "deprecated/StreamSwitcher.cpp",
"primary/PrimaryMixer.cpp",
"primary/StreamPrimary.cpp",
"r_submix/ModuleRemoteSubmix.cpp",
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
index 3547f54..e57c108 100644
--- a/audio/aidl/default/config/audioPolicy/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -191,6 +191,7 @@
enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_XHE;
enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC3;
enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC4_L4;
enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_ALAC;
enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_NB;
enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_WB;
diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
index d93f697..108a6a3 100644
--- a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -389,6 +389,7 @@
<xs:enumeration value="AUDIO_FORMAT_APTX"/>
<xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
<xs:enumeration value="AUDIO_FORMAT_AC4"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC4_L4"/>
<xs:enumeration value="AUDIO_FORMAT_LDAC"/>
<xs:enumeration value="AUDIO_FORMAT_MAT"/>
<xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/deprecated/StreamSwitcher.cpp
similarity index 98%
rename from audio/aidl/default/StreamSwitcher.cpp
rename to audio/aidl/default/deprecated/StreamSwitcher.cpp
index 0052889..f1e0f52 100644
--- a/audio/aidl/default/StreamSwitcher.cpp
+++ b/audio/aidl/default/deprecated/StreamSwitcher.cpp
@@ -23,12 +23,12 @@
#include <error/expected_utils.h>
#include "core-impl/StreamStub.h"
-#include "core-impl/StreamSwitcher.h"
+#include "deprecated/StreamSwitcher.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::media::audio::common::AudioDevice;
-namespace aidl::android::hardware::audio::core {
+namespace aidl::android::hardware::audio::core::deprecated {
StreamSwitcher::StreamSwitcher(StreamContext* context, const Metadata& metadata)
: mContext(context),
@@ -268,4 +268,4 @@
return mStream->setGain(gain);
}
-} // namespace aidl::android::hardware::audio::core
+} // namespace aidl::android::hardware::audio::core::deprecated
diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/deprecated/StreamSwitcher.h
similarity index 96%
rename from audio/aidl/default/include/core-impl/StreamSwitcher.h
rename to audio/aidl/default/deprecated/StreamSwitcher.h
index 2d75e85..56fdd23 100644
--- a/audio/aidl/default/include/core-impl/StreamSwitcher.h
+++ b/audio/aidl/default/deprecated/StreamSwitcher.h
@@ -14,11 +14,18 @@
* limitations under the License.
*/
+/**
+ ** This class is deprecated because its use causes threading issues
+ ** with the FMQ due to change of threads reading and writing into FMQ.
+ **
+ ** DO NOT USE. These files will be removed.
+ **/
+
#pragma once
-#include "Stream.h"
+#include "core-impl/Stream.h"
-namespace aidl::android::hardware::audio::core {
+namespace aidl::android::hardware::audio::core::deprecated {
// 'StreamSwitcher' is an implementation of 'StreamCommonInterface' which allows
// dynamically switching the underlying stream implementation based on currently
@@ -192,4 +199,4 @@
bool mBluetoothParametersUpdated = false;
};
-} // namespace aidl::android::hardware::audio::core
+} // namespace aidl::android::hardware::audio::core::deprecated
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 6ea7968..e78e8b7 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -16,19 +16,18 @@
#pragma once
+#include <atomic>
+#include <mutex>
#include <vector>
#include "core-impl/Stream.h"
-#include "core-impl/StreamSwitcher.h"
#include "r_submix/SubmixRoute.h"
namespace aidl::android::hardware::audio::core {
class StreamRemoteSubmix : public StreamCommonImpl {
public:
- StreamRemoteSubmix(
- StreamContext* context, const Metadata& metadata,
- const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
+ StreamRemoteSubmix(StreamContext* context, const Metadata& metadata);
~StreamRemoteSubmix();
// Methods of 'DriverInterface'.
@@ -45,17 +44,18 @@
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
ndk::ScopedAStatus prepareToClose() override;
+ ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
private:
long getDelayInUsForFrameCount(size_t frameCount);
+ ::aidl::android::media::audio::common::AudioDeviceAddress getDeviceAddress() const {
+ std::lock_guard guard(mLock);
+ return mDeviceAddress;
+ }
size_t getStreamPipeSizeInFrames();
- ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount);
::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount);
-
- const ::aidl::android::media::audio::common::AudioDeviceAddress mDeviceAddress;
- const bool mIsInput;
- r_submix::AudioConfig mStreamConfig;
- std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;
+ ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount);
+ ::android::status_t setCurrentRoute();
// Limit for the number of error log entries to avoid spamming the logs.
static constexpr int kMaxErrorLogs = 5;
@@ -66,6 +66,15 @@
// 5ms between two read attempts when pipe is empty
static constexpr int kReadAttemptSleepUs = 5000;
+ const bool mIsInput;
+ const r_submix::AudioConfig mStreamConfig;
+
+ mutable std::mutex mLock;
+ ::aidl::android::media::audio::common::AudioDeviceAddress mDeviceAddress GUARDED_BY(mLock);
+ std::atomic<bool> mDeviceAddressUpdated = false;
+
+ // Used by the worker thread only.
+ std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;
int64_t mStartTimeNs = 0;
long mFramesSinceStart = 0;
int mReadErrorCount = 0;
@@ -73,7 +82,7 @@
int mWriteShutdownCount = 0;
};
-class StreamInRemoteSubmix final : public StreamIn, public StreamSwitcher {
+class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix {
public:
friend class ndk::SharedRefBase;
StreamInRemoteSubmix(
@@ -82,19 +91,13 @@
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
private:
- DeviceSwitchBehavior switchCurrentStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
- override;
- std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
- StreamContext* context, const Metadata& metadata) override;
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
ndk::ScopedAStatus getActiveMicrophones(
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
override;
};
-class StreamOutRemoteSubmix final : public StreamOut, public StreamSwitcher {
+class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix {
public:
friend class ndk::SharedRefBase;
StreamOutRemoteSubmix(
@@ -104,12 +107,6 @@
offloadInfo);
private:
- DeviceSwitchBehavior switchCurrentStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
- override;
- std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
- StreamContext* context, const Metadata& metadata) override;
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
};
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index db105b6..93fe028 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -26,128 +26,106 @@
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::hardware::audio::core::r_submix::SubmixRoute;
using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioOffloadInfo;
using aidl::android::media::audio::common::MicrophoneDynamicInfo;
using aidl::android::media::audio::common::MicrophoneInfo;
namespace aidl::android::hardware::audio::core {
-StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& metadata,
- const AudioDeviceAddress& deviceAddress)
+StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& metadata)
: StreamCommonImpl(context, metadata),
- mDeviceAddress(deviceAddress),
- mIsInput(isInput(metadata)) {
- mStreamConfig.frameSize = context->getFrameSize();
- mStreamConfig.format = context->getFormat();
- mStreamConfig.channelLayout = context->getChannelLayout();
- mStreamConfig.sampleRate = context->getSampleRate();
-}
+ mIsInput(isInput(metadata)),
+ mStreamConfig{.sampleRate = context->getSampleRate(),
+ .format = context->getFormat(),
+ .channelLayout = context->getChannelLayout(),
+ .frameSize = context->getFrameSize()} {}
StreamRemoteSubmix::~StreamRemoteSubmix() {
cleanupWorker();
}
::android::status_t StreamRemoteSubmix::init() {
- mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
- if (mCurrentRoute == nullptr) {
- return ::android::NO_INIT;
- }
- if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
- LOG(ERROR) << __func__ << ": invalid stream config";
- return ::android::NO_INIT;
- }
- sp<MonoPipe> sink = mCurrentRoute->getSink();
- if (sink == nullptr) {
- LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
- return ::android::NO_INIT;
- }
- if ((!mIsInput || mCurrentRoute->isStreamInOpen()) && sink->isShutdown()) {
- LOG(DEBUG) << __func__ << ": Shut down sink when opening stream";
- if (::android::OK != mCurrentRoute->resetPipe()) {
- LOG(ERROR) << __func__ << ": reset pipe failed";
- return ::android::NO_INIT;
- }
- }
- mCurrentRoute->openStream(mIsInput);
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) {
- usleep(1000);
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::flush() {
- usleep(1000);
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::pause() {
- usleep(1000);
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::standby() {
- mCurrentRoute->standby(mIsInput);
+ if (mCurrentRoute) mCurrentRoute->standby(mIsInput);
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::start() {
- mCurrentRoute->exitStandby(mIsInput);
+ if (mDeviceAddressUpdated.load(std::memory_order_acquire)) {
+ LOG(DEBUG) << __func__ << ": device address updated, reset current route";
+ shutdown();
+ mDeviceAddressUpdated.store(false, std::memory_order_release);
+ }
+ if (!mCurrentRoute) {
+ RETURN_STATUS_IF_ERROR(setCurrentRoute());
+ LOG(DEBUG) << __func__ << ": have current route? " << (mCurrentRoute != nullptr);
+ }
+ if (mCurrentRoute) mCurrentRoute->exitStandby(mIsInput);
mStartTimeNs = ::android::uptimeNanos();
mFramesSinceStart = 0;
return ::android::OK;
}
-ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
- if (!mIsInput) {
- std::shared_ptr<SubmixRoute> route = SubmixRoute::findRoute(mDeviceAddress);
- if (route != nullptr) {
- sp<MonoPipe> sink = route->getSink();
- if (sink == nullptr) {
- ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
- LOG(DEBUG) << __func__ << ": shutting down MonoPipe sink";
-
- sink->shutdown(true);
- // The client already considers this stream as closed, release the output end.
- route->closeStream(mIsInput);
- } else {
- LOG(DEBUG) << __func__ << ": stream already closed.";
- ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
- }
- return ndk::ScopedAStatus::ok();
-}
-
// Remove references to the specified input and output streams. When the device no longer
// references input and output streams destroy the associated pipe.
void StreamRemoteSubmix::shutdown() {
+ if (!mCurrentRoute) return;
mCurrentRoute->closeStream(mIsInput);
// If all stream instances are closed, we can remove route information for this port.
if (!mCurrentRoute->hasAtleastOneStreamOpen()) {
mCurrentRoute->releasePipe();
LOG(DEBUG) << __func__ << ": pipe destroyed";
- SubmixRoute::removeRoute(mDeviceAddress);
+ SubmixRoute::removeRoute(getDeviceAddress());
}
mCurrentRoute.reset();
}
::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount,
size_t* actualFrameCount, int32_t* latencyMs) {
+ if (mDeviceAddressUpdated.load(std::memory_order_acquire)) {
+ // 'setConnectedDevices' was called. I/O will be restarted.
+ return ::android::OK;
+ }
+
*latencyMs = getDelayInUsForFrameCount(getStreamPipeSizeInFrames()) / 1000;
LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms";
- mCurrentRoute->exitStandby(mIsInput);
- ::android::status_t status = mIsInput ? inRead(buffer, frameCount, actualFrameCount)
- : outWrite(buffer, frameCount, actualFrameCount);
- if ((status != ::android::OK && mIsInput) ||
- ((status != ::android::OK && status != ::android::DEAD_OBJECT) && !mIsInput)) {
- return status;
+ ::android::status_t status = ::android::OK;
+ if (mCurrentRoute) {
+ mCurrentRoute->exitStandby(mIsInput);
+ status = mIsInput ? inRead(buffer, frameCount, actualFrameCount)
+ : outWrite(buffer, frameCount, actualFrameCount);
+ if ((status != ::android::OK && mIsInput) ||
+ ((status != ::android::OK && status != ::android::DEAD_OBJECT) && !mIsInput)) {
+ return status;
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": no current route";
+ if (mIsInput) {
+ memset(buffer, 0, mStreamConfig.frameSize * frameCount);
+ }
+ *actualFrameCount = frameCount;
}
mFramesSinceStart += *actualFrameCount;
- if (!mIsInput && status != ::android::DEAD_OBJECT) return ::android::OK;
- // Input streams always need to block, output streams need to block when there is no sink.
- // When the sink exists, more sophisticated blocking algorithm is implemented by MonoPipe.
+ // If there is no route, always block, otherwise:
+ // - Input streams always need to block, output streams need to block when there is no sink.
+ // - When the sink exists, more sophisticated blocking algorithm is implemented by MonoPipe.
+ if (mCurrentRoute && !mIsInput && status != ::android::DEAD_OBJECT) return ::android::OK;
const long bufferDurationUs =
(*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
const auto totalDurationUs = (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
@@ -163,6 +141,10 @@
}
::android::status_t StreamRemoteSubmix::refinePosition(StreamDescriptor::Position* position) {
+ if (!mCurrentRoute) {
+ RETURN_STATUS_IF_ERROR(setCurrentRoute());
+ if (!mCurrentRoute) return ::android::OK;
+ }
sp<MonoPipeReader> source = mCurrentRoute->getSource();
if (source == nullptr) {
return ::android::NO_INIT;
@@ -186,6 +168,7 @@
// Calculate the maximum size of the pipe buffer in frames for the specified stream.
size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
+ if (!mCurrentRoute) return r_submix::kDefaultPipeSizeInFrames;
auto pipeConfig = mCurrentRoute->getPipeConfig();
const size_t maxFrameSize = std::max(mStreamConfig.frameSize, pipeConfig.frameSize);
return (pipeConfig.frameCount * pipeConfig.frameSize) / maxFrameSize;
@@ -209,7 +192,7 @@
}
mWriteShutdownCount = 0;
- LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+ LOG(VERBOSE) << __func__ << ": " << getDeviceAddress().toString() << ", " << frameCount
<< " frames";
const bool shouldBlockWrite = mCurrentRoute->shouldBlockWrite();
@@ -283,8 +266,9 @@
}
mReadErrorCount = 0;
- LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+ LOG(VERBOSE) << __func__ << ": " << getDeviceAddress().toString() << ", " << frameCount
<< " frames";
+
// read the data from the pipe
char* buff = (char*)buffer;
size_t actuallyRead = 0;
@@ -324,10 +308,91 @@
return ::android::OK;
}
+::android::status_t StreamRemoteSubmix::setCurrentRoute() {
+ const auto address = getDeviceAddress();
+ if (address == AudioDeviceAddress{}) {
+ return ::android::OK;
+ }
+ mCurrentRoute = SubmixRoute::findOrCreateRoute(address, mStreamConfig);
+ if (mCurrentRoute == nullptr) {
+ return ::android::NO_INIT;
+ }
+ if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
+ LOG(ERROR) << __func__ << ": invalid stream config";
+ return ::android::NO_INIT;
+ }
+ sp<MonoPipe> sink = mCurrentRoute->getSink();
+ if (sink == nullptr) {
+ LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
+ return ::android::NO_INIT;
+ }
+ if ((!mIsInput || mCurrentRoute->isStreamInOpen()) && sink->isShutdown()) {
+ LOG(DEBUG) << __func__ << ": Shut down sink when opening stream";
+ if (::android::OK != mCurrentRoute->resetPipe()) {
+ LOG(ERROR) << __func__ << ": reset pipe failed";
+ return ::android::NO_INIT;
+ }
+ }
+ mCurrentRoute->openStream(mIsInput);
+ return ::android::OK;
+}
+
+ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
+ if (!mIsInput) {
+ const auto address = getDeviceAddress();
+ if (address == AudioDeviceAddress{}) return ndk::ScopedAStatus::ok();
+ std::shared_ptr<SubmixRoute> route = SubmixRoute::findRoute(address);
+ if (route != nullptr) {
+ sp<MonoPipe> sink = route->getSink();
+ if (sink == nullptr) {
+ ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ LOG(DEBUG) << __func__ << ": shutting down MonoPipe sink";
+
+ sink->shutdown(true);
+ // The client already considers this stream as closed, release the output end.
+ route->closeStream(mIsInput);
+ } else {
+ LOG(DEBUG) << __func__ << ": stream already closed.";
+ ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamRemoteSubmix::setConnectedDevices(const ConnectedDevices& devices) {
+ if (devices.size() > 1) {
+ LOG(ERROR) << __func__ << ": Only single device supported, got " << devices.size();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ AudioDeviceAddress newAddress;
+ if (!devices.empty()) {
+ if (auto deviceDesc = devices.front().type;
+ (mIsInput && deviceDesc.type != AudioDeviceType::IN_SUBMIX) ||
+ (!mIsInput && deviceDesc.type != AudioDeviceType::OUT_SUBMIX)) {
+ LOG(ERROR) << __func__ << ": Device type " << toString(deviceDesc.type)
+ << " not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ newAddress = devices.front().address;
+ LOG(DEBUG) << __func__ << ": connected to " << newAddress.toString();
+ } else {
+ LOG(DEBUG) << __func__ << ": disconnected";
+ }
+ RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(devices));
+ std::lock_guard guard(mLock);
+ if (mDeviceAddress != newAddress) {
+ mDeviceAddress = newAddress;
+ mDeviceAddressUpdated.store(true, std::memory_order_release);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context,
const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones)
- : StreamIn(std::move(context), microphones), StreamSwitcher(&mContextInstance, sinkMetadata) {}
+ : StreamIn(std::move(context), microphones),
+ StreamRemoteSubmix(&mContextInstance, sinkMetadata) {}
ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones(
std::vector<MicrophoneDynamicInfo>* _aidl_return) {
@@ -336,66 +401,10 @@
return ndk::ScopedAStatus::ok();
}
-StreamSwitcher::DeviceSwitchBehavior StreamInRemoteSubmix::switchCurrentStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
- // This implementation effectively postpones stream creation until
- // receiving the first call to 'setConnectedDevices' with a non-empty list.
- if (isStubStream()) {
- if (devices.size() == 1) {
- auto deviceDesc = devices.front().type;
- if (deviceDesc.type ==
- ::aidl::android::media::audio::common::AudioDeviceType::IN_SUBMIX) {
- return DeviceSwitchBehavior::CREATE_NEW_STREAM;
- }
- LOG(ERROR) << __func__ << ": Device type " << toString(deviceDesc.type)
- << " not supported";
- } else {
- LOG(ERROR) << __func__ << ": Only single device supported.";
- }
- return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
- }
- return DeviceSwitchBehavior::USE_CURRENT_STREAM;
-}
-
-std::unique_ptr<StreamCommonInterfaceEx> StreamInRemoteSubmix::createNewStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
- StreamContext* context, const Metadata& metadata) {
- return std::unique_ptr<StreamCommonInterfaceEx>(
- new InnerStreamWrapper<StreamRemoteSubmix>(context, metadata, devices.front().address));
-}
-
StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context,
const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo)
: StreamOut(std::move(context), offloadInfo),
- StreamSwitcher(&mContextInstance, sourceMetadata) {}
-
-StreamSwitcher::DeviceSwitchBehavior StreamOutRemoteSubmix::switchCurrentStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
- // This implementation effectively postpones stream creation until
- // receiving the first call to 'setConnectedDevices' with a non-empty list.
- if (isStubStream()) {
- if (devices.size() == 1) {
- auto deviceDesc = devices.front().type;
- if (deviceDesc.type ==
- ::aidl::android::media::audio::common::AudioDeviceType::OUT_SUBMIX) {
- return DeviceSwitchBehavior::CREATE_NEW_STREAM;
- }
- LOG(ERROR) << __func__ << ": Device type " << toString(deviceDesc.type)
- << " not supported";
- } else {
- LOG(ERROR) << __func__ << ": Only single device supported.";
- }
- return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
- }
- return DeviceSwitchBehavior::USE_CURRENT_STREAM;
-}
-
-std::unique_ptr<StreamCommonInterfaceEx> StreamOutRemoteSubmix::createNewStream(
- const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
- StreamContext* context, const Metadata& metadata) {
- return std::unique_ptr<StreamCommonInterfaceEx>(
- new InnerStreamWrapper<StreamRemoteSubmix>(context, metadata, devices.front().address));
-}
+ StreamRemoteSubmix(&mContextInstance, sourceMetadata) {}
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h
index 5425f12..0097f39 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.h
+++ b/audio/aidl/default/r_submix/SubmixRoute.h
@@ -25,10 +25,12 @@
#include <media/nbaio/MonoPipe.h>
#include <media/nbaio/MonoPipeReader.h>
+#include <Utils.h>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioDeviceAddress.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+using aidl::android::hardware::audio::common::getFrameSizeInBytes;
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
@@ -56,8 +58,8 @@
AudioChannelLayout channelLayout =
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::LAYOUT_STEREO);
- size_t frameSize;
- size_t frameCount;
+ size_t frameSize = getFrameSizeInBytes(format, channelLayout);
+ size_t frameCount = 0;
};
class SubmixRoute {
diff --git a/boot/aidl/client/BootControlClient.cpp b/boot/aidl/client/BootControlClient.cpp
index 89258d2..dca98c6 100644
--- a/boot/aidl/client/BootControlClient.cpp
+++ b/boot/aidl/client/BootControlClient.cpp
@@ -18,6 +18,7 @@
#include <aidl/android/hardware/boot/IBootControl.h>
#include <android-base/logging.h>
+#include <android/binder_ibinder.h>
#include <android/binder_manager.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/boot/1.1/IBootControl.h>
@@ -65,63 +66,79 @@
using IBootControl = ::aidl::android::hardware::boot::IBootControl;
public:
- BootControlClientAidl(std::shared_ptr<IBootControl> module) : module_(module) {}
+ explicit BootControlClientAidl(std::shared_ptr<IBootControl> module)
+ : module_(module),
+ boot_control_death_recipient(AIBinder_DeathRecipient_new(onBootControlServiceDied)) {
+ binder_status_t status = AIBinder_linkToDeath(module->asBinder().get(),
+ boot_control_death_recipient, nullptr);
+ if (status != STATUS_OK) {
+ LOG(ERROR) << "Could not link to binder death";
+ return;
+ }
+ }
BootControlVersion GetVersion() const override { return BootControlVersion::BOOTCTL_AIDL; }
- ~BootControlClientAidl() = default;
- virtual int32_t GetNumSlots() const {
+ ~BootControlClientAidl() {
+ if (boot_control_death_recipient) {
+ AIBinder_unlinkToDeath(module_->asBinder().get(), boot_control_death_recipient, this);
+ }
+ }
+
+ void onBootControlServiceDied() { LOG(ERROR) << "boot control service AIDL died"; }
+
+ int32_t GetNumSlots() const override {
int32_t ret = -1;
LOG_NDK_STATUS(module_->getNumberSlots(&ret));
return ret;
}
- int32_t GetCurrentSlot() const {
+ int32_t GetCurrentSlot() const override {
int32_t ret = -1;
LOG_NDK_STATUS(module_->getCurrentSlot(&ret));
return ret;
}
- MergeStatus getSnapshotMergeStatus() const {
+ MergeStatus getSnapshotMergeStatus() const override {
MergeStatus status = MergeStatus::UNKNOWN;
LOG_NDK_STATUS(module_->getSnapshotMergeStatus(&status));
return status;
}
- std::string GetSuffix(int32_t slot) const {
+ std::string GetSuffix(int32_t slot) const override {
std::string ret;
const auto status = module_->getSuffix(slot, &ret);
if (!status.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << status.getDescription();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
+ << status.getDescription();
return {};
}
return ret;
}
- std::optional<bool> IsSlotBootable(int32_t slot) const {
+ std::optional<bool> IsSlotBootable(int32_t slot) const override {
bool ret = false;
const auto status = module_->isSlotBootable(slot, &ret);
if (!status.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << status.getDescription();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
+ << status.getDescription();
return {};
}
return ret;
}
- CommandResult MarkSlotUnbootable(int32_t slot) {
+ CommandResult MarkSlotUnbootable(int32_t slot) override {
const auto status = module_->setSlotAsUnbootable(slot);
if (!status.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << status.getDescription();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
+ << status.getDescription();
}
return {.success = status.isOk(), .errMsg = status.getDescription()};
}
- CommandResult SetActiveBootSlot(int slot) {
+ CommandResult SetActiveBootSlot(int slot) override {
const auto status = module_->setActiveBootSlot(slot);
if (!status.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << status.getDescription();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
+ << status.getDescription();
}
return {.success = status.isOk(), .errMsg = status.getDescription()};
}
@@ -132,18 +149,18 @@
}
// Check if |slot| is marked boot successfully.
- std::optional<bool> IsSlotMarkedSuccessful(int slot) const {
+ std::optional<bool> IsSlotMarkedSuccessful(int slot) const override {
bool ret = false;
const auto status = module_->isSlotMarkedSuccessful(slot, &ret);
if (!status.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << status.getDescription();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed "
+ << status.getDescription();
return {};
}
return ret;
}
- CommandResult MarkBootSuccessful() {
+ CommandResult MarkBootSuccessful() override {
const auto status = module_->markBootSuccessful();
if (!status.isOk()) {
LOG(ERROR) << __FUNCTION__ << " failed " << status.getDescription();
@@ -151,17 +168,23 @@
return {.success = status.isOk(), .errMsg = status.getDescription()};
}
- CommandResult SetSnapshotMergeStatus(aidl::android::hardware::boot::MergeStatus merge_status) {
+ CommandResult SetSnapshotMergeStatus(
+ aidl::android::hardware::boot::MergeStatus merge_status) override {
const auto status = module_->setSnapshotMergeStatus(merge_status);
if (!status.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
- << " failed " << status.getDescription();
+ LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")" << " failed "
+ << status.getDescription();
}
return {.success = status.isOk(), .errMsg = status.getDescription()};
}
private:
const std::shared_ptr<IBootControl> module_;
+ AIBinder_DeathRecipient* boot_control_death_recipient;
+ static void onBootControlServiceDied(void* client) {
+ BootControlClientAidl* self = static_cast<BootControlClientAidl*>(client);
+ self->onBootControlServiceDied();
+ }
};
using namespace android::hardware::boot;
@@ -183,7 +206,7 @@
return BootControlVersion::BOOTCTL_V1_0;
}
}
- int32_t GetNumSlots() const {
+ int32_t GetNumSlots() const override {
const auto ret = module_v1_->getNumberSlots();
if (!ret.isOk()) {
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
@@ -191,7 +214,7 @@
return ret.withDefault(-1);
}
- int32_t GetCurrentSlot() const {
+ int32_t GetCurrentSlot() const override {
const auto ret = module_v1_->getCurrentSlot();
if (!ret.isOk()) {
LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
@@ -199,23 +222,21 @@
return ret.withDefault(-1);
}
- std::string GetSuffix(int32_t slot) const {
+ std::string GetSuffix(int32_t slot) const override {
std::string suffix;
const auto ret = module_v1_->getSuffix(
slot,
[&](const ::android::hardware::hidl_string& slotSuffix) { suffix = slotSuffix; });
if (!ret.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << ret.description();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
}
return suffix;
}
- std::optional<bool> IsSlotBootable(int32_t slot) const {
+ std::optional<bool> IsSlotBootable(int32_t slot) const override {
const auto ret = module_v1_->isSlotBootable(slot);
if (!ret.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << ret.description();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
return {};
}
const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
@@ -225,7 +246,7 @@
return bool_result == V1_0::BoolResult::TRUE;
}
- CommandResult MarkSlotUnbootable(int32_t slot) {
+ CommandResult MarkSlotUnbootable(int32_t slot) override {
CommandResult result;
const auto ret =
module_v1_->setSlotAsUnbootable(slot, [&](const V1_0::CommandResult& error) {
@@ -233,26 +254,24 @@
result.errMsg = error.errMsg;
});
if (!ret.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << ret.description();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
}
return result;
}
- CommandResult SetActiveBootSlot(int32_t slot) {
+ CommandResult SetActiveBootSlot(int32_t slot) override {
CommandResult result;
const auto ret = module_v1_->setActiveBootSlot(slot, [&](const V1_0::CommandResult& error) {
result.success = error.success;
result.errMsg = error.errMsg;
});
if (!ret.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << ret.description();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
}
return result;
}
- CommandResult MarkBootSuccessful() {
+ CommandResult MarkBootSuccessful() override {
CommandResult result;
const auto ret = module_v1_->markBootSuccessful([&](const V1_0::CommandResult& error) {
result.success = error.success;
@@ -264,11 +283,10 @@
return result;
}
- std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const {
+ std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const override {
const auto ret = module_v1_->isSlotMarkedSuccessful(slot);
if (!ret.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
- << " failed " << ret.description();
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")" << " failed " << ret.description();
return {};
}
const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
@@ -278,7 +296,7 @@
return bool_result == V1_0::BoolResult::TRUE;
}
- MergeStatus getSnapshotMergeStatus() const {
+ MergeStatus getSnapshotMergeStatus() const override {
if (module_v1_1_ == nullptr) {
LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.1";
return MergeStatus::UNKNOWN;
@@ -291,7 +309,7 @@
ret.withDefault(static_cast<V1_1::MergeStatus>(MergeStatus::UNKNOWN)));
}
- CommandResult SetSnapshotMergeStatus(MergeStatus merge_status) {
+ CommandResult SetSnapshotMergeStatus(MergeStatus merge_status) override {
if (module_v1_1_ == nullptr) {
return {.success = false,
.errMsg = "setSnapshotMergeStatus is unsupported, requires at least boot v1.1"};
@@ -299,13 +317,13 @@
const auto ret =
module_v1_1_->setSnapshotMergeStatus(static_cast<V1_1::MergeStatus>(merge_status));
if (!ret.isOk()) {
- LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
- << " failed " << ret.description();
+ LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")" << " failed "
+ << ret.description();
}
return {.success = ret.isOk(), .errMsg = ret.description()};
}
- int32_t GetActiveBootSlot() const {
+ int32_t GetActiveBootSlot() const override {
if (module_v1_2_ == nullptr) {
LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.2";
return -1;
@@ -326,7 +344,6 @@
std::unique_ptr<BootControlClient> BootControlClient::WaitForService() {
const auto instance_name =
std::string(::aidl::android::hardware::boot::IBootControl::descriptor) + "/default";
-
if (AServiceManager_isDeclared(instance_name.c_str())) {
auto module = ::aidl::android::hardware::boot::IBootControl::fromBinder(
ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str())));
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
index 91196d4..abd5d7e 100644
--- a/camera/device/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -1136,6 +1136,11 @@
uint32_t v4lBufferCount = (fps >= kDefaultFps) ? mCfg.numVideoBuffers : mCfg.numStillBuffers;
+ // Double the max lag in theory.
+ mMaxLagNs = v4lBufferCount * 1000000000LL * 2 / fps;
+ ALOGI("%s: set mMaxLagNs to %" PRIu64 " ns, v4lBufferCount %u", __FUNCTION__, mMaxLagNs,
+ v4lBufferCount);
+
// VIDIOC_REQBUFS: create buffers
v4l2_requestbuffers req_buffers{};
req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -1232,40 +1237,67 @@
}
}
- ATRACE_BEGIN("VIDIOC_DQBUF");
+ uint64_t lagNs = 0;
v4l2_buffer buffer{};
- buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buffer.memory = V4L2_MEMORY_MMAP;
- if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
- ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
- return ret;
- }
- ATRACE_END();
+ do {
+ ATRACE_BEGIN("VIDIOC_DQBUF");
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_MMAP;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
+ ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
+ return ret;
+ }
+ ATRACE_END();
- if (buffer.index >= mV4L2BufferCount) {
- ALOGE("%s: Invalid buffer id: %d", __FUNCTION__, buffer.index);
- return ret;
- }
+ if (buffer.index >= mV4L2BufferCount) {
+ ALOGE("%s: Invalid buffer id: %d", __FUNCTION__, buffer.index);
+ return ret;
+ }
- if (buffer.flags & V4L2_BUF_FLAG_ERROR) {
- ALOGE("%s: v4l2 buf error! buf flag 0x%x", __FUNCTION__, buffer.flags);
- // TODO: try to dequeue again
- }
+ if (buffer.flags & V4L2_BUF_FLAG_ERROR) {
+ ALOGE("%s: v4l2 buf error! buf flag 0x%x", __FUNCTION__, buffer.flags);
+ // TODO: try to dequeue again
+ }
- if (buffer.bytesused > mMaxV4L2BufferSize) {
- ALOGE("%s: v4l2 buffer bytes used: %u maximum %u", __FUNCTION__, buffer.bytesused,
- mMaxV4L2BufferSize);
- return ret;
- }
+ if (buffer.bytesused > mMaxV4L2BufferSize) {
+ ALOGE("%s: v4l2 buffer bytes used: %u maximum %u", __FUNCTION__, buffer.bytesused,
+ mMaxV4L2BufferSize);
+ return ret;
+ }
- if (buffer.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) {
- // Ideally we should also check for V4L2_BUF_FLAG_TSTAMP_SRC_SOE, but
- // even V4L2_BUF_FLAG_TSTAMP_SRC_EOF is better than capture a timestamp now
- *shutterTs = static_cast<nsecs_t>(buffer.timestamp.tv_sec) * 1000000000LL +
- buffer.timestamp.tv_usec * 1000LL;
- } else {
- *shutterTs = systemTime(SYSTEM_TIME_MONOTONIC);
- }
+ nsecs_t curTimeNs = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ if (buffer.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) {
+ // Ideally we should also check for V4L2_BUF_FLAG_TSTAMP_SRC_SOE, but
+ // even V4L2_BUF_FLAG_TSTAMP_SRC_EOF is better than capture a timestamp now
+ *shutterTs = static_cast<nsecs_t>(buffer.timestamp.tv_sec) * 1000000000LL +
+ buffer.timestamp.tv_usec * 1000LL;
+ } else {
+ *shutterTs = curTimeNs;
+ }
+
+ // The tactic only takes effect on v4l2 buffers with flag V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC.
+ // Most USB cameras should have the feature.
+ if (curTimeNs < *shutterTs) {
+ lagNs = 0;
+ ALOGW("%s: should not happen, the monotonic clock has issue, shutterTs is in the "
+ "future, curTimeNs %" PRId64 " < "
+ "shutterTs %" PRId64 "",
+ __func__, curTimeNs, *shutterTs);
+ } else {
+ lagNs = curTimeNs - *shutterTs;
+ }
+
+ if (lagNs > mMaxLagNs) {
+ ALOGI("%s: drop too old buffer, index %d, lag %" PRIu64 " ns > max %" PRIu64 " ns", __FUNCTION__,
+ buffer.index, lagNs, mMaxLagNs);
+ int retVal = ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer);
+ if (retVal) {
+ ALOGE("%s: unexpected VIDIOC_QBUF failed, retVal %d", __FUNCTION__, retVal);
+ return ret;
+ }
+ }
+ } while (lagNs > mMaxLagNs);
{
std::lock_guard<std::mutex> lk(mV4l2BufferLock);
diff --git a/camera/device/default/ExternalCameraDeviceSession.h b/camera/device/default/ExternalCameraDeviceSession.h
index 795b589..1c6ed06 100644
--- a/camera/device/default/ExternalCameraDeviceSession.h
+++ b/camera/device/default/ExternalCameraDeviceSession.h
@@ -382,6 +382,9 @@
std::string mExifMake;
std::string mExifModel;
/* End of members not changed after initialize() */
+
+ // The max tolerant lag between the dequeued v4l2 buffer and current capture request.
+ uint64_t mMaxLagNs;
};
} // namespace implementation
diff --git a/graphics/Android.bp b/graphics/Android.bp
index c33f7ff..9e604a1 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -18,9 +18,13 @@
cc_defaults {
name: "android.hardware.graphics.allocator-ndk_static",
- static_libs: [
- "android.hardware.graphics.allocator-V2-ndk",
- ],
+ target: {
+ linux: {
+ static_libs: [
+ "android.hardware.graphics.allocator-V2-ndk",
+ ],
+ },
+ },
defaults: [
"android.hardware.graphics.common-ndk_static",
],
@@ -28,9 +32,13 @@
cc_defaults {
name: "android.hardware.graphics.allocator-ndk_shared",
- shared_libs: [
- "android.hardware.graphics.allocator-V2-ndk",
- ],
+ target: {
+ linux: {
+ shared_libs: [
+ "android.hardware.graphics.allocator-V2-ndk",
+ ],
+ },
+ },
defaults: [
"android.hardware.graphics.common-ndk_shared",
],
@@ -38,30 +46,46 @@
cc_defaults {
name: "android.hardware.graphics.common-ndk_static",
- static_libs: [
- "android.hardware.graphics.common-V5-ndk",
- ],
+ target: {
+ linux: {
+ static_libs: [
+ "android.hardware.graphics.common-V5-ndk",
+ ],
+ },
+ },
}
cc_defaults {
name: "android.hardware.graphics.common-ndk_shared",
- shared_libs: [
- "android.hardware.graphics.common-V5-ndk",
- ],
+ target: {
+ linux: {
+ shared_libs: [
+ "android.hardware.graphics.common-V5-ndk",
+ ],
+ },
+ },
}
cc_defaults {
name: "android.hardware.graphics.composer3-ndk_static",
- static_libs: [
- "android.hardware.drm.common-V1-ndk",
- "android.hardware.graphics.composer3-V4-ndk",
- ],
+ target: {
+ linux: {
+ static_libs: [
+ "android.hardware.drm.common-V1-ndk",
+ "android.hardware.graphics.composer3-V4-ndk",
+ ],
+ },
+ },
}
cc_defaults {
name: "android.hardware.graphics.composer3-ndk_shared",
- shared_libs: [
- "android.hardware.drm.common-V1-ndk",
- "android.hardware.graphics.composer3-V4-ndk",
- ],
+ target: {
+ linux: {
+ shared_libs: [
+ "android.hardware.drm.common-V1-ndk",
+ "android.hardware.graphics.composer3-V4-ndk",
+ ],
+ },
+ },
}
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
index 82306be..f4196b9 100644
--- a/graphics/mapper/stable-c/Android.bp
+++ b/graphics/mapper/stable-c/Android.bp
@@ -111,7 +111,7 @@
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
"android.hardware.graphics.allocator-ndk_shared",
- "android.hardware.graphics.common-ndk_shared",
+ "android.hardware.graphics.common-ndk_static",
],
srcs: [
"vts/VtsHalGraphicsMapperStableC_TargetTest.cpp",
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 914cad0..3d24165 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -609,6 +609,11 @@
}
}
+ if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+ GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Cdma2000 "
+ "due to undefined FEATURE_TELEPHONY_CDMA";
+ }
+
serial = GetRandomSerialNumber();
SignalThresholdInfo signalThresholdInfo;
@@ -824,9 +829,12 @@
signalThresholdInfoNgran.isEnabled = true;
signalThresholdInfoNgran.ran = AccessNetwork::NGRAN;
- const static std::vector<SignalThresholdInfo> candidateSignalThresholdInfos = {
+ std::vector<SignalThresholdInfo> candidateSignalThresholdInfos = {
signalThresholdInfoGeran, signalThresholdInfoUtran, signalThresholdInfoEutran,
- signalThresholdInfoCdma2000, signalThresholdInfoNgran};
+ signalThresholdInfoNgran};
+ if (deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+ candidateSignalThresholdInfos.push_back(signalThresholdInfoCdma2000);
+ }
std::vector<SignalThresholdInfo> supportedSignalThresholdInfos;
for (size_t i = 0; i < candidateSignalThresholdInfos.size(); i++) {
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index f669110..9e3e159 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -253,39 +253,14 @@
// Collection of valid attestation ID tags.
auto attestation_id_tags = AuthorizationSetBuilder();
- // Use ro.product.brand_for_attestation property for attestation if it is present else fallback
- // to ro.product.brand
- std::string prop_value =
- ::android::base::GetProperty("ro.product.brand_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND,
- "ro.product.brand_for_attestation");
- } else {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
- }
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
- // Use ro.product.name_for_attestation property for attestation if it is present else fallback
- // to ro.product.name
- prop_value = ::android::base::GetProperty("ro.product.name_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT,
- "ro.product.name_for_attestation");
- } else {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- }
+
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "brand");
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "device");
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
- "ro.product.manufacturer");
- // Use ro.product.model_for_attestation property for attestation if it is present else fallback
- // to ro.product.model
- prop_value =
- ::android::base::GetProperty("ro.product.model_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL,
- "ro.product.model_for_attestation");
- } else {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
- }
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "model");
+
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index c19ab11..cfe9fa7 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -2400,6 +2400,43 @@
return imei;
}
+std::optional<std::string> get_attestation_id(const char* prop) {
+ // The frameworks code (in AndroidKeyStoreKeyPairGeneratorSpi.java) populates device ID
+ // values from one of 3 places, so the same logic needs to be reproduced here so the tests
+ // check what's expected correctly.
+ //
+ // In order of preference, the properties checked are:
+ //
+ // 1) `ro.product.<device-id>_for_attestation`: This should only be set in special cases; in
+ // particular, AOSP builds for reference devices use a different value than the normal
+ // builds for the same device (e.g. model of "aosp_raven" instead of "raven").
+ ::android::String8 prop_name =
+ ::android::String8::format("ro.product.%s_for_attestation", prop);
+ std::string prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+ if (!prop_value.empty()) {
+ return prop_value;
+ }
+
+ // 2) `ro.product.vendor.<device-id>`: This property refers to the vendor code, and so is
+ // retained even in a GSI environment.
+ prop_name = ::android::String8::format("ro.product.vendor.%s", prop);
+ prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+ if (!prop_value.empty()) {
+ return prop_value;
+ }
+
+ // 3) `ro.product.<device-id>`: Note that this property is replaced by a default value when
+ // running a GSI environment, and so will *not* match the value expected/used by the
+ // vendor code on the device.
+ prop_name = ::android::String8::format("ro.product.%s", prop);
+ prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+ if (!prop_value.empty()) {
+ return prop_value;
+ }
+
+ return std::nullopt;
+}
+
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 0368bba..85ae93d 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -17,6 +17,7 @@
#pragma once
#include <functional>
+#include <optional>
#include <string_view>
#include <aidl/Gtest.h>
@@ -384,14 +385,20 @@
const string& plaintext, const string& exp_cipher_text);
};
+// If the given string is non-empty, add it to the tag set under the given tag ID.
+template <Tag tag>
+void add_tag(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
+ const std::string& prop_value) {
+ if (!prop_value.empty()) {
+ tags->Authorization(ttag, prop_value.data(), prop_value.size());
+ }
+}
+
// If the given property is available, add it to the tag set under the given tag ID.
template <Tag tag>
void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
const char* prop) {
- std::string prop_value = ::android::base::GetProperty(prop, /* default= */ "");
- if (!prop_value.empty()) {
- tags->Authorization(ttag, prop_value.data(), prop_value.size());
- }
+ add_tag(tags, ttag, ::android::base::GetProperty(prop, /* default= */ ""));
}
// Return the VSR API level for this device.
@@ -431,6 +438,20 @@
std::optional<int32_t> keymint_feature_value(bool strongbox);
std::string get_imei(int slot);
+// Retrieve a device ID property value, to match what is expected in attestations.
+std::optional<std::string> get_attestation_id(const char* prop);
+
+// Add the appropriate attestation device ID tag value to the provided `AuthorizationSetBuilder`,
+// if found.
+template <Tag tag>
+void add_attestation_id(AuthorizationSetBuilder* attestation_id_tags,
+ TypedTag<TagType::BYTES, tag> tag_type, const char* prop) {
+ auto prop_value = get_attestation_id(prop);
+ if (prop_value.has_value()) {
+ add_tag(attestation_id_tags, tag_type, prop_value.value());
+ }
+}
+
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain,
@@ -444,29 +465,6 @@
::android::PrintInstanceNameToString); \
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);
-// Use `ro.product.<property>_for_attestation` property for attestation if it is present else
-// fallback to use `ro.product.vendor.<property>` if it is present else fallback to
-// `ro.product.<property>`. Similar logic can be seen in Java method `getVendorDeviceIdProperty`
-// in frameworks/base/core/java/android/os/Build.java.
-template <Tag tag>
-void add_attestation_id(AuthorizationSetBuilder* attestation_id_tags,
- TypedTag<TagType::BYTES, tag> tag_type, const char* prop) {
- ::android::String8 prop_name =
- ::android::String8::format("ro.product.%s_for_attestation", prop);
- std::string prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
- } else {
- prop_name = ::android::String8::format("ro.product.vendor.%s", prop);
- prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
- } else {
- prop_name = ::android::String8::format("ro.product.%s", prop);
- add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
- }
- }
-}
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl
new file mode 100644
index 0000000..50e1bbb
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable ApIfaceParams {
+ android.hardware.wifi.IfaceConcurrencyType ifaceType;
+ boolean usesMlo;
+ @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
index e71dde4..af95bee 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
@@ -40,4 +40,5 @@
void setCountryCode(in byte[2] code);
void resetToFactoryMacAddress();
void setMacAddress(in byte[6] mac);
+ boolean usesMlo();
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index 5fe7c53..1af0d65 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -35,7 +35,13 @@
@VintfStability
interface IWifiChip {
void configureChip(in int modeId);
+ /**
+ * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams.
+ */
@PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApIface();
+ /**
+ * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams.
+ */
@PropagateAllowBlocking android.hardware.wifi.IWifiApIface createBridgedApIface();
@PropagateAllowBlocking android.hardware.wifi.IWifiNanIface createNanIface();
@PropagateAllowBlocking android.hardware.wifi.IWifiP2pIface createP2pIface();
@@ -83,8 +89,12 @@
void triggerSubsystemRestart();
void enableStaChannelForPeerNetwork(in int channelCategoryEnableFlag);
void setMloMode(in android.hardware.wifi.IWifiChip.ChipMloMode mode);
+ /**
+ * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams.
+ */
@PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApOrBridgedApIface(in android.hardware.wifi.IfaceConcurrencyType iface, in android.hardware.wifi.common.OuiKeyedData[] vendorData);
void setVoipMode(in android.hardware.wifi.IWifiChip.VoipMode mode);
+ @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApOrBridgedApIfaceWithParams(in android.hardware.wifi.ApIfaceParams params);
const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF;
@Backing(type="int") @VintfStability
enum FeatureSetMask {
diff --git a/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl b/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl
new file mode 100644
index 0000000..f075b72
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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 android.hardware.wifi;
+
+import android.hardware.wifi.IfaceConcurrencyType;
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters to use for setting up the access point interfaces.
+ */
+@VintfStability
+parcelable ApIfaceParams {
+ /**
+ * IfaceConcurrencyType to be created. Takes one of
+ * |IfaceConcurrencyType.AP| or |IfaceConcurrencyType.AP_BRIDGED|
+ */
+ IfaceConcurrencyType ifaceType;
+ /**
+ * Whether the current iface will be operated on Multi-links on the one MLD device (MLO).
+ */
+ boolean usesMlo;
+ /**
+ * Optional vendor-specific configuration parameters.
+ */
+ @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
index b14a800..a350e52 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
@@ -85,4 +85,11 @@
* |WifiStatusCode.ERROR_UNKNOWN|
*/
void setMacAddress(in byte[6] mac);
+
+ /**
+ * Check if ApIface is for an AP using Multi-Link Operation
+ *
+ * @return true if it is MLO iface, false otherwise.
+ */
+ boolean usesMlo();
}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index 4e418d8..04f31d2 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -17,6 +17,7 @@
package android.hardware.wifi;
import android.hardware.wifi.AfcChannelAllowance;
+import android.hardware.wifi.ApIfaceParams;
import android.hardware.wifi.IWifiApIface;
import android.hardware.wifi.IWifiChipEventCallback;
import android.hardware.wifi.IWifiNanIface;
@@ -433,6 +434,9 @@
* reached the maximum allowed (specified in |ChipIfaceCombination|) number
* of ifaces of the AP type.
*
+ * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+ * createApOrBridgedApIfaceWithParams.
+ *
* @return AIDL interface object representing the iface if
* successful, null otherwise.
* @throws ServiceSpecificException with one of the following values:
@@ -450,6 +454,9 @@
* reached the maximum allowed (specified in |ChipIfaceCombination|) number
* of ifaces of the AP type.
*
+ * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+ * createApOrBridgedApIfaceWithParams.
+ *
* @return AIDL interface object representing the iface if
* successful, null otherwise.
* @throws ServiceSpecificException with one of the following values:
@@ -1177,6 +1184,9 @@
* reached the maximum allowed (specified in |ChipIfaceCombination|) number
* of ifaces of the AP or AP_BRIDGED type.
*
+ * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+ * createApOrBridgedApIfaceWithParams.
+ *
* @param iface IfaceConcurrencyType to be created. Takes one of
|IfaceConcurrencyType.AP| or |IfaceConcurrencyType.AP_BRIDGED|
* @param vendorData Vendor-provided configuration data as a list of |OuiKeyedData|.
@@ -1210,4 +1220,22 @@
* |WifiStatusCode.ERROR_UNKNOWN|
*/
void setVoipMode(in VoipMode mode);
+
+ /**
+ * Create an AP or bridged AP iface on the chip based on ApIfaceParamss.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+ * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+ * of ifaces of the AP type.
+ *
+ * @return AIDL interface object representing the iface if
+ * successful, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ @PropagateAllowBlocking
+ IWifiApIface createApOrBridgedApIfaceWithParams(in ApIfaceParams params);
}
diff --git a/wifi/aidl/default/wifi_ap_iface.cpp b/wifi/aidl/default/wifi_ap_iface.cpp
index 7779750..6a73cc8 100644
--- a/wifi/aidl/default/wifi_ap_iface.cpp
+++ b/wifi/aidl/default/wifi_ap_iface.cpp
@@ -28,10 +28,12 @@
namespace wifi {
using aidl_return_util::validateAndCall;
-WifiApIface::WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+WifiApIface::WifiApIface(const std::string& ifname, const bool usesMlo,
+ const std::vector<std::string>& instances,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: ifname_(ifname),
+ uses_mlo_(usesMlo),
instances_(instances),
legacy_hal_(legacy_hal),
iface_util_(iface_util),
@@ -50,6 +52,10 @@
return ifname_;
}
+bool WifiApIface::usesMlo() {
+ return uses_mlo_;
+}
+
void WifiApIface::removeInstance(std::string instance) {
instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end());
}
@@ -72,7 +78,7 @@
ndk::ScopedAStatus WifiApIface::getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::getFactoryMacAddressInternal, _aidl_return,
- instances_.size() > 0 ? instances_[0] : ifname_);
+ getOperatingInstanceName());
}
ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddress() {
@@ -90,14 +96,14 @@
}
ndk::ScopedAStatus WifiApIface::setCountryCodeInternal(const std::array<uint8_t, 2>& code) {
- legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
- instances_.size() > 0 ? instances_[0] : ifname_, code);
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setCountryCode(getOperatingInstanceName(), code);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiApIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
// Support random MAC up to 2 interfaces
- if (instances_.size() == 2) {
+ if (instances_.size() == 2 && !uses_mlo_) {
int rbyte = 1;
for (auto const& intf : instances_) {
std::array<uint8_t, 6> rmac = mac;
@@ -131,7 +137,7 @@
ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddressInternal() {
std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getMacResult;
- if (instances_.size() == 2) {
+ if (instances_.size() == 2 && !uses_mlo_) {
for (auto const& intf : instances_) {
getMacResult = getFactoryMacAddressInternal(intf);
LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
@@ -166,6 +172,11 @@
return {instances_, ndk::ScopedAStatus::ok()};
}
+ndk::ScopedAStatus WifiApIface::usesMlo(bool* _aidl_return) {
+ *_aidl_return = uses_mlo_;
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/aidl/default/wifi_ap_iface.h b/wifi/aidl/default/wifi_ap_iface.h
index 7378f98..e07154d 100644
--- a/wifi/aidl/default/wifi_ap_iface.h
+++ b/wifi/aidl/default/wifi_ap_iface.h
@@ -33,13 +33,15 @@
*/
class WifiApIface : public BnWifiApIface {
public:
- WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+ WifiApIface(const std::string& ifname, const bool usesMlo,
+ const std::vector<std::string>& instances,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
std::string getName();
+ bool usesMlo();
void removeInstance(std::string instance);
// AIDL methods exposed.
@@ -49,6 +51,7 @@
ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
ndk::ScopedAStatus resetToFactoryMacAddress() override;
ndk::ScopedAStatus getBridgedInstances(std::vector<std::string>* _aidl_return) override;
+ ndk::ScopedAStatus usesMlo(bool* _aidl_return) override;
private:
// Corresponding worker functions for the AIDL methods.
@@ -61,11 +64,18 @@
std::pair<std::vector<std::string>, ndk::ScopedAStatus> getBridgedInstancesInternal();
std::string ifname_;
+ bool uses_mlo_;
std::vector<std::string> instances_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
bool is_valid_;
+ // The mlo is using one interface but owning two link instances.
+ // The operating should be based on interface.
+ inline std::string getOperatingInstanceName() {
+ return (instances_.size() > 0 && !uses_mlo_) ? instances_[0] : ifname_;
+ };
+
DISALLOW_COPY_AND_ASSIGN(WifiApIface);
};
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index fccfc15..045e07d 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -369,7 +369,7 @@
ndk::ScopedAStatus WifiChip::createBridgedApIface(std::shared_ptr<IWifiApIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::createBridgedApIfaceInternal, _aidl_return);
+ &WifiChip::createBridgedApIfaceInternal, _aidl_return, false);
}
ndk::ScopedAStatus WifiChip::createApOrBridgedApIface(
@@ -613,6 +613,13 @@
&WifiChip::setVoipModeInternal, in_mode);
}
+ndk::ScopedAStatus WifiChip::createApOrBridgedApIfaceWithParams(
+ const ApIfaceParams& in_params, std::shared_ptr<IWifiApIface>* _aidl_return) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createApOrBridgedApIfaceWithParamsInternal, _aidl_return,
+ in_params);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
@@ -797,15 +804,15 @@
return ndk::ScopedAStatus::ok();
}
-std::shared_ptr<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
+std::shared_ptr<WifiApIface> WifiChip::newWifiApIface(std::string& ifname, bool usesMlo) {
std::vector<std::string> ap_instances;
for (auto const& it : br_ifaces_ap_instances_) {
if (it.first == ifname) {
ap_instances = it.second;
}
}
- std::shared_ptr<WifiApIface> iface =
- ndk::SharedRefBase::make<WifiApIface>(ifname, ap_instances, legacy_hal_, iface_util_);
+ std::shared_ptr<WifiApIface> iface = ndk::SharedRefBase::make<WifiApIface>(
+ ifname, usesMlo, ap_instances, legacy_hal_, iface_util_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
@@ -826,47 +833,60 @@
if (!status.isOk()) {
return {std::shared_ptr<WifiApIface>(), std::move(status)};
}
- std::shared_ptr<WifiApIface> iface = newWifiApIface(ifname);
+ std::shared_ptr<WifiApIface> iface = newWifiApIface(ifname, false);
return {iface, ndk::ScopedAStatus::ok()};
}
-std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
-WifiChip::createBridgedApIfaceInternal() {
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> WifiChip::createBridgedApIfaceInternal(
+ bool usesMlo) {
if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
- std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
+ std::string br_ifname;
+ std::vector<std::string> ap_instances = allocateBridgedApInstanceNames(usesMlo);
if (ap_instances.size() < 2) {
LOG(ERROR) << "Fail to allocate two instances";
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
- std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
- for (int i = 0; i < 2; i++) {
- ndk::ScopedAStatus status = createVirtualApInterface(ap_instances[i]);
- if (!status.isOk()) {
- if (i != 0) { // The failure happened when creating second virtual
- // iface.
- legacy_hal_.lock()->deleteVirtualInterface(
- ap_instances.front()); // Remove the first virtual iface.
+ if (usesMlo) {
+ // MLO SoftAp is using single interface with two links. So only need to create 1 interface.
+ br_ifname = allocateApIfaceName();
+ } else {
+ br_ifname = kApBridgeIfacePrefix + ap_instances[0];
+ for (int i = 0; i < 2; i++) {
+ ndk::ScopedAStatus status = createVirtualApInterface(ap_instances[i]);
+ if (!status.isOk()) {
+ if (i != 0) { // The failure happened when creating second virtual
+ // iface.
+ legacy_hal_.lock()->deleteVirtualInterface(
+ ap_instances.front()); // Remove the first virtual iface.
+ }
+ return {nullptr, std::move(status)};
}
- return {nullptr, std::move(status)};
}
}
br_ifaces_ap_instances_[br_ifname] = ap_instances;
- if (!iface_util_->createBridge(br_ifname)) {
- LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
- deleteApIface(br_ifname);
- return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
- }
- for (auto const& instance : ap_instances) {
- // Bind ap instance interface to AP bridge
- if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
- LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
+ if (usesMlo) {
+ ndk::ScopedAStatus status = createVirtualApInterface(br_ifname);
+ if (!status.isOk()) {
+ return {nullptr, std::move(status)};
+ }
+ } else {
+ if (!iface_util_->createBridge(br_ifname)) {
+ LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
deleteApIface(br_ifname);
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
+ for (auto const& instance : ap_instances) {
+ // Bind ap instance interface to AP bridge
+ if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
+ LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
+ deleteApIface(br_ifname);
+ return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+ }
+ }
}
- std::shared_ptr<WifiApIface> iface = newWifiApIface(br_ifname);
+ std::shared_ptr<WifiApIface> iface = newWifiApIface(br_ifname, usesMlo);
return {iface, ndk::ScopedAStatus::ok()};
}
@@ -876,7 +896,18 @@
if (ifaceType == IfaceConcurrencyType::AP) {
return createApIfaceInternal();
} else if (ifaceType == IfaceConcurrencyType::AP_BRIDGED) {
- return createBridgedApIfaceInternal();
+ return createBridgedApIfaceInternal(false);
+ } else {
+ return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+ }
+}
+
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
+WifiChip::createApOrBridgedApIfaceWithParamsInternal(const ApIfaceParams& params) {
+ if (params.ifaceType == IfaceConcurrencyType::AP) {
+ return createApIfaceInternal();
+ } else if (params.ifaceType == IfaceConcurrencyType::AP_BRIDGED) {
+ return createBridgedApIfaceInternal(params.usesMlo);
} else {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
@@ -925,23 +956,28 @@
if (!iface.get() || ifInstanceName.empty()) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
+
// Requires to remove one of the instance in bridge mode
for (auto const& it : br_ifaces_ap_instances_) {
if (it.first == ifname) {
std::vector<std::string> ap_instances = it.second;
- for (auto const& iface : ap_instances) {
- if (iface == ifInstanceName) {
- if (!iface_util_->removeIfaceFromBridge(it.first, iface)) {
- LOG(ERROR) << "Failed to remove interface: " << ifInstanceName << " from "
- << ifname;
- return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->deleteVirtualInterface(iface);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to del interface: " << iface << " "
- << legacyErrorToString(legacy_status);
- return createWifiStatusFromLegacyError(legacy_status);
+ for (auto const& instance : ap_instances) {
+ if (instance == ifInstanceName) {
+ if (iface->usesMlo()) {
+ LOG(INFO) << "Remove Link " << ifInstanceName << " from " << ifname;
+ } else {
+ if (!iface_util_->removeIfaceFromBridge(it.first, instance)) {
+ LOG(ERROR) << "Failed to remove interface: " << ifInstanceName
+ << " from " << ifname;
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->deleteVirtualInterface(instance);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to del interface: " << instance << " "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
}
ap_instances.erase(
std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName),
@@ -1729,7 +1765,7 @@
// If the first active wlan iface is bridged iface.
// Return first instance name.
for (auto const& it : br_ifaces_ap_instances_) {
- if (it.first == ap_ifaces_[0]->getName()) {
+ if (it.first == ap_ifaces_[0]->getName() && !ap_ifaces_[0]->usesMlo()) {
return it.second[0];
}
}
@@ -1782,9 +1818,19 @@
return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
}
-std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
- // Check if we have a dedicated iface for AP.
- std::vector<std::string> instances = getPredefinedApIfaceNames(true);
+std::vector<std::string> WifiChip::allocateBridgedApInstanceNames(bool usesMlo) {
+ std::vector<std::string> instances;
+ if (usesMlo) {
+ // For MLO AP, the instances are MLO links and it will be maintained in hostapd.
+ // The hostapd will use 0 as an initial link id and 1 as the next.
+ // Considering Android didn't support link reconfiguration. Forcing to use 0 & 1
+ // should work.
+ instances.push_back("0");
+ instances.push_back("1");
+ } else {
+ // Check if we have a dedicated iface for AP.
+ instances = getPredefinedApIfaceNames(true);
+ }
if (instances.size() == 2) {
return instances;
} else {
@@ -1856,11 +1902,14 @@
void WifiChip::invalidateAndClearBridgedApAll() {
for (auto const& it : br_ifaces_ap_instances_) {
- for (auto const& iface : it.second) {
- iface_util_->removeIfaceFromBridge(it.first, iface);
- legacy_hal_.lock()->deleteVirtualInterface(iface);
+ const auto iface = findUsingName(ap_ifaces_, it.first);
+ if (!iface->usesMlo()) {
+ for (auto const& iface : it.second) {
+ iface_util_->removeIfaceFromBridge(it.first, iface);
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ }
+ iface_util_->deleteBridge(it.first);
}
- iface_util_->deleteBridge(it.first);
}
br_ifaces_ap_instances_.clear();
}
@@ -1868,16 +1917,19 @@
void WifiChip::deleteApIface(const std::string& if_name) {
if (if_name.empty()) return;
// delete bridged interfaces if any
- for (auto const& it : br_ifaces_ap_instances_) {
- if (it.first == if_name) {
- for (auto const& iface : it.second) {
- iface_util_->removeIfaceFromBridge(if_name, iface);
- legacy_hal_.lock()->deleteVirtualInterface(iface);
+ const auto iface = findUsingName(ap_ifaces_, if_name);
+ if (!iface->usesMlo()) {
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == if_name) {
+ for (auto const& instance : it.second) {
+ iface_util_->removeIfaceFromBridge(if_name, instance);
+ legacy_hal_.lock()->deleteVirtualInterface(instance);
+ }
+ iface_util_->deleteBridge(if_name);
+ br_ifaces_ap_instances_.erase(if_name);
+ // ifname is bridged AP, return here.
+ return;
}
- iface_util_->deleteBridge(if_name);
- br_ifaces_ap_instances_.erase(if_name);
- // ifname is bridged AP, return here.
- return;
}
}
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
index ffd507f..24dd00d 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -159,6 +159,8 @@
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
ndk::ScopedAStatus setMloMode(const ChipMloMode in_mode) override;
ndk::ScopedAStatus setVoipMode(const VoipMode in_mode) override;
+ ndk::ScopedAStatus createApOrBridgedApIfaceWithParams(
+ const ApIfaceParams& in_params, std::shared_ptr<IWifiApIface>* _aidl_return) override;
private:
void invalidateAndRemoveAllIfaces();
@@ -178,12 +180,15 @@
std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> requestChipDebugInfoInternal();
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestDriverDebugDumpInternal();
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestFirmwareDebugDumpInternal();
- std::shared_ptr<WifiApIface> newWifiApIface(std::string& ifname);
+ std::shared_ptr<WifiApIface> newWifiApIface(std::string& ifname, bool usesMlo);
ndk::ScopedAStatus createVirtualApInterface(const std::string& apVirtIf);
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApIfaceInternal();
- std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createBridgedApIfaceInternal();
+ std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createBridgedApIfaceInternal(
+ bool usesMlo);
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApOrBridgedApIfaceInternal(
IfaceConcurrencyType ifaceType, const std::vector<common::OuiKeyedData>& vendorData);
+ std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
+ createApOrBridgedApIfaceWithParamsInternal(const ApIfaceParams& params);
std::pair<std::vector<std::string>, ndk::ScopedAStatus> getApIfaceNamesInternal();
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> getApIfaceInternal(
const std::string& ifname);
@@ -258,7 +263,7 @@
std::string getFirstActiveWlanIfaceName();
std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
std::string allocateApIfaceName();
- std::vector<std::string> allocateBridgedApInstanceNames();
+ std::vector<std::string> allocateBridgedApInstanceNames(bool usesMlo);
std::string allocateStaIfaceName();
bool writeRingbufferFilesInternal();
std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
index 8da3441..7b67102 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -39,5 +39,5 @@
android.hardware.wifi.hostapd.ChannelParams[] channelParams;
@nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
@nullable String[] instanceIdentities;
- boolean isMlo;
+ boolean usesMlo;
}
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
index bb646e3..f4e4647 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -46,7 +46,7 @@
*/
@nullable String[] instanceIdentities;
/**
- * Whether the current iface is MLO.
+ * Whether the current iface is using multi-link operation.
*/
- boolean isMlo;
+ boolean usesMlo;
}