Merge "Revert^2 "AAudio: add support of Audio Attributes tags"" into main
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 2d1af32..daa2656 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -22,12 +22,14 @@
#include <camera/camera2/OutputConfiguration.h>
#include <camera/StringUtils.h>
+#include <com_android_internal_camera_flags.h>
#include <binder/Parcel.h>
#include <gui/view/Surface.h>
#include <system/camera_metadata.h>
#include <system/graphics.h>
#include <utils/String8.h>
+namespace flags = com::android::internal::camera::flags;
namespace android {
@@ -95,7 +97,27 @@
return mTimestampBase;
}
-int OutputConfiguration::getMirrorMode() const {
+int OutputConfiguration::getMirrorMode(sp<IGraphicBufferProducer> surface) const {
+ if (!flags::mirror_mode_shared_surfaces()) {
+ return mMirrorMode;
+ }
+
+ if (mGbps.size() != mMirrorModeForProducers.size()) {
+ ALOGE("%s: mGbps size doesn't match mMirrorModeForProducers: %zu vs %zu",
+ __FUNCTION__, mGbps.size(), mMirrorModeForProducers.size());
+ return mMirrorMode;
+ }
+
+ // Use per-producer mirror mode if available.
+ for (size_t i = 0; i < mGbps.size(); i++) {
+ if (mGbps[i] == surface) {
+ return mMirrorModeForProducers[i];
+ }
+ }
+
+ // For surface that doesn't belong to this output configuration, use
+ // mMirrorMode as default.
+ ALOGW("%s: Surface doesn't belong to this OutputConfiguration!", __FUNCTION__);
return mMirrorMode;
}
@@ -251,6 +273,12 @@
return err;
}
+ std::vector<int> mirrorModeForProducers;
+ if ((err = parcel->readInt32Vector(&mirrorModeForProducers)) != OK) {
+ ALOGE("%s: Failed to read mirroring mode for surfaces from parcel", __FUNCTION__);
+ return err;
+ }
+
int useReadoutTimestamp = 0;
if ((err = parcel->readInt32(&useReadoutTimestamp)) != OK) {
ALOGE("%s: Failed to read useReadoutTimestamp flag from parcel", __FUNCTION__);
@@ -286,6 +314,7 @@
mStreamUseCase = streamUseCase;
mTimestampBase = timestampBase;
mMirrorMode = mirrorMode;
+ mMirrorModeForProducers = std::move(mirrorModeForProducers);
mUseReadoutTimestamp = useReadoutTimestamp != 0;
for (auto& surface : surfaceShims) {
ALOGV("%s: OutputConfiguration: %p, name %s", __FUNCTION__,
@@ -327,6 +356,7 @@
mStreamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
mTimestampBase = TIMESTAMP_BASE_DEFAULT;
mMirrorMode = MIRROR_MODE_AUTO;
+ mMirrorModeForProducers.push_back(mMirrorMode);
mUseReadoutTimestamp = false;
mFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
mDataspace = 0;
@@ -344,9 +374,9 @@
mColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
mTimestampBase(TIMESTAMP_BASE_DEFAULT),
- mMirrorMode(MIRROR_MODE_AUTO), mUseReadoutTimestamp(false),
- mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), mDataspace(0),
- mUsage(0) { }
+ mMirrorMode(MIRROR_MODE_AUTO), mMirrorModeForProducers(gbps.size(), mMirrorMode),
+ mUseReadoutTimestamp(false), mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mDataspace(0), mUsage(0) { }
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
@@ -409,6 +439,9 @@
err = parcel->writeInt32(mMirrorMode);
if (err != OK) return err;
+ err = parcel->writeInt32Vector(mMirrorModeForProducers);
+ if (err != OK) return err;
+
err = parcel->writeInt32(mUseReadoutTimestamp ? 1 : 0);
if (err != OK) return err;
@@ -438,6 +471,20 @@
return true;
}
+template <typename T>
+static bool simpleVectorsLessThan(T first, T second) {
+ if (first.size() != second.size()) {
+ return first.size() < second.size();
+ }
+
+ for (size_t i = 0; i < first.size(); i++) {
+ if (first[i] != second[i]) {
+ return first[i] < second[i];
+ }
+ }
+ return false;
+}
+
bool OutputConfiguration::gbpsEqual(const OutputConfiguration& other) const {
const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
other.getGraphicBufferProducers();
@@ -449,20 +496,20 @@
return simpleVectorsEqual(othersensorPixelModesUsed, mSensorPixelModesUsed);
}
+bool OutputConfiguration::mirrorModesEqual(const OutputConfiguration& other) const {
+ const std::vector<int>& otherMirrorModes = other.getMirrorModes();
+ return simpleVectorsEqual(otherMirrorModes, mMirrorModeForProducers);
+
+}
+
bool OutputConfiguration::sensorPixelModesUsedLessThan(const OutputConfiguration& other) const {
const std::vector<int32_t>& spms = other.getSensorPixelModesUsed();
+ return simpleVectorsLessThan(mSensorPixelModesUsed, spms);
+}
- if (mSensorPixelModesUsed.size() != spms.size()) {
- return mSensorPixelModesUsed.size() < spms.size();
- }
-
- for (size_t i = 0; i < spms.size(); i++) {
- if (mSensorPixelModesUsed[i] != spms[i]) {
- return mSensorPixelModesUsed[i] < spms[i];
- }
- }
-
- return false;
+bool OutputConfiguration::mirrorModesLessThan(const OutputConfiguration& other) const {
+ const std::vector<int>& otherMirrorModes = other.getMirrorModes();
+ return simpleVectorsLessThan(mMirrorModeForProducers, otherMirrorModes);
}
bool OutputConfiguration::gbpsLessThan(const OutputConfiguration& other) const {
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 8e53ca0..c9e8ffd 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -178,3 +178,20 @@
description: "Pass the full AttributionSource chain to PermissionChecker"
bug: "190657833"
}
+
+flag {
+ namespace: "camera_platform"
+ name: "mirror_mode_shared_surfaces"
+ is_exported: true
+ description: "Support setting and getting mirror mode for shared surfaces"
+ bug: "298899993"
+}
+
+flag {
+ namespace: "camera_platform"
+ is_exported: true
+ name: "multiresolution_imagereader_usage_public"
+ description: "Make constructor for MultiResolutionImageReader with usage public"
+ bug: "338621560"
+}
+
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 83ce39d..2049a31 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -72,7 +72,7 @@
bool isMultiResolution() const;
int64_t getStreamUseCase() const;
int getTimestampBase() const;
- int getMirrorMode() const;
+ int getMirrorMode(sp<IGraphicBufferProducer> surface) const;
bool useReadoutTimestamp() const;
int getFormat() const;
int getDataspace() const;
@@ -125,6 +125,7 @@
mStreamUseCase == other.mStreamUseCase &&
mTimestampBase == other.mTimestampBase &&
mMirrorMode == other.mMirrorMode &&
+ mirrorModesEqual(other) &&
mUseReadoutTimestamp == other.mUseReadoutTimestamp &&
mFormat == other.mFormat &&
mDataspace == other.mDataspace &&
@@ -180,6 +181,9 @@
if (mMirrorMode != other.mMirrorMode) {
return mMirrorMode < other.mMirrorMode;
}
+ if (!mirrorModesEqual(other)) {
+ return mirrorModesLessThan(other);
+ }
if (mUseReadoutTimestamp != other.mUseReadoutTimestamp) {
return mUseReadoutTimestamp < other.mUseReadoutTimestamp;
}
@@ -204,6 +208,9 @@
bool sensorPixelModesUsedLessThan(const OutputConfiguration& other) const;
bool gbpsLessThan(const OutputConfiguration& other) const;
void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {mGbps.push_back(gbp);}
+ bool mirrorModesEqual(const OutputConfiguration& other) const;
+ bool mirrorModesLessThan(const OutputConfiguration& other) const;
+ const std::vector<int32_t>& getMirrorModes() const {return mMirrorModeForProducers;}
private:
std::vector<sp<IGraphicBufferProducer>> mGbps;
int mRotation;
@@ -221,6 +228,7 @@
int64_t mStreamUseCase;
int mTimestampBase;
int mMirrorMode;
+ std::vector<int> mMirrorModeForProducers; // 1:1 mapped with mGbps
bool mUseReadoutTimestamp;
int mFormat;
int mDataspace;
diff --git a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
index 7046075..b6fa817 100644
--- a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
@@ -120,7 +120,10 @@
[&]() { outputConfiguration->getColorSpace(); },
[&]() { outputConfiguration->getStreamUseCase(); },
[&]() { outputConfiguration->getTimestampBase(); },
- [&]() { outputConfiguration->getMirrorMode(); },
+ [&]() {
+ sp<IGraphicBufferProducer> gbp = createIGraphicBufferProducer();
+ outputConfiguration->getMirrorMode(gbp);
+ },
[&]() { outputConfiguration->useReadoutTimestamp(); },
});
callC2OutputConfAPIs();
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index 84c0f48..b5c7edf 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -13,6 +13,14 @@
}
flag {
+ name: "apv_support"
+ is_exported: true
+ namespace: "codec_fwk"
+ description: "Feature flag for Android support for APV Content"
+ bug: "375464302"
+}
+
+flag {
name: "codec_buffer_state_cleanup"
namespace: "codec_fwk"
description: "Bugfix flag for more buffer state cleanup in MediaCodec"
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 0b434f7..aebdf1e 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -32,6 +32,17 @@
bug: "374751406"
}
+flag {
+ name: "enable_multichannel_group_device"
+ namespace: "media_audio"
+ description:
+ "Enable new audio device type for wireless connected speaker group"
+ "supporting multichannel content."
+ is_exported: true
+ is_fixed_read_only: true
+ bug: "344031109"
+}
+
flag{
name: "enable_ringtone_haptics_customization"
namespace: "media_audio"
@@ -163,6 +174,13 @@
bug: "367816690"
}
+flag {
+ name: "speaker_cleanup_usage"
+ namespace: "media_audio"
+ description: "Support new AudioAttributes usage for speaker cleanup"
+ bug: "355050846"
+}
+
# TODO remove
flag {
name: "volume_ringer_api_hardening"
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index cdcce08..de6742a 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -1797,6 +1797,8 @@
return AUDIO_USAGE_VEHICLE_STATUS;
case AudioUsage::ANNOUNCEMENT:
return AUDIO_USAGE_ANNOUNCEMENT;
+ case AudioUsage::SPEAKER_CLEANUP:
+ return AUDIO_USAGE_SPEAKER_CLEANUP;
}
return unexpected(BAD_VALUE);
}
@@ -1848,6 +1850,8 @@
return AudioUsage::VEHICLE_STATUS;
case AUDIO_USAGE_ANNOUNCEMENT:
return AudioUsage::ANNOUNCEMENT;
+ case AUDIO_USAGE_SPEAKER_CLEANUP:
+ return AudioUsage::SPEAKER_CLEANUP;
}
return unexpected(BAD_VALUE);
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 4353521..e2b28dc 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -335,7 +335,7 @@
void CCodecBufferChannel::setComponent(
const std::shared_ptr<Codec2Client::Component> &component) {
- mComponent = component;
+ std::atomic_store(&mComponent, component);
mComponentName = component->getName() + StringPrintf("#%d", int(uintptr_t(component.get()) % 997));
mName = mComponentName.c_str();
}
@@ -351,7 +351,7 @@
inputSurface->numProcessingBuffersBalance = 0;
inputSurface->surface = surface;
mHasInputSurface = true;
- return inputSurface->surface->connect(mComponent);
+ return inputSurface->surface->connect(std::atomic_load(&mComponent));
}
status_t CCodecBufferChannel::signalEndOfInputStream() {
@@ -547,7 +547,7 @@
now);
}
}
- err = mComponent->queue(&items);
+ err = std::atomic_load(&mComponent)->queue(&items);
}
if (err != C2_OK) {
Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
@@ -1457,7 +1457,7 @@
qbi.setSurfaceDamage(Region::INVALID_REGION); // we don't have dirty regions
qbi.getFrameTimestamps = true; // we need to know when a frame is rendered
IGraphicBufferProducer::QueueBufferOutput qbo;
- status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
+ status_t result = std::atomic_load(&mComponent)->queueToOutputSurface(block, qbi, &qbo);
if (result != OK) {
ALOGI("[%s] queueBuffer failed: %d", mName, result);
if (result == NO_INIT) {
@@ -1596,7 +1596,7 @@
void CCodecBufferChannel::pollForRenderedBuffers() {
FrameEventHistoryDelta delta;
- mComponent->pollForRenderedFrames(&delta);
+ std::atomic_load(&mComponent)->pollForRenderedFrames(&delta);
processRenderedFrames(delta);
}
@@ -1605,7 +1605,7 @@
// knowing the internal state of CCodec/CCodecBufferChannel,
// prevent mComponent from being destroyed by holding the shared reference
// during this interface being executed.
- std::shared_ptr<Codec2Client::Component> comp = mComponent;
+ std::shared_ptr<Codec2Client::Component> comp = std::atomic_load(&mComponent);
if (comp) {
SurfaceCallbackHandler::GetInstance().post(
SurfaceCallbackHandler::ON_BUFFER_RELEASED, comp, generation);
@@ -1617,7 +1617,7 @@
// knowing the internal state of CCodec/CCodecBufferChannel,
// prevent mComponent from being destroyed by holding the shared reference
// during this interface being executed.
- std::shared_ptr<Codec2Client::Component> comp = mComponent;
+ std::shared_ptr<Codec2Client::Component> comp = std::atomic_load(&mComponent);
if (comp) {
SurfaceCallbackHandler::GetInstance().post(
SurfaceCallbackHandler::ON_BUFFER_ATTACHED, comp, generation);
@@ -1691,7 +1691,7 @@
C2ActualPipelineDelayTuning pipelineDelay(0);
C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);
- c2_status_t err = mComponent->query(
+ c2_status_t err = std::atomic_load(&mComponent)->query(
{
&iStreamFormat,
&oStreamFormat,
@@ -1722,7 +1722,7 @@
size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
// TODO: get this from input format
- bool secure = mComponent->getName().find(".secure") != std::string::npos;
+ bool secure = std::atomic_load(&mComponent)->getName().find(".secure") != std::string::npos;
// secure mode is a static parameter (shall not change in the executing state)
mSendEncryptedInfoBuffer = secureMode.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED;
@@ -1768,7 +1768,7 @@
channelCount.invalidate();
pcmEncoding.invalidate();
}
- err = mComponent->query(stackParams,
+ err = std::atomic_load(&mComponent)->query(stackParams,
{ C2PortAllocatorsTuning::input::PARAM_TYPE },
C2_DONT_BLOCK,
¶ms);
@@ -1929,7 +1929,7 @@
// query C2PortAllocatorsTuning::output from component, or use default allocator if
// unsuccessful.
std::vector<std::unique_ptr<C2Param>> params;
- err = mComponent->query({ },
+ err = std::atomic_load(&mComponent)->query({ },
{ C2PortAllocatorsTuning::output::PARAM_TYPE },
C2_DONT_BLOCK,
¶ms);
@@ -1957,7 +1957,7 @@
// if unsuccessful.
if (outputSurface) {
params.clear();
- err = mComponent->query({ },
+ err = std::atomic_load(&mComponent)->query({ },
{ C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
C2_DONT_BLOCK,
¶ms);
@@ -1988,7 +1988,7 @@
}
if ((poolMask >> pools->outputAllocatorId) & 1) {
- err = mComponent->createBlockPool(
+ err = std::atomic_load(&mComponent)->createBlockPool(
pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
ALOGI("[%s] Created output block pool with allocatorID %u => poolID %llu - %s",
mName, pools->outputAllocatorId,
@@ -2009,7 +2009,8 @@
C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId });
std::vector<std::unique_ptr<C2SettingResult>> failures;
- err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
+ err = std::atomic_load(&mComponent)->config(
+ { poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
ALOGD("[%s] Configured output block pool ids %llu => %s",
mName, (unsigned long long)poolIdsTuning->m.values[0], asString(err));
outputPoolId_ = pools->outputPoolId;
@@ -2017,7 +2018,7 @@
if (prevOutputPoolId != C2BlockPool::BASIC_LINEAR
&& prevOutputPoolId != C2BlockPool::BASIC_GRAPHIC) {
- c2_status_t err = mComponent->destroyBlockPool(prevOutputPoolId);
+ c2_status_t err = std::atomic_load(&mComponent)->destroyBlockPool(prevOutputPoolId);
if (err != C2_OK) {
ALOGW("Failed to clean up previous block pool %llu - %s (%d)\n",
(unsigned long long) prevOutputPoolId, asString(err), err);
@@ -2049,7 +2050,7 @@
// Try to set output surface to created block pool if given.
if (outputSurface) {
- mComponent->setOutputSurface(
+ std::atomic_load(&mComponent)->setOutputSurface(
outputPoolId_,
outputSurface,
outputGeneration,
@@ -2058,7 +2059,7 @@
// configure CPU read consumer usage
C2StreamUsageTuning::output outputUsage{0u, C2MemoryUsage::CPU_READ};
std::vector<std::unique_ptr<C2SettingResult>> failures;
- err = mComponent->config({ &outputUsage }, C2_MAY_BLOCK, &failures);
+ err = std::atomic_load(&mComponent)->config({ &outputUsage }, C2_MAY_BLOCK, &failures);
// do not print error message for now as most components may not yet
// support this setting
ALOGD_IF(err != C2_BAD_INDEX, "[%s] Configured output usage [%#llx]",
@@ -2180,7 +2181,8 @@
}
C2StreamBufferTypeSetting::output oStreamFormat(0u);
C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
- c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
+ c2_status_t err = std::atomic_load(&mComponent)->query(
+ { &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
if (err != C2_OK && err != C2_BAD_INDEX) {
return UNKNOWN_ERROR;
}
@@ -2198,7 +2200,7 @@
now);
}
}
- err = mComponent->queue(&flushedConfigs);
+ err = std::atomic_load(&mComponent)->queue(&flushedConfigs);
if (err != C2_OK) {
ALOGW("[%s] Error while queueing a flushed config", mName);
return UNKNOWN_ERROR;
@@ -2249,7 +2251,8 @@
Mutexed<BlockPools>::Locked pools(mBlockPools);
outputPoolId = pools->outputPoolId;
}
- if (mComponent) mComponent->stopUsingOutputSurface(outputPoolId);
+ std::shared_ptr<Codec2Client::Component> comp = std::atomic_load(&mComponent);
+ if (comp) comp->stopUsingOutputSurface(outputPoolId);
if (pushBlankBuffer) {
sp<ANativeWindow> anw = static_cast<ANativeWindow *>(surface.get());
@@ -2283,7 +2286,8 @@
void CCodecBufferChannel::release() {
mInfoBuffers.clear();
- mComponent.reset();
+ std::shared_ptr<Codec2Client::Component> nullComp;
+ std::atomic_store(&mComponent, nullComp);
mInputAllocator.reset();
mOutputSurface.lock()->surface.clear();
{
@@ -2605,7 +2609,7 @@
}
}
if (maxDequeueCount > 0) {
- mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
+ std::atomic_load(&mComponent)->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
}
}
@@ -2853,7 +2857,7 @@
}
if (outputPoolIntf) {
- if (mComponent->setOutputSurface(
+ if (std::atomic_load(&mComponent)->setOutputSurface(
outputPoolId,
producer,
generation,
diff --git a/media/janitors/media_solutions_OWNERS b/media/janitors/media_solutions_OWNERS
index 3243726..95c2b97 100644
--- a/media/janitors/media_solutions_OWNERS
+++ b/media/janitors/media_solutions_OWNERS
@@ -4,6 +4,7 @@
andrewlewis@google.com
bachinger@google.com
claincly@google.com
+dancho@google.com
ibaker@google.com
ivanbuper@google.com
jbibik@google.com
diff --git a/media/libaaudio/fuzzer/Android.bp b/media/libaaudio/fuzzer/Android.bp
index f4637e3..a1ed6a0 100644
--- a/media/libaaudio/fuzzer/Android.bp
+++ b/media/libaaudio/fuzzer/Android.bp
@@ -37,12 +37,16 @@
],
shared_libs: [
"com.android.media.aaudio-aconfig-cc",
+ "libaconfig_storage_read_api_cc",
"libaudio_aidl_conversion_common_cpp",
"libaudioclient_aidl_conversion",
"libaudiomanager",
"libaudiopolicy",
"libbinder",
+ "libbinder_ndk",
+ "libmediautils",
"libutils",
+ "server_configurable_flags",
],
static_libs: [
"aaudio-aidl-cpp",
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index b193950..1e6be68 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1577,11 +1577,6 @@
const int INITIAL_RETRIES = 3;
int retries = INITIAL_RETRIES;
retry:
- if (retries < INITIAL_RETRIES) {
- // refresh the audio configuration cache in this process to make sure we get new
- // input parameters and new IAudioRecord in createRecord_l()
- AudioSystem::clearAudioConfigCache();
- }
mFlags = mOrigFlags;
// if the new IAudioRecord is created, createRecord_l() will modify the
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index a178d01..483a1ef 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -26,12 +26,14 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
+#include <cutils/properties.h>
#include <media/AidlConversion.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/IAudioFlinger.h>
#include <media/PolicyAidlConversion.h>
#include <media/TypeConverter.h>
+#include <mediautils/ServiceSingleton.h>
#include <math.h>
#include <system/audio.h>
@@ -80,172 +82,215 @@
std::mutex AudioSystem::gSoundTriggerMutex;
sp<CaptureStateListenerImpl> AudioSystem::gSoundTriggerCaptureStateListener;
-// Sets the Binder for the AudioFlinger service, passed to this client process
-// from the system server.
-// This allows specific isolated processes to access the audio system. Currently used only for the
-// HotwordDetectionService.
-template <typename ServiceInterface, typename Client, typename AidlInterface,
- typename ServiceTraits>
-class ServiceHandler {
+// ----------------------------
+
+// AudioSystem is the client side interface to AudioFlinger (AF) and AudioPolicy (AP).
+//
+// For clients:
+// We use the ServiceSingleton class in mediautils to fetch the AF/AP service.
+// The ServiceSingleton offers service prefetch, automatic
+// new service notification, automatic binder death notification.
+//
+// AudioFlingerServiceTraits and AudioPolicyServiceTraits are passed into
+// ServiceSingleton to provide interaction with the service notifications and
+// binder death notifications.
+//
+// If the AF/AP service is unavailable for kServiceWaitMs from ServiceManager,
+// ServiceSingleton will return a nullptr service handle resulting in the same dead object error
+// as if the service died (which it did, otherwise we'd be returning the cached handle).
+//
+// Potential deadlock sequence:
+// 1) audioserver reboots.
+// 2) App clients call into AudioService (system server) obtaining binder threads,
+// these calls blocking for audioserver reboot completion (or waiting for a mutex
+// held by those blocked threads).
+// 3) AudioFlinger and AudioPolicyManager services need to call into system server
+// during initialization. It can't because app clients hold all the binder threads
+// in the threadpool.
+// 4) We have a resource deadlock between (2) and (3) potentially causing an ANR and
+// further reinitialization.
+// 5) However, after the service wait timeout kServiceWaitNs, the calls for (2) will
+// return an error and resolve itself, breaking the resource deadlock in (4).
+//
+// At this time, it is a matter of experimentation whether the service timeout is
+// applied only for system server, and we let other clients block indefinitely.
+//
+// For audio services:
+// AudioFlinger and AudioPolicy may call back into AudioSystem. When doing
+// so it should not hold any mutexes. There is no service wait as AudioFlinger
+// and AudioPolicy are in-process with each other, and the call proceeds without
+// binder. The setLocalService() method is used to set the service interfaces
+// within audioserver to bypass the ServiceManager lookup.
+//
+
+// Wait timeout for AudioFlinger or AudioPolicy service before returning with null.
+// Such an audioserver failure is considered benign as the ground truth is stored in
+// the Java AudioService and can be restored once audioserver has finished initialization.
+//
+// TODO(b/375691003) We use 10s as a conservative timeout value, and will tune closer to 3s.
+// Too small a value (i.e. less than 1s would churn repeated calls to get the service).
+static constexpr int32_t kServiceWaitMs = 10'000;
+
+static constexpr const char kServiceWaitProperty[] = "audio.service.wait_ms";
+
+// AudioFlingerServiceTraits is a collection of methods that parameterize the
+// ServiceSingleton handler for IAudioFlinger
+
+class AudioFlingerServiceTraits {
public:
- sp<ServiceInterface> getService()
- EXCLUDES(mMutex) NO_THREAD_SAFETY_ANALYSIS { // std::unique_ptr
- sp<ServiceInterface> service;
- sp<Client> client;
+ // ------- required by ServiceSingleton
- bool reportNoError = false;
+ static constexpr const char* getServiceName() { return "media.audio_flinger"; }
+
+ static void onNewService(const sp<media::IAudioFlingerService>& afs) {
+ onNewServiceWithAdapter(createServiceAdapter(afs));
+ }
+
+ static void onServiceDied(const sp<media::IAudioFlingerService>&) {
+ ALOGW("%s: %s service died", __func__, getServiceName());
{
- std::lock_guard _l(mMutex);
- if (mService != nullptr) {
- return mService;
- }
+ std::lock_guard l(mMutex);
+ mValid = false;
+ mClient->clearIoCache();
}
+ AudioSystem::reportError(DEAD_OBJECT);
+ }
- std::unique_lock ul_only1thread(mSingleGetter);
- std::unique_lock ul(mMutex);
- if (mService != nullptr) {
- return mService;
- }
- if (mClient == nullptr) {
- mClient = sp<Client>::make();
- } else {
- reportNoError = true;
- }
- while (true) {
- mService = mLocalService;
- if (mService != nullptr) break;
+ static constexpr mediautils::ServiceOptions options() {
+ return mediautils::ServiceOptions::kNone;
+ }
- sp<IBinder> binder = mBinder;
- if (binder == nullptr) {
- sp <IServiceManager> sm = defaultServiceManager();
- binder = sm->checkService(String16(ServiceTraits::SERVICE_NAME));
- if (binder == nullptr) {
- ALOGD("%s: waiting for %s", __func__, ServiceTraits::SERVICE_NAME);
+ // ------- required by AudioSystem
- // if the condition variable is present, setLocalService() and
- // setBinder() is allowed to use it to notify us.
- if (mCvGetter == nullptr) {
- mCvGetter = std::make_shared<std::condition_variable>();
- }
- mCvGetter->wait_for(ul, std::chrono::seconds(1));
- continue;
- }
+ static sp<IAudioFlinger> getService(
+ std::chrono::milliseconds waitMs = std::chrono::milliseconds{-1}) {
+ static bool init = false;
+ audio_utils::unique_lock ul(mMutex);
+ if (!init) {
+ if (!mDisableThreadPoolStart) {
+ ProcessState::self()->startThreadPool();
}
- binder->linkToDeath(mClient);
- auto aidlInterface = interface_cast<AidlInterface>(binder);
- LOG_ALWAYS_FATAL_IF(aidlInterface == nullptr);
- if constexpr (std::is_same_v<ServiceInterface, AidlInterface>) {
- mService = std::move(aidlInterface);
- } else /* constexpr */ {
- mService = ServiceTraits::createServiceAdapter(aidlInterface);
- }
- break;
+ mediautils::initService<media::IAudioFlingerService, AudioFlingerServiceTraits>();
+ mWaitMs = std::chrono::milliseconds(
+ property_get_int32(kServiceWaitProperty, kServiceWaitMs));
+ init = true;
}
- if (mCvGetter) mCvGetter.reset(); // remove condition variable.
- client = mClient;
- service = mService;
- // Make sure callbacks can be received by the client
- if (mCanStartThreadPool) {
- ProcessState::self()->startThreadPool();
- }
+ if (mValid) return mService;
+ if (waitMs.count() < 0) waitMs = mWaitMs;
ul.unlock();
- ul_only1thread.unlock();
- ServiceTraits::onServiceCreate(service, client);
- if (reportNoError) AudioSystem::reportError(NO_ERROR);
- return service;
+
+ // mediautils::getService() installs a persistent new service notification.
+ auto service = mediautils::getService<
+ media::IAudioFlingerService>(waitMs);
+ ALOGD("%s: checking for service %s: %p", __func__, getServiceName(), service.get());
+
+ ul.lock();
+ // return the IAudioFlinger interface which is adapted
+ // from the media::IAudioFlingerService.
+ return mService;
}
- status_t setLocalService(const sp<ServiceInterface>& service) EXCLUDES(mMutex) {
- std::lock_guard _l(mMutex);
- // we allow clearing once set, but not a double non-null set.
- if (mService != nullptr && service != nullptr) return INVALID_OPERATION;
- mLocalService = service;
- if (mCvGetter) mCvGetter->notify_one();
- return OK;
- }
+ static sp<AudioSystem::AudioFlingerClient> getClient() {
+ audio_utils::unique_lock ul(mMutex);
+ if (mValid) return mClient;
+ ul.unlock();
- sp<Client> getClient() EXCLUDES(mMutex) {
- const auto service = getService();
- if (service == nullptr) return nullptr;
- std::lock_guard _l(mMutex);
+ auto service = getService();
+ ALOGD("%s: checking for service: %p", __func__, service.get());
+
+ ul.lock();
return mClient;
}
- void setBinder(const sp<IBinder>& binder) EXCLUDES(mMutex) {
- std::lock_guard _l(mMutex);
- if (mService != nullptr) {
- ALOGW("%s: ignoring; %s connection already established.",
- __func__, ServiceTraits::SERVICE_NAME);
- return;
+ static void setBinder(const sp<IBinder>& binder) {
+ setLocalService(createServiceAdapter(
+ mediautils::interfaceFromBinder<media::IAudioFlingerService>(binder)));
+ }
+
+ static status_t setLocalService(const sp<IAudioFlinger>& af) {
+ mediautils::skipService<media::IAudioFlingerService>();
+ sp<IAudioFlinger> old;
+ {
+ std::lock_guard l(mMutex);
+ old = mService;
+ mService = af;
}
- mBinder = binder;
- if (mCvGetter) mCvGetter->notify_one();
+ if (old) onServiceDied({});
+ if (af) onNewServiceWithAdapter(af);
+ return OK;
}
- void clearService() EXCLUDES(mMutex) {
- std::lock_guard _l(mMutex);
- mService.clear();
- if (mClient) ServiceTraits::onClearService(mClient);
+ static void disableThreadPoolStart() {
+ mDisableThreadPoolStart = true;
}
- void disableThreadPool() {
- mCanStartThreadPool = false;
+ static bool isValid() {
+ audio_utils::unique_lock ul(mMutex);
+ if (mValid) return true;
+ ul.unlock();
+ (void)getService({});
+ ul.lock();
+ return mValid;
+ }
+
+ // called to determine error on nullptr service return.
+ static constexpr status_t getError() {
+ return DEAD_OBJECT;
}
private:
- std::mutex mSingleGetter;
- std::mutex mMutex;
- std::shared_ptr<std::condition_variable> mCvGetter GUARDED_BY(mMutex);
- sp<IBinder> mBinder GUARDED_BY(mMutex);
- sp<ServiceInterface> mLocalService GUARDED_BY(mMutex);
- sp<ServiceInterface> mService GUARDED_BY(mMutex);
- sp<Client> mClient GUARDED_BY(mMutex);
- std::atomic<bool> mCanStartThreadPool = true;
-};
-struct AudioFlingerTraits {
- static void onServiceCreate(
- const sp<IAudioFlinger>& af, const sp<AudioSystem::AudioFlingerClient>& afc) {
+ static void onNewServiceWithAdapter(const sp<IAudioFlinger>& service) {
+ ALOGD("%s: %s service obtained %p", __func__, getServiceName(), service.get());
+ sp<AudioSystem::AudioFlingerClient> client;
+ bool reportNoError = false;
+ {
+ std::lock_guard l(mMutex);
+ if (mClient == nullptr) {
+ mClient = sp<AudioSystem::AudioFlingerClient>::make();
+ } else {
+ mClient->clearIoCache();
+ reportNoError = true;
+ }
+ mService = service;
+ client = mClient;
+ mValid = true;
+ }
+ // TODO(b/375280520) consider registerClient() within mMutex lock.
const int64_t token = IPCThreadState::self()->clearCallingIdentity();
- af->registerClient(afc);
+ service->registerClient(client);
IPCThreadState::self()->restoreCallingIdentity(token);
+
+ if (reportNoError) AudioSystem::reportError(NO_ERROR);
}
static sp<IAudioFlinger> createServiceAdapter(
- const sp<media::IAudioFlingerService>& aidlInterface) {
- return sp<AudioFlingerClientAdapter>::make(aidlInterface);
+ const sp<media::IAudioFlingerService>& af) {
+ return sp<AudioFlingerClientAdapter>::make(af);
}
- static void onClearService(const sp<AudioSystem::AudioFlingerClient>& afc) {
- afc->clearIoCache();
- }
-
- static constexpr const char* SERVICE_NAME = IAudioFlinger::DEFAULT_SERVICE_NAME;
+ static inline constinit std::mutex mMutex;
+ static inline constinit sp<AudioSystem::AudioFlingerClient> mClient GUARDED_BY(mMutex);
+ static inline constinit sp<IAudioFlinger> mService GUARDED_BY(mMutex);
+ static inline constinit std::chrono::milliseconds mWaitMs GUARDED_BY(mMutex) {kServiceWaitMs};
+ static inline constinit bool mValid GUARDED_BY(mMutex) = false;
+ static inline constinit std::atomic_bool mDisableThreadPoolStart = false;
};
-[[clang::no_destroy]] static constinit ServiceHandler<IAudioFlinger,
- AudioSystem::AudioFlingerClient, media::IAudioFlingerService,
- AudioFlingerTraits> gAudioFlingerServiceHandler;
-
sp<IAudioFlinger> AudioSystem::get_audio_flinger() {
- return gAudioFlingerServiceHandler.getService();
+ return AudioFlingerServiceTraits::getService();
}
sp<AudioSystem::AudioFlingerClient> AudioSystem::getAudioFlingerClient() {
- return gAudioFlingerServiceHandler.getClient();
+ return AudioFlingerServiceTraits::getClient();
}
void AudioSystem::setAudioFlingerBinder(const sp<IBinder>& audioFlinger) {
- if (audioFlinger->getInterfaceDescriptor() != media::IAudioFlingerService::descriptor) {
- ALOGE("%s: received a binder of type %s",
- __func__, String8(audioFlinger->getInterfaceDescriptor()).c_str());
- return;
- }
- gAudioFlingerServiceHandler.setBinder(audioFlinger);
+ AudioFlingerServiceTraits::setBinder(audioFlinger);
}
status_t AudioSystem::setLocalAudioFlinger(const sp<IAudioFlinger>& af) {
- return gAudioFlingerServiceHandler.setLocalService(af);
+ return AudioFlingerServiceTraits::setLocalService(af);
}
sp<AudioIoDescriptor> AudioSystem::getIoDescriptor(audio_io_handle_t ioHandle) {
@@ -258,9 +303,7 @@
}
/* static */ status_t AudioSystem::checkAudioFlinger() {
- if (defaultServiceManager()->checkService(String16("media.audio_flinger")) != 0) {
- return NO_ERROR;
- }
+ if (AudioFlingerServiceTraits::isValid()) return OK;
return DEAD_OBJECT;
}
@@ -268,41 +311,41 @@
status_t AudioSystem::muteMicrophone(bool state) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setMicMute(state);
}
status_t AudioSystem::isMicrophoneMuted(bool* state) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
*state = af->getMicMute();
return NO_ERROR;
}
status_t AudioSystem::setMasterVolume(float value) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
af->setMasterVolume(value);
return NO_ERROR;
}
status_t AudioSystem::setMasterMute(bool mute) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
af->setMasterMute(mute);
return NO_ERROR;
}
status_t AudioSystem::getMasterVolume(float* volume) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
*volume = af->masterVolume();
return NO_ERROR;
}
status_t AudioSystem::getMasterMute(bool* mute) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
*mute = af->masterMute();
return NO_ERROR;
}
@@ -311,7 +354,7 @@
bool muted, audio_io_handle_t output) {
if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
af->setStreamVolume(stream, value, muted, output);
return NO_ERROR;
}
@@ -319,7 +362,7 @@
status_t AudioSystem::setStreamMute(audio_stream_type_t stream, bool mute) {
if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
af->setStreamMute(stream, mute);
return NO_ERROR;
}
@@ -328,7 +371,7 @@
const std::vector<audio_port_handle_t>& portIds, float volume, bool muted,
audio_io_handle_t output) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
std::vector<int32_t> portIdsAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(
portIds, legacy2aidl_audio_port_handle_t_int32_t));
@@ -340,26 +383,26 @@
status_t AudioSystem::setMode(audio_mode_t mode) {
if (uint32_t(mode) >= AUDIO_MODE_CNT) return BAD_VALUE;
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setMode(mode);
}
status_t AudioSystem::setSimulateDeviceConnections(bool enabled) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setSimulateDeviceConnections(enabled);
}
status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setParameters(ioHandle, keyValuePairs);
}
String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) {
const sp<IAudioFlinger> af = get_audio_flinger();
String8 result = String8("");
- if (af == 0) return result;
+ if (af == nullptr) return result;
result = af->getParameters(ioHandle, keys);
return result;
@@ -438,7 +481,7 @@
status_t AudioSystem::getSamplingRate(audio_io_handle_t ioHandle,
uint32_t* samplingRate) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
sp<AudioIoDescriptor> desc = getIoDescriptor(ioHandle);
if (desc == 0) {
*samplingRate = af->sampleRate(ioHandle);
@@ -473,7 +516,7 @@
status_t AudioSystem::getFrameCount(audio_io_handle_t ioHandle,
size_t* frameCount) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
sp<AudioIoDescriptor> desc = getIoDescriptor(ioHandle);
if (desc == 0) {
*frameCount = af->frameCount(ioHandle);
@@ -508,7 +551,7 @@
status_t AudioSystem::getLatency(audio_io_handle_t output,
uint32_t* latency) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output);
if (outputDesc == 0) {
*latency = af->latency(output);
@@ -532,14 +575,14 @@
status_t AudioSystem::setVoiceVolume(float value) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setVoiceVolume(value);
}
status_t AudioSystem::getRenderPosition(audio_io_handle_t output, uint32_t* halFrames,
uint32_t* dspFrames) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->getRenderPosition(halFrames, dspFrames, output);
}
@@ -547,7 +590,7 @@
uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) {
const sp<IAudioFlinger> af = get_audio_flinger();
uint32_t result = 0;
- if (af == 0) return result;
+ if (af == nullptr) return result;
if (ioHandle == AUDIO_IO_HANDLE_NONE) return result;
result = af->getInputFramesLost(ioHandle);
@@ -557,7 +600,7 @@
audio_unique_id_t AudioSystem::newAudioUniqueId(audio_unique_id_use_t use) {
// Must not use AF as IDs will re-roll on audioserver restart, b/130369529.
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return AUDIO_UNIQUE_ID_ALLOCATE;
+ if (af == nullptr) return AUDIO_UNIQUE_ID_ALLOCATE;
return af->newAudioUniqueId(use);
}
@@ -577,26 +620,26 @@
audio_hw_sync_t AudioSystem::getAudioHwSyncForSession(audio_session_t sessionId) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return AUDIO_HW_SYNC_INVALID;
+ if (af == nullptr) return AUDIO_HW_SYNC_INVALID;
return af->getAudioHwSyncForSession(sessionId);
}
status_t AudioSystem::systemReady() {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return NO_INIT;
+ if (af == nullptr) return NO_INIT;
return af->systemReady();
}
status_t AudioSystem::audioPolicyReady() {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return NO_INIT;
+ if (af == nullptr) return NO_INIT;
return af->audioPolicyReady();
}
status_t AudioSystem::getFrameCountHAL(audio_io_handle_t ioHandle,
size_t* frameCount) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
sp<AudioIoDescriptor> desc = getIoDescriptor(ioHandle);
if (desc == 0) {
*frameCount = af->frameCountHAL(ioHandle);
@@ -625,13 +668,6 @@
mInChannelMask = AUDIO_CHANNEL_NONE;
}
-void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused) {
- gAudioFlingerServiceHandler.clearService();
- reportError(DEAD_OBJECT);
-
- ALOGW("AudioFlinger server died!");
-}
-
Status AudioSystem::AudioFlingerClient::ioConfigChanged(
media::AudioIoConfigEvent _event,
const media::AudioIoDescriptor& _ioDesc) {
@@ -788,9 +824,7 @@
uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, size_t* buffSize) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
std::lock_guard _l(mMutex);
// Do we have a stale mInBuffSize or are we requesting the input buffer size for new values
if ((mInBuffSize == 0) || (sampleRate != mInSamplingRate) || (format != mInFormat)
@@ -925,47 +959,145 @@
gVolRangeInitReqCallback = cb;
}
-struct AudioPolicyTraits {
- static void onServiceCreate(const sp<IAudioPolicyService>& ap,
- const sp<AudioSystem::AudioPolicyServiceClient>& apc) {
+
+// AudioPolicyServiceTraits is a collection of methods that parameterize the
+// ServiceSingleton class implementation of IAudioPolicyService.
+
+class AudioPolicyServiceTraits {
+public:
+ // ------- methods required by ServiceSingleton
+
+ static constexpr const char* getServiceName() { return "media.audio_policy"; }
+
+ static void onNewService(const sp<IAudioPolicyService>& aps) {
+ ALOGD("%s: %s service obtained %p", __func__, getServiceName(), aps.get());
+ sp<AudioSystem::AudioPolicyServiceClient> client;
+ {
+ std::lock_guard l(mMutex);
+ if (mClient == nullptr) {
+ mClient = sp<AudioSystem::AudioPolicyServiceClient>::make();
+ }
+ client = mClient;
+ mService = aps;
+ mValid = true;
+ }
+ // TODO(b/375280520) consider registerClient() within mMutex lock.
const int64_t token = IPCThreadState::self()->clearCallingIdentity();
- ap->registerClient(apc);
- ap->setAudioPortCallbacksEnabled(apc->isAudioPortCbEnabled());
- ap->setAudioVolumeGroupCallbacksEnabled(apc->isAudioVolumeGroupCbEnabled());
+ aps->registerClient(client);
IPCThreadState::self()->restoreCallingIdentity(token);
}
- static void onClearService(const sp<AudioSystem::AudioPolicyServiceClient>&) {}
+ static void onServiceDied(const sp<IAudioPolicyService>&) {
+ ALOGW("%s: %s service died", __func__, getServiceName());
+ sp<AudioSystem::AudioPolicyServiceClient> client;
+ {
+ std::lock_guard l(mMutex);
+ mValid = false;
+ client = mClient;
+ }
+ client->onServiceDied();
+ }
- static constexpr const char *SERVICE_NAME = "media.audio_policy";
+ static constexpr mediautils::ServiceOptions options() {
+ return mediautils::ServiceOptions::kNone;
+ }
+
+ // ------- methods required by AudioSystem
+
+ static sp<IAudioPolicyService> getService(
+ std::chrono::milliseconds waitMs = std::chrono::milliseconds{-1}) {
+ static bool init = false;
+ audio_utils::unique_lock ul(mMutex);
+ if (!init) {
+ if (!mDisableThreadPoolStart) {
+ ProcessState::self()->startThreadPool();
+ }
+ mediautils::initService<IAudioPolicyService, AudioPolicyServiceTraits>();
+ mWaitMs = std::chrono::milliseconds(
+ property_get_int32(kServiceWaitProperty, kServiceWaitMs));
+ init = true;
+ }
+ if (mValid) return mService;
+ if (waitMs.count() < 0) waitMs = mWaitMs;
+ ul.unlock();
+
+ auto service = mediautils::getService<
+ media::IAudioPolicyService>(waitMs);
+ ALOGD("%s: checking for service %s: %p", __func__, getServiceName(), service.get());
+
+ // mediautils::getService() will return early if setLocalService() is called
+ // (whereupon mService contained the actual local service pointer to use).
+ // we should always return mService.
+ ul.lock();
+ return mService;
+ }
+
+ static sp<AudioSystem::AudioPolicyServiceClient> getClient() {
+ audio_utils::unique_lock ul(mMutex);
+ if (mValid) return mClient;
+ ul.unlock();
+
+ auto service = getService();
+ ALOGD("%s: checking for service: %p", __func__, service.get());
+
+ ul.lock();
+ return mClient;
+ }
+
+ static status_t setLocalService(const sp<IAudioPolicyService>& aps) {
+ mediautils::skipService<IAudioPolicyService>();
+ sp<IAudioPolicyService> old;
+ {
+ std::lock_guard l(mMutex);
+ old = mService;
+ mService = aps;
+ }
+ if (old) onServiceDied(old);
+ if (aps) onNewService(aps);
+ return OK;
+ }
+
+ static void disableThreadPoolStart() {
+ mDisableThreadPoolStart = true;
+ }
+
+ // called to determine error on nullptr service return.
+ static constexpr status_t getError() {
+ return DEAD_OBJECT;
+ }
+private:
+
+ static inline constinit std::mutex mMutex;
+ static inline constinit sp<AudioSystem::AudioPolicyServiceClient> mClient GUARDED_BY(mMutex);
+ static inline constinit sp<IAudioPolicyService> mService GUARDED_BY(mMutex);
+ static inline constinit bool mValid GUARDED_BY(mMutex) = false;
+ static inline constinit std::chrono::milliseconds mWaitMs GUARDED_BY(mMutex) {kServiceWaitMs};
+ static inline constinit std::atomic_bool mDisableThreadPoolStart = false;
};
-[[clang::no_destroy]] static constinit ServiceHandler<IAudioPolicyService,
- AudioSystem::AudioPolicyServiceClient, IAudioPolicyService,
- AudioPolicyTraits> gAudioPolicyServiceHandler;
-
-status_t AudioSystem::setLocalAudioPolicyService(const sp<IAudioPolicyService>& aps) {
- return gAudioPolicyServiceHandler.setLocalService(aps);
-}
sp<IAudioPolicyService> AudioSystem::get_audio_policy_service() {
- return gAudioPolicyServiceHandler.getService();
+ return AudioPolicyServiceTraits::getService();
}
-void AudioSystem::clearAudioPolicyService() {
- gAudioPolicyServiceHandler.clearService();
+status_t AudioSystem::setLocalAudioPolicyService(const sp<IAudioPolicyService>& aps) {
+ return AudioPolicyServiceTraits::setLocalService(aps);
+}
+
+sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::getAudioPolicyClient() {
+ return AudioPolicyServiceTraits::getClient();
}
void AudioSystem::disableThreadPool() {
- gAudioFlingerServiceHandler.disableThreadPool();
- gAudioPolicyServiceHandler.disableThreadPool();
+ AudioFlingerServiceTraits::disableThreadPoolStart();
+ AudioPolicyServiceTraits::disableThreadPoolStart();
}
// ---------------------------------------------------------------------------
void AudioSystem::onNewAudioModulesAvailable() {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return;
+ if (aps == nullptr) return;
aps->onNewAudioModulesAvailable();
}
@@ -974,7 +1106,7 @@
audio_format_t encodedFormat) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
return statusTFromBinderStatus(
aps->setDeviceConnectionState(
@@ -988,7 +1120,7 @@
audio_policy_dev_state_t AudioSystem::getDeviceConnectionState(audio_devices_t device,
const char* device_address) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
+ if (aps == nullptr) return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
auto result = [&]() -> ConversionResult<audio_policy_dev_state_t> {
AudioDevice deviceAidl = VALUE_OR_RETURN(
@@ -1011,7 +1143,7 @@
const char* address = "";
const char* name = "";
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
if (device_address != NULL) {
address = device_address;
@@ -1031,7 +1163,7 @@
status_t AudioSystem::setPhoneState(audio_mode_t state, uid_t uid) {
if (uint32_t(state) >= AUDIO_MODE_CNT) return BAD_VALUE;
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
return statusTFromBinderStatus(aps->setPhoneState(
VALUE_OR_RETURN_STATUS(legacy2aidl_audio_mode_t_AudioMode(state)),
@@ -1041,7 +1173,7 @@
status_t
AudioSystem::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
return statusTFromBinderStatus(
aps->setForceUse(
@@ -1054,7 +1186,7 @@
audio_policy_forced_cfg_t AudioSystem::getForceUse(audio_policy_force_use_t usage) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return AUDIO_POLICY_FORCE_NONE;
+ if (aps == nullptr) return AUDIO_POLICY_FORCE_NONE;
auto result = [&]() -> ConversionResult<audio_policy_forced_cfg_t> {
AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
@@ -1071,7 +1203,7 @@
audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return AUDIO_IO_HANDLE_NONE;
+ if (aps == nullptr) return AUDIO_IO_HANDLE_NONE;
auto result = [&]() -> ConversionResult<audio_io_handle_t> {
AudioStreamType streamAidl = VALUE_OR_RETURN(
@@ -1121,7 +1253,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return NO_INIT;
+ if (aps == nullptr) return NO_INIT;
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
@@ -1172,7 +1304,7 @@
status_t AudioSystem::startOutput(audio_port_handle_t portId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
return statusTFromBinderStatus(aps->startOutput(portIdAidl));
@@ -1180,7 +1312,7 @@
status_t AudioSystem::stopOutput(audio_port_handle_t portId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
return statusTFromBinderStatus(aps->stopOutput(portIdAidl));
@@ -1188,7 +1320,7 @@
void AudioSystem::releaseOutput(audio_port_handle_t portId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return;
+ if (aps == nullptr) return;
auto status = [&]() -> status_t {
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(
@@ -1228,7 +1360,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return NO_INIT;
+ if (aps == nullptr) return NO_INIT;
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
@@ -1262,7 +1394,7 @@
status_t AudioSystem::startInput(audio_port_handle_t portId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
return statusTFromBinderStatus(aps->startInput(portIdAidl));
@@ -1270,7 +1402,7 @@
status_t AudioSystem::stopInput(audio_port_handle_t portId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
return statusTFromBinderStatus(aps->stopInput(portIdAidl));
@@ -1278,7 +1410,7 @@
void AudioSystem::releaseInput(audio_port_handle_t portId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return;
+ if (aps == nullptr) return;
auto status = [&]() -> status_t {
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(
@@ -1296,7 +1428,7 @@
bool enabled,
audio_stream_type_t streamToDriveAbs) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
AudioDevice deviceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_device_AudioDevice(deviceType, address));
@@ -1310,7 +1442,7 @@
int indexMin,
int indexMax) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
@@ -1318,12 +1450,6 @@
int32_t indexMaxAidl = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(indexMax));
status_t status = statusTFromBinderStatus(
aps->initStreamVolume(streamAidl, indexMinAidl, indexMaxAidl));
- if (status == DEAD_OBJECT) {
- // This is a critical operation since w/o proper stream volumes no audio
- // will be heard. Make sure we recover from a failure in any case.
- ALOGE("Received DEAD_OBJECT from APS, clearing the client");
- clearAudioPolicyService();
- }
return status;
}
@@ -1332,7 +1458,7 @@
bool muted,
audio_devices_t device) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
@@ -1347,7 +1473,7 @@
int* index,
audio_devices_t device) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
@@ -1367,7 +1493,7 @@
bool muted,
audio_devices_t device) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attr));
@@ -1382,7 +1508,7 @@
int& index,
audio_devices_t device) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attr));
@@ -1397,7 +1523,7 @@
status_t AudioSystem::getMaxVolumeIndexForAttributes(const audio_attributes_t& attr, int& index) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attr));
@@ -1410,7 +1536,7 @@
status_t AudioSystem::getMinVolumeIndexForAttributes(const audio_attributes_t& attr, int& index) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attr));
@@ -1423,7 +1549,7 @@
product_strategy_t AudioSystem::getStrategyForStream(audio_stream_type_t stream) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PRODUCT_STRATEGY_NONE;
+ if (aps == nullptr) return PRODUCT_STRATEGY_NONE;
auto result = [&]() -> ConversionResult<product_strategy_t> {
AudioStreamType streamAidl = VALUE_OR_RETURN(
@@ -1443,7 +1569,7 @@
return BAD_VALUE;
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes aaAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(aa));
@@ -1460,7 +1586,7 @@
audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t* desc) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
// FIXME change return type to status_t, and return PERMISSION_DENIED here
- if (aps == 0) return AUDIO_IO_HANDLE_NONE;
+ if (aps == nullptr) return AUDIO_IO_HANDLE_NONE;
auto result = [&]() -> ConversionResult<audio_io_handle_t> {
media::EffectDescriptor descAidl = VALUE_OR_RETURN(
@@ -1480,7 +1606,7 @@
audio_session_t session,
int id) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::EffectDescriptor descAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_effect_descriptor_t_EffectDescriptor(*desc));
@@ -1494,7 +1620,7 @@
status_t AudioSystem::unregisterEffect(int id) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t idAidl = VALUE_OR_RETURN_STATUS(convertReinterpret<int32_t>(id));
return statusTFromBinderStatus(
@@ -1503,7 +1629,7 @@
status_t AudioSystem::setEffectEnabled(int id, bool enabled) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t idAidl = VALUE_OR_RETURN_STATUS(convertReinterpret<int32_t>(id));
return statusTFromBinderStatus(
@@ -1512,7 +1638,7 @@
status_t AudioSystem::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<int32_t> idsAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(ids, convertReinterpret<int32_t, int>));
@@ -1522,7 +1648,7 @@
status_t AudioSystem::isStreamActive(audio_stream_type_t stream, bool* state, uint32_t inPastMs) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
if (state == NULL) return BAD_VALUE;
AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
@@ -1536,7 +1662,7 @@
status_t AudioSystem::isStreamActiveRemotely(audio_stream_type_t stream, bool* state,
uint32_t inPastMs) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
if (state == NULL) return BAD_VALUE;
AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
@@ -1549,7 +1675,7 @@
status_t AudioSystem::isSourceActive(audio_source_t stream, bool* state) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
if (state == NULL) return BAD_VALUE;
AudioSource streamAidl = VALUE_OR_RETURN_STATUS(
@@ -1561,32 +1687,25 @@
uint32_t AudioSystem::getPrimaryOutputSamplingRate() {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return 0;
+ if (af == nullptr) return 0;
return af->getPrimaryOutputSamplingRate();
}
size_t AudioSystem::getPrimaryOutputFrameCount() {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return 0;
+ if (af == nullptr) return 0;
return af->getPrimaryOutputFrameCount();
}
status_t AudioSystem::setLowRamDevice(bool isLowRamDevice, int64_t totalMemory) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setLowRamDevice(isLowRamDevice, totalMemory);
}
-void AudioSystem::clearAudioConfigCache() {
- // called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances
- ALOGV("clearAudioConfigCache()");
- gAudioFlingerServiceHandler.clearService();
- clearAudioPolicyService();
-}
-
status_t AudioSystem::setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<AudioUsage> systemUsagesAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<AudioUsage>>(systemUsages,
@@ -1596,7 +1715,7 @@
status_t AudioSystem::setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t capturePolicy) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
int32_t capturePolicyAidl = VALUE_OR_RETURN_STATUS(
@@ -1607,7 +1726,7 @@
audio_offload_mode_t AudioSystem::getOffloadSupport(const audio_offload_info_t& info) {
ALOGV("%s", __func__);
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return AUDIO_OFFLOAD_NOT_SUPPORTED;
+ if (aps == nullptr) return AUDIO_OFFLOAD_NOT_SUPPORTED;
auto result = [&]() -> ConversionResult<audio_offload_mode_t> {
AudioOffloadInfo infoAidl = VALUE_OR_RETURN(
@@ -1632,7 +1751,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::AudioPortRole roleAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_port_role_t_AudioPortRole(role));
@@ -1656,7 +1775,7 @@
std::vector<media::AudioPortFw>* result) {
if (result == nullptr) return BAD_VALUE;
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(aps->listDeclaredDevicePorts(role, result)));
return OK;
}
@@ -1666,7 +1785,7 @@
return BAD_VALUE;
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::AudioPortFw portAidl;
RETURN_STATUS_IF_ERROR(
@@ -1682,7 +1801,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::AudioPatchFw patchAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_patch_AudioPatchFw(*patch));
@@ -1695,7 +1814,7 @@
status_t AudioSystem::releaseAudioPatch(audio_patch_handle_t handle) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t handleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_patch_handle_t_int32_t(handle));
return statusTFromBinderStatus(aps->releaseAudioPatch(handleAidl));
@@ -1710,7 +1829,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
Int numPatchesAidl;
@@ -1733,7 +1852,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::AudioPortConfigFw configAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_port_config_AudioPortConfigFw(*config));
@@ -1742,8 +1861,8 @@
status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callback) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
- const auto apc = gAudioPolicyServiceHandler.getClient();
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+ const auto apc = getAudioPolicyClient();
if (apc == nullptr) return NO_INIT;
std::lock_guard _l(gApsCallbackMutex);
@@ -1757,8 +1876,8 @@
/*static*/
status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callback) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
- const auto apc = gAudioPolicyServiceHandler.getClient();
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+ const auto apc = AudioSystem::getAudioPolicyClient();
if (apc == nullptr) return NO_INIT;
std::lock_guard _l(gApsCallbackMutex);
@@ -1771,8 +1890,8 @@
status_t AudioSystem::addAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
- const auto apc = gAudioPolicyServiceHandler.getClient();
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+ const auto apc = AudioSystem::getAudioPolicyClient();
if (apc == nullptr) return NO_INIT;
std::lock_guard _l(gApsCallbackMutex);
@@ -1785,8 +1904,8 @@
status_t AudioSystem::removeAudioVolumeGroupCallback(const sp<AudioVolumeGroupCallback>& callback) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
- const auto apc = gAudioPolicyServiceHandler.getClient();
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+ const auto apc = AudioSystem::getAudioPolicyClient();
if (apc == nullptr) return NO_INIT;
std::lock_guard _l(gApsCallbackMutex);
@@ -1844,7 +1963,7 @@
audio_port_handle_t AudioSystem::getDeviceIdForIo(audio_io_handle_t audioIo) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
const sp<AudioIoDescriptor> desc = getIoDescriptor(audioIo);
if (desc == 0) {
return AUDIO_PORT_HANDLE_NONE;
@@ -1859,7 +1978,7 @@
return BAD_VALUE;
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::SoundTriggerSession retAidl;
RETURN_STATUS_IF_ERROR(
@@ -1873,7 +1992,7 @@
status_t AudioSystem::releaseSoundTriggerSession(audio_session_t session) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t sessionAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_session_t_int32_t(session));
return statusTFromBinderStatus(aps->releaseSoundTriggerSession(sessionAidl));
@@ -1881,7 +2000,7 @@
audio_mode_t AudioSystem::getPhoneState() {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return AUDIO_MODE_INVALID;
+ if (aps == nullptr) return AUDIO_MODE_INVALID;
auto result = [&]() -> ConversionResult<audio_mode_t> {
media::audio::common::AudioMode retAidl;
@@ -1894,7 +2013,7 @@
status_t AudioSystem::registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
size_t mixesSize = std::min(mixes.size(), size_t{MAX_MIXES_PER_POLICY});
std::vector<media::AudioMix> mixesAidl;
@@ -1910,7 +2029,7 @@
}
const sp<IAudioPolicyService> aps = AudioSystem::get_audio_policy_service();
- if (aps == nullptr) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<::android::media::AudioMix> aidlMixes;
Status status = aps->getRegisteredPolicyMixes(&aidlMixes);
@@ -1927,7 +2046,7 @@
const std::vector<std::pair<AudioMix, std::vector<AudioMixMatchCriterion>>>&
mixesWithUpdates) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<media::AudioMixUpdate> updatesAidl;
updatesAidl.reserve(mixesWithUpdates.size());
@@ -1946,7 +2065,7 @@
status_t AudioSystem::setUidDeviceAffinities(uid_t uid, const AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
std::vector<AudioDevice> devicesAidl = VALUE_OR_RETURN_STATUS(
@@ -1957,7 +2076,7 @@
status_t AudioSystem::removeUidDeviceAffinities(uid_t uid) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
return statusTFromBinderStatus(aps->removeUidDeviceAffinities(uidAidl));
@@ -1966,7 +2085,7 @@
status_t AudioSystem::setUserIdDeviceAffinities(int userId,
const AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t userIdAidl = VALUE_OR_RETURN_STATUS(convertReinterpret<int32_t>(userId));
std::vector<AudioDevice> devicesAidl = VALUE_OR_RETURN_STATUS(
@@ -1978,7 +2097,7 @@
status_t AudioSystem::removeUserIdDeviceAffinities(int userId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t userIdAidl = VALUE_OR_RETURN_STATUS(convertReinterpret<int32_t>(userId));
return statusTFromBinderStatus(aps->removeUserIdDeviceAffinities(userIdAidl));
}
@@ -1990,7 +2109,7 @@
return BAD_VALUE;
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::AudioPortConfigFw sourceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_port_config_AudioPortConfigFw(*source));
@@ -2005,7 +2124,7 @@
status_t AudioSystem::stopAudioSource(audio_port_handle_t portId) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
return statusTFromBinderStatus(aps->stopAudioSource(portIdAidl));
@@ -2013,7 +2132,7 @@
status_t AudioSystem::setMasterMono(bool mono) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
return statusTFromBinderStatus(aps->setMasterMono(mono));
}
@@ -2022,26 +2141,26 @@
return BAD_VALUE;
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
return statusTFromBinderStatus(aps->getMasterMono(mono));
}
status_t AudioSystem::setMasterBalance(float balance) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setMasterBalance(balance);
}
status_t AudioSystem::getMasterBalance(float* balance) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->getMasterBalance(balance);
}
float
AudioSystem::getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return NAN;
+ if (aps == nullptr) return NAN;
auto result = [&]() -> ConversionResult<float> {
AudioStreamType streamAidl = VALUE_OR_RETURN(
@@ -2059,13 +2178,13 @@
status_t AudioSystem::getMicrophones(std::vector<media::MicrophoneInfoFw>* microphones) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->getMicrophones(microphones);
}
status_t AudioSystem::setAudioHalPids(const std::vector<pid_t>& pids) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) return PERMISSION_DENIED;
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setAudioHalPids(pids);
}
@@ -2079,7 +2198,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
Int numSurroundFormatsAidl;
numSurroundFormatsAidl.value =
VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*numSurroundFormats));
@@ -2106,7 +2225,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
Int numSurroundFormatsAidl;
numSurroundFormatsAidl.value =
VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*numSurroundFormats));
@@ -2124,7 +2243,7 @@
status_t AudioSystem::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
AudioFormatDescription audioFormatAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_format_t_AudioFormatDescription(audioFormat));
@@ -2134,7 +2253,7 @@
status_t AudioSystem::setAssistantServicesUids(const std::vector<uid_t>& uids) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<int32_t> uidsAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(uids, legacy2aidl_uid_t_int32_t));
@@ -2143,7 +2262,7 @@
status_t AudioSystem::setActiveAssistantServicesUids(const std::vector<uid_t>& activeUids) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<int32_t> activeUidsAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(activeUids, legacy2aidl_uid_t_int32_t));
@@ -2152,7 +2271,7 @@
status_t AudioSystem::setA11yServicesUids(const std::vector<uid_t>& uids) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<int32_t> uidsAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(uids, legacy2aidl_uid_t_int32_t));
@@ -2161,7 +2280,7 @@
status_t AudioSystem::setCurrentImeUid(uid_t uid) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
return statusTFromBinderStatus(aps->setCurrentImeUid(uidAidl));
@@ -2169,7 +2288,7 @@
bool AudioSystem::isHapticPlaybackSupported() {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return false;
+ if (aps == nullptr) return false;
auto result = [&]() -> ConversionResult<bool> {
bool retVal;
@@ -2182,7 +2301,7 @@
bool AudioSystem::isUltrasoundSupported() {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return false;
+ if (aps == nullptr) return false;
auto result = [&]() -> ConversionResult<bool> {
bool retVal;
@@ -2200,7 +2319,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<AudioFormatDescription> formatsAidl;
AudioDeviceDescription deviceAidl = VALUE_OR_RETURN_STATUS(
@@ -2216,7 +2335,7 @@
status_t AudioSystem::listAudioProductStrategies(AudioProductStrategyVector& strategies) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<media::AudioProductStrategy> strategiesAidl;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
@@ -2278,7 +2397,7 @@
product_strategy_t& productStrategy,
bool fallbackOnDefault) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes aaAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(aa));
@@ -2294,7 +2413,7 @@
status_t AudioSystem::listAudioVolumeGroups(AudioVolumeGroupVector& groups) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::vector<media::AudioVolumeGroup> groupsAidl;
RETURN_STATUS_IF_ERROR(
@@ -2308,7 +2427,7 @@
volume_group_t& volumeGroup,
bool fallbackOnDefault) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes aaAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(aa));
@@ -2321,13 +2440,13 @@
status_t AudioSystem::setRttEnabled(bool enabled) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
return statusTFromBinderStatus(aps->setRttEnabled(enabled));
}
bool AudioSystem::isCallScreenModeSupported() {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) return false;
+ if (aps == nullptr) return false;
auto result = [&]() -> ConversionResult<bool> {
bool retAidl;
@@ -2342,9 +2461,7 @@
device_role_t role,
const AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
@@ -2359,9 +2476,7 @@
device_role_t role,
const AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
@@ -2375,9 +2490,8 @@
status_t
AudioSystem::clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+
int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
return statusTFromBinderStatus(
@@ -2388,9 +2502,8 @@
device_role_t role,
AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+
int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
std::vector<AudioDevice> devicesAidl;
@@ -2406,9 +2519,7 @@
device_role_t role,
const AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
AudioSource audioSourceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_source_t_AudioSource(audioSource));
@@ -2424,9 +2535,8 @@
device_role_t role,
const AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+
AudioSource audioSourceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_source_t_AudioSource(audioSource));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
@@ -2440,9 +2550,8 @@
status_t AudioSystem::removeDevicesRoleForCapturePreset(
audio_source_t audioSource, device_role_t role, const AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+
AudioSource audioSourceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_source_t_AudioSource(audioSource));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
@@ -2456,9 +2565,8 @@
status_t AudioSystem::clearDevicesRoleForCapturePreset(audio_source_t audioSource,
device_role_t role) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
+
AudioSource audioSourceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_source_t_AudioSource(audioSource));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
@@ -2470,9 +2578,7 @@
device_role_t role,
AudioDeviceTypeAddrVector& devices) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
AudioSource audioSourceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_source_t_AudioSource(audioSource));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
@@ -2491,9 +2597,7 @@
if (spatializer == nullptr) {
return BAD_VALUE;
}
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::GetSpatializerResponse response;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
aps->getSpatializer(callback, &response)));
@@ -2510,9 +2614,7 @@
if (canBeSpatialized == nullptr) {
return BAD_VALUE;
}
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
audio_attributes_t attributes = attr != nullptr ? *attr : AUDIO_ATTRIBUTES_INITIALIZER;
audio_config_t configuration = config != nullptr ? *config : AUDIO_CONFIG_INITIALIZER;
@@ -2531,9 +2633,7 @@
status_t AudioSystem::getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback,
sp<media::ISoundDose>* soundDose) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
if (soundDose == nullptr) {
return BAD_VALUE;
}
@@ -2550,9 +2650,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
@@ -2574,9 +2672,7 @@
}
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
@@ -2593,52 +2689,40 @@
status_t AudioSystem::setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setRequestedLatencyMode(output, mode);
}
status_t AudioSystem::getSupportedLatencyModes(audio_io_handle_t output,
std::vector<audio_latency_mode_t>* modes) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->getSupportedLatencyModes(output, modes);
}
status_t AudioSystem::setBluetoothVariableLatencyEnabled(bool enabled) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setBluetoothVariableLatencyEnabled(enabled);
}
status_t AudioSystem::isBluetoothVariableLatencyEnabled(
bool *enabled) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->isBluetoothVariableLatencyEnabled(enabled);
}
status_t AudioSystem::supportsBluetoothVariableLatency(
bool *support) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->supportsBluetoothVariableLatency(support);
}
status_t AudioSystem::getAudioPolicyConfig(media::AudioPolicyConfig *config) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->getAudioPolicyConfig(config);
}
@@ -2685,9 +2769,7 @@
LOG_ALWAYS_FATAL_IF(listener == nullptr);
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == 0) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
std::lock_guard _l(AudioSystem::gSoundTriggerMutex);
gSoundTriggerCaptureStateListener = new CaptureStateListenerImpl(aps, listener);
@@ -2699,43 +2781,33 @@
status_t AudioSystem::setVibratorInfos(
const std::vector<media::AudioVibratorInfo>& vibratorInfos) {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->setVibratorInfos(vibratorInfos);
}
status_t AudioSystem::getMmapPolicyInfos(
AudioMMapPolicyType policyType, std::vector<AudioMMapPolicyInfo> *policyInfos) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
return statusTFromBinderStatus(aps->getMmapPolicyInfos(policyType, policyInfos));
}
int32_t AudioSystem::getAAudioMixerBurstCount() {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->getAAudioMixerBurstCount();
}
int32_t AudioSystem::getAAudioHardwareBurstMinUsec() {
const sp<IAudioFlinger> af = get_audio_flinger();
- if (af == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (af == nullptr) return AudioFlingerServiceTraits::getError();
return af->getAAudioHardwareBurstMinUsec();
}
status_t AudioSystem::getSupportedMixerAttributes(
audio_port_handle_t portId, std::vector<audio_mixer_attributes_t> *mixerAttrs) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
std::vector<media::AudioMixerAttributesInternal> _aidlReturn;
@@ -2753,9 +2825,7 @@
uid_t uid,
const audio_mixer_attributes_t *mixerAttr) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
@@ -2773,9 +2843,7 @@
audio_port_handle_t portId,
std::optional<audio_mixer_attributes_t> *mixerAttr) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
@@ -2796,9 +2864,7 @@
audio_port_handle_t portId,
uid_t uid) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
- if (aps == nullptr) {
- return PERMISSION_DENIED;
- }
+ if (aps == nullptr) return AudioPolicyServiceTraits::getError();
media::audio::common::AudioAttributes attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
@@ -2964,19 +3030,14 @@
return Status::ok();
}
-void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused) {
- {
- std::lock_guard _l(mMutex);
- for (const auto& callback : mAudioPortCallbacks) {
- callback->onServiceDied();
- }
- for (const auto& callback : mAudioVolumeGroupCallbacks) {
- callback->onServiceDied();
- }
+void AudioSystem::AudioPolicyServiceClient::onServiceDied() {
+ std::lock_guard _l(mMutex);
+ for (const auto& callback : mAudioPortCallbacks) {
+ callback->onServiceDied();
}
- AudioSystem::clearAudioPolicyService();
-
- ALOGW("AudioPolicyService server died!");
+ for (const auto& callback : mAudioVolumeGroupCallbacks) {
+ callback->onServiceDied();
+ }
}
ConversionResult<record_client_info_t>
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e0c5e92..a9409eb 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2875,10 +2875,6 @@
__func__, mPortId, isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from);
++mSequence;
- // refresh the audio configuration cache in this process to make sure we get new
- // output parameters and new IAudioFlinger in createTrack_l()
- AudioSystem::clearAudioConfigCache();
-
if (!forceRestore &&
(isOffloadedOrDirect_l() || mDoNotReconnect)) {
// FIXME re-creation of offloaded and direct tracks is not yet implemented;
@@ -2911,10 +2907,6 @@
const int INITIAL_RETRIES = 3;
int retries = INITIAL_RETRIES;
retry:
- if (retries < INITIAL_RETRIES) {
- // See the comment for clearAudioConfigCache at the start of the function.
- AudioSystem::clearAudioConfigCache();
- }
mFlags = mOrigFlags;
// If a new IAudioTrack is successfully created, createTrack_l() will modify the
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 686ec6a..5565281 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -103,6 +103,7 @@
template <typename ServiceInterface, typename Client, typename AidlInterface,
typename ServiceTraits>
friend class ServiceHandler;
+ friend class AudioFlingerServiceTraits;
public:
@@ -426,17 +427,12 @@
static status_t setEffectEnabled(int id, bool enabled);
static status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io);
- // clear stream to output mapping cache (gStreamOutputMap)
- // and output configuration cache (gOutputs)
- static void clearAudioConfigCache();
-
// Sets a local AudioPolicyService interface to be used by AudioSystem.
// This is used by audioserver main() to allow client object initialization
// before exposing any interfaces to ServiceManager.
static status_t setLocalAudioPolicyService(const sp<media::IAudioPolicyService>& aps);
static sp<media::IAudioPolicyService> get_audio_policy_service();
- static void clearAudioPolicyService();
// helpers for android.media.AudioManager.getProperty(), see description there for meaning
static uint32_t getPrimaryOutputSamplingRate();
@@ -813,7 +809,7 @@
media::audio::common::AudioMMapPolicyType policyType, audio_devices_t device,
media::audio::common::AudioMMapPolicyInfo *policyInfo);
- class AudioFlingerClient: public IBinder::DeathRecipient, public media::BnAudioFlingerClient
+ class AudioFlingerClient: public media::BnAudioFlingerClient
{
public:
AudioFlingerClient() = default;
@@ -823,9 +819,6 @@
audio_channel_mask_t channelMask, size_t* buffSize) EXCLUDES(mMutex);
sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle) EXCLUDES(mMutex);
- // DeathRecipient
- void binderDied(const wp<IBinder>& who) final;
-
// IAudioFlingerClient
// indicate a change in the configuration of an output or input: keeps the cached
@@ -870,8 +863,7 @@
sp<AudioIoDescriptor> getIoDescriptor_l(audio_io_handle_t ioHandle) REQUIRES(mMutex);
};
- class AudioPolicyServiceClient: public IBinder::DeathRecipient,
- public media::BnAudioPolicyServiceClient {
+ class AudioPolicyServiceClient: public media::BnAudioPolicyServiceClient {
public:
AudioPolicyServiceClient() = default;
@@ -895,8 +887,7 @@
return !mAudioVolumeGroupCallbacks.empty();
}
- // DeathRecipient
- void binderDied(const wp<IBinder>& who) final;
+ void onServiceDied();
// IAudioPolicyServiceClient
binder::Status onAudioVolumeGroupChanged(int32_t group, int32_t flags) override;
@@ -926,6 +917,7 @@
static audio_io_handle_t getOutput(audio_stream_type_t stream);
static sp<AudioFlingerClient> getAudioFlingerClient();
+ static sp<AudioPolicyServiceClient> getAudioPolicyClient();
static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
// Invokes all registered error callbacks with the given error code.
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index c4e4ae8..0d65f8c 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -367,8 +367,12 @@
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply, statePositions));
- *frames = std::max<int64_t>(0, reply.observable.frames);
- *timestamp = std::max<int64_t>(0, reply.observable.timeNs);
+ if (reply.observable.frames == StreamDescriptor::Position::UNKNOWN ||
+ reply.observable.timeNs == StreamDescriptor::Position::UNKNOWN) {
+ return INVALID_OPERATION;
+ }
+ *frames = reply.observable.frames;
+ *timestamp = reply.observable.timeNs;
return OK;
}
@@ -377,8 +381,12 @@
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
- *frames = std::max<int64_t>(0, reply.hardware.frames);
- *timestamp = std::max<int64_t>(0, reply.hardware.timeNs);
+ if (reply.hardware.frames == StreamDescriptor::Position::UNKNOWN ||
+ reply.hardware.timeNs == StreamDescriptor::Position::UNKNOWN) {
+ return INVALID_OPERATION;
+ }
+ *frames = reply.hardware.frames;
+ *timestamp = reply.hardware.timeNs;
return OK;
}
@@ -387,7 +395,10 @@
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
- *frames = std::max<int32_t>(0, reply.xrunFrames);
+ if (reply.xrunFrames == StreamDescriptor::Position::UNKNOWN) {
+ return INVALID_OPERATION;
+ }
+ *frames = reply.xrunFrames;
return OK;
}
@@ -577,7 +588,9 @@
// For compatibility with HIDL behavior, apply a "soft" position reset
// after receiving the "drain ready" callback.
std::lock_guard l(mLock);
- mStatePositions.framesAtFlushOrDrain = mLastReply.observable.frames;
+ if (mLastReply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
+ mStatePositions.framesAtFlushOrDrain = mLastReply.observable.frames;
+ }
} else {
AUGMENT_LOG(W, "unexpected onDrainReady in the state %s", toString(state).c_str());
}
@@ -670,7 +683,8 @@
}
mLastReply = *reply;
mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
- if (!mIsInput && reply->status == STATUS_OK) {
+ if (!mIsInput && reply->status == STATUS_OK &&
+ reply->observable.frames != StreamDescriptor::Position::UNKNOWN) {
if (command.getTag() == StreamDescriptor::Command::standby &&
reply->state == StreamDescriptor::State::STANDBY) {
mStatePositions.framesAtStandby = reply->observable.frames;
diff --git a/media/libmedia/AudioCapabilities.cpp b/media/libmedia/AudioCapabilities.cpp
index e8cf517..1a92307 100644
--- a/media/libmedia/AudioCapabilities.cpp
+++ b/media/libmedia/AudioCapabilities.cpp
@@ -26,7 +26,7 @@
namespace android {
-const Range<int>& AudioCapabilities::getBitrateRange() const {
+const Range<int32_t>& AudioCapabilities::getBitrateRange() const {
return mBitrateRange;
}
@@ -86,7 +86,7 @@
}
void AudioCapabilities::initWithPlatformLimits() {
- mBitrateRange = Range<int>(0, INT_MAX);
+ mBitrateRange = Range<int>(0, INT32_MAX);
mInputChannelRanges.push_back(Range<int>(1, MAX_INPUT_CHANNEL_COUNT));
const int minSampleRate = base::GetIntProperty("ro.mediacodec.min_sample_rate", 7350);
@@ -94,30 +94,31 @@
mSampleRateRanges.push_back(Range<int>(minSampleRate, maxSampleRate));
}
-bool AudioCapabilities::supports(int sampleRate, int inputChannels) {
+bool AudioCapabilities::supports(std::optional<int> sampleRate,
+ std::optional<int> inputChannels) {
// channels and sample rates are checked orthogonally
- if (inputChannels != 0
+ if (inputChannels
&& !std::any_of(mInputChannelRanges.begin(), mInputChannelRanges.end(),
- [inputChannels](const Range<int> &a) { return a.contains(inputChannels); })) {
+ [inputChannels](const Range<int> &a) { return a.contains(inputChannels.value()); })) {
return false;
}
- if (sampleRate != 0
+ if (sampleRate
&& !std::any_of(mSampleRateRanges.begin(), mSampleRateRanges.end(),
- [sampleRate](const Range<int> &a) { return a.contains(sampleRate); })) {
+ [sampleRate](const Range<int> &a) { return a.contains(sampleRate.value()); })) {
return false;
}
return true;
}
bool AudioCapabilities::isSampleRateSupported(int sampleRate) {
- return supports(sampleRate, 0);
+ return supports(std::make_optional<int>(sampleRate), std::nullopt);
}
void AudioCapabilities::limitSampleRates(std::vector<int> rates) {
std::vector<Range<int>> sampleRateRanges;
std::sort(rates.begin(), rates.end());
for (int rate : rates) {
- if (supports(rate, 0 /* channels */)) {
+ if (supports(std::make_optional<int>(rate), std::nullopt /* channels */)) {
sampleRateRanges.push_back(Range<int>(rate, rate));
}
}
@@ -280,7 +281,7 @@
void AudioCapabilities::applyLimits(
const std::vector<Range<int>> &inputChannels,
- const std::optional<Range<int>> &bitRates) {
+ const std::optional<Range<int32_t>> &bitRates) {
// clamp & make a local copy
std::vector<Range<int>> inputChannelsCopy(inputChannels.size());
for (int i = 0; i < inputChannels.size(); i++) {
@@ -301,7 +302,7 @@
void AudioCapabilities::parseFromInfo(const sp<AMessage> &format) {
int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
std::vector<Range<int>> channels = { Range<int>(1, maxInputChannels) };
- std::optional<Range<int>> bitRates = POSITIVE_INTEGERS;
+ std::optional<Range<int32_t>> bitRates = POSITIVE_INT32;
AString rateAString;
if (format->findString("sample-rate-ranges", &rateAString)) {
@@ -348,7 +349,7 @@
}
if (format->findString("bitrate-range", &valueStr)) {
- std::optional<Range<int>> parsedBitrate = ParseIntRange(valueStr.c_str());
+ std::optional<Range<int32_t>> parsedBitrate = ParseIntRange(valueStr.c_str());
if (parsedBitrate) {
bitRates = bitRates.value().intersect(parsedBitrate.value());
}
@@ -372,10 +373,12 @@
}
bool AudioCapabilities::supportsFormat(const sp<AMessage> &format) {
- int32_t sampleRate;
- format->findInt32(KEY_SAMPLE_RATE, &sampleRate);
- int32_t channels;
- format->findInt32(KEY_CHANNEL_COUNT, &channels);
+ int32_t sampleRateValue;
+ std::optional<int> sampleRate = format->findInt32(KEY_SAMPLE_RATE, &sampleRateValue)
+ ? std::make_optional<int>(sampleRateValue) : std::nullopt;
+ int32_t channelsValue;
+ std::optional<int> channels = format->findInt32(KEY_CHANNEL_COUNT, &channelsValue)
+ ? std::make_optional<int>(channelsValue) : std::nullopt;
if (!supports(sampleRate, channels)) {
return false;
diff --git a/media/libmedia/CodecCapabilities.cpp b/media/libmedia/CodecCapabilities.cpp
index 5bed1c4..87eb4bc 100644
--- a/media/libmedia/CodecCapabilities.cpp
+++ b/media/libmedia/CodecCapabilities.cpp
@@ -25,7 +25,7 @@
namespace android {
-bool CodecCapabilities::SupportsBitrate(Range<int> bitrateRange,
+bool CodecCapabilities::SupportsBitrate(Range<int32_t> bitrateRange,
const sp<AMessage> &format) {
// consider max bitrate over average bitrate for support
int32_t maxBitrate = 0;
diff --git a/media/libmedia/include/media/AudioCapabilities.h b/media/libmedia/include/media/AudioCapabilities.h
index 2bc3335..d2bd9d7 100644
--- a/media/libmedia/include/media/AudioCapabilities.h
+++ b/media/libmedia/include/media/AudioCapabilities.h
@@ -37,7 +37,7 @@
/**
* Returns the range of supported bitrates in bits/second.
*/
- const Range<int>& getBitrateRange() const;
+ const Range<int32_t>& getBitrateRange() const;
/**
* Returns the array of supported sample rates if the codec
@@ -110,7 +110,7 @@
std::string mMediaType;
std::vector<ProfileLevel> mProfileLevels;
- Range<int> mBitrateRange;
+ Range<int32_t> mBitrateRange;
std::vector<int> mSampleRates;
std::vector<Range<int>> mSampleRateRanges;
@@ -121,13 +121,13 @@
void init(std::string mediaType, std::vector<ProfileLevel> profLevs,
const sp<AMessage> &format);
void initWithPlatformLimits();
- bool supports(int sampleRate, int inputChannels);
+ bool supports(std::optional<int> sampleRate, std::optional<int> inputChannels);
void limitSampleRates(std::vector<int> rates);
void createDiscreteSampleRates();
void limitSampleRates(std::vector<Range<int>> rateRanges);
void applyLevelLimits();
void applyLimits(const std::vector<Range<int>> &inputChannels,
- const std::optional<Range<int>> &bitRates);
+ const std::optional<Range<int32_t>> &bitRates);
void parseFromInfo(const sp<AMessage> &format);
friend struct CodecCapabilities;
diff --git a/media/libmedia/include/media/CodecCapabilities.h b/media/libmedia/include/media/CodecCapabilities.h
index 9d1c4ea..570c8b5 100644
--- a/media/libmedia/include/media/CodecCapabilities.h
+++ b/media/libmedia/include/media/CodecCapabilities.h
@@ -34,7 +34,7 @@
struct CodecCapabilities {
- static bool SupportsBitrate(Range<int> bitrateRange,
+ static bool SupportsBitrate(Range<int32_t> bitrateRange,
const sp<AMessage> &format);
/**
diff --git a/media/libmedia/include/media/CodecCapabilitiesUtils.h b/media/libmedia/include/media/CodecCapabilitiesUtils.h
index 2bf822a..89a452c 100644
--- a/media/libmedia/include/media/CodecCapabilitiesUtils.h
+++ b/media/libmedia/include/media/CodecCapabilitiesUtils.h
@@ -118,7 +118,7 @@
T upper_;
};
-static const Range<int> POSITIVE_INTEGERS = Range<int>(1, INT_MAX);
+static const Range<int32_t> POSITIVE_INT32 = Range<int32_t>(1, INT32_MAX);
// found stuff that is not supported by framework (=> this should not happen)
constexpr int ERROR_CAPABILITIES_UNRECOGNIZED = (1 << 0);
diff --git a/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
index 89c9739..02e43a4 100644
--- a/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
+++ b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
@@ -64,7 +64,7 @@
};
TEST_F(AudioCapsAacTest, AudioCaps_Aac_Bitrate) {
- const Range<int>& bitrateRange = audioCaps->getBitrateRange();
+ const Range<int32_t>& bitrateRange = audioCaps->getBitrateRange();
EXPECT_EQ(bitrateRange.lower(), 8000) << "bitrate range1 does not match. lower: "
<< bitrateRange.lower();
EXPECT_EQ(bitrateRange.upper(), 510000) << "bitrate range1 does not match. upper: "
@@ -114,7 +114,7 @@
};
TEST_F(AudioCapsRawTest, AudioCaps_Raw_Bitrate) {
- const Range<int>& bitrateRange = audioCaps->getBitrateRange();
+ const Range<int32_t>& bitrateRange = audioCaps->getBitrateRange();
EXPECT_EQ(bitrateRange.lower(), 1);
EXPECT_EQ(bitrateRange.upper(), 10000000);
}
diff --git a/media/psh_utils/Android.bp b/media/psh_utils/Android.bp
index dafa63b..803de94 100644
--- a/media/psh_utils/Android.bp
+++ b/media/psh_utils/Android.bp
@@ -10,7 +10,7 @@
// libraries that are included whole_static for test apps
ndk_libs = [
"android.hardware.health-V3-ndk",
- "android.hardware.power.stats-V1-ndk",
+ "android.hardware.power.stats-V1-cpp",
]
// Power, System, Health utils
@@ -32,6 +32,7 @@
"com.android.media.audio-aconfig-cc",
"libaudioutils",
"libbase",
+ "libbinder",
"libbinder_ndk",
"libcutils",
"liblog",
diff --git a/media/psh_utils/HealthStatsProvider.cpp b/media/psh_utils/HealthStatsProvider.cpp
index de72463..611c424 100644
--- a/media/psh_utils/HealthStatsProvider.cpp
+++ b/media/psh_utils/HealthStatsProvider.cpp
@@ -18,7 +18,7 @@
#include <aidl/android/hardware/health/IHealth.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
-#include <psh_utils/ServiceSingleton.h>
+#include <mediautils/ServiceSingleton.h>
using ::aidl::android::hardware::health::HealthInfo;
using ::aidl::android::hardware::health::IHealth;
@@ -26,7 +26,7 @@
namespace android::media::psh_utils {
static auto getHealthService() {
- return getServiceSingleton<IHealth>();
+ return mediautils::getService<IHealth>();
}
status_t HealthStatsDataProvider::fill(PowerStats* stat) const {
diff --git a/media/psh_utils/PowerStats.cpp b/media/psh_utils/PowerStats.cpp
index f8f87c5..89e36e2 100644
--- a/media/psh_utils/PowerStats.cpp
+++ b/media/psh_utils/PowerStats.cpp
@@ -233,14 +233,14 @@
health_stats += other.health_stats;
if (power_entity_state_residency.empty()) {
power_entity_state_residency = other.power_entity_state_residency;
- } else {
+ } else if (power_entity_state_residency.size() == other.power_entity_state_residency.size()) {
for (size_t i = 0; i < power_entity_state_residency.size(); ++i) {
power_entity_state_residency[i] += other.power_entity_state_residency[i];
}
}
if (rail_energy.empty()) {
rail_energy = other.rail_energy;
- } else {
+ } else if (rail_energy.size() == other.rail_energy.size()) {
for (size_t i = 0; i < rail_energy.size(); ++i) {
rail_energy[i] += other.rail_energy[i];
}
@@ -253,14 +253,14 @@
health_stats -= other.health_stats;
if (power_entity_state_residency.empty()) {
power_entity_state_residency = other.power_entity_state_residency;
- } else {
+ } else if (power_entity_state_residency.size() == other.power_entity_state_residency.size()) {
for (size_t i = 0; i < power_entity_state_residency.size(); ++i) {
power_entity_state_residency[i] -= other.power_entity_state_residency[i];
}
}
if (rail_energy.empty()) {
rail_energy = other.rail_energy;
- } else {
+ } else if (rail_energy.size() == other.rail_energy.size()) {
for (size_t i = 0; i < rail_energy.size(); ++i) {
rail_energy[i] -= other.rail_energy[i];
}
diff --git a/media/psh_utils/PowerStatsProvider.cpp b/media/psh_utils/PowerStatsProvider.cpp
index 112c323..033ad95 100644
--- a/media/psh_utils/PowerStatsProvider.cpp
+++ b/media/psh_utils/PowerStatsProvider.cpp
@@ -15,17 +15,17 @@
*/
#include "PowerStatsProvider.h"
-#include <aidl/android/hardware/power/stats/IPowerStats.h>
+#include <android/hardware/power/stats/IPowerStats.h>
#include <android-base/logging.h>
-#include <psh_utils/ServiceSingleton.h>
+#include <mediautils/ServiceSingleton.h>
#include <unordered_map>
-using ::aidl::android::hardware::power::stats::IPowerStats;
+using ::android::hardware::power::stats::IPowerStats;
namespace android::media::psh_utils {
static auto getPowerStatsService() {
- return getServiceSingleton<IPowerStats>();
+ return mediautils::getService<IPowerStats>();
}
status_t RailEnergyDataProvider::fill(PowerStats *stat) const {
@@ -35,9 +35,9 @@
return NO_INIT;
}
- std::unordered_map<int32_t, ::aidl::android::hardware::power::stats::Channel> channelMap;
+ std::unordered_map<int32_t, ::android::hardware::power::stats::Channel> channelMap;
{
- std::vector<::aidl::android::hardware::power::stats::Channel> channels;
+ std::vector<::android::hardware::power::stats::Channel> channels;
if (!powerStatsService->getEnergyMeterInfo(&channels).isOk()) {
LOG(ERROR) << "unable to get energy meter info";
return INVALID_OPERATION;
@@ -47,7 +47,7 @@
}
}
- std::vector<::aidl::android::hardware::power::stats::EnergyMeasurement> measurements;
+ std::vector<::android::hardware::power::stats::EnergyMeasurement> measurements;
if (!powerStatsService->readEnergyMeter({}, &measurements).isOk()) {
LOG(ERROR) << "unable to get energy measurements";
return INVALID_OPERATION;
@@ -86,7 +86,7 @@
std::vector<int32_t> powerEntityIds; // ids to use
{
- std::vector<::aidl::android::hardware::power::stats::PowerEntity> entities;
+ std::vector<::android::hardware::power::stats::PowerEntity> entities;
if (!powerStatsService->getPowerEntityInfo(&entities).isOk()) {
LOG(ERROR) << __func__ << ": unable to get entity info";
return INVALID_OPERATION;
@@ -108,7 +108,7 @@
}
}
- std::vector<::aidl::android::hardware::power::stats::StateResidencyResult> results;
+ std::vector<::android::hardware::power::stats::StateResidencyResult> results;
if (!powerStatsService->getStateResidency(powerEntityIds, &results).isOk()) {
LOG(ERROR) << __func__ << ": Unable to get state residency";
return INVALID_OPERATION;
diff --git a/media/psh_utils/benchmarks/Android.bp b/media/psh_utils/benchmarks/Android.bp
index 2382c69..066771b 100644
--- a/media/psh_utils/benchmarks/Android.bp
+++ b/media/psh_utils/benchmarks/Android.bp
@@ -8,10 +8,9 @@
default_applicable_licenses: ["frameworks_av_license"],
}
-cc_benchmark {
- name: "audio_powerstats_benchmark",
+cc_defaults {
+ name: "audio_psh_utils_benchmark_defaults",
- srcs: ["audio_powerstats_benchmark.cpp"],
cflags: [
"-Wall",
"-Werror",
@@ -22,6 +21,7 @@
shared_libs: [
"libaudioutils",
"libbase",
+ "libbinder",
"libbinder_ndk",
"libcutils",
"liblog",
@@ -31,45 +31,25 @@
}
cc_benchmark {
+ name: "audio_powerstats_benchmark",
+
+ defaults: ["audio_psh_utils_benchmark_defaults"],
+
+ srcs: ["audio_powerstats_benchmark.cpp"],
+}
+
+cc_benchmark {
name: "audio_powerstatscollector_benchmark",
+ defaults: ["audio_psh_utils_benchmark_defaults"],
+
srcs: ["audio_powerstatscollector_benchmark.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- static_libs: [
- "libpshutils",
- ],
- shared_libs: [
- "libaudioutils",
- "libbase",
- "libbinder_ndk",
- "libcutils",
- "liblog",
- "libmediautils",
- "libutils",
- ],
}
cc_benchmark {
name: "audio_token_benchmark",
+ defaults: ["audio_psh_utils_benchmark_defaults"],
+
srcs: ["audio_token_benchmark.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- static_libs: [
- "libpshutils",
- ],
- shared_libs: [
- "libaudioutils",
- "libbase",
- "libbinder_ndk",
- "libcutils",
- "liblog",
- "libmediautils",
- "libutils",
- ],
}
diff --git a/media/psh_utils/include/psh_utils/ServiceSingleton.h b/media/psh_utils/include/psh_utils/ServiceSingleton.h
deleted file mode 100644
index d0cd6d2..0000000
--- a/media/psh_utils/include/psh_utils/ServiceSingleton.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/binder_auto_utils.h>
-#include <android/binder_manager.h>
-#include <android-base/thread_annotations.h>
-#include <mutex>
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-namespace android::media::psh_utils {
-
-struct DefaultServiceTraits {
- static constexpr int64_t kThresholdRetryNs = 1'000'000'000;
- static constexpr int64_t kMaxRetries = 5;
- static constexpr const char* kServiceVersion = "/default";
- static constexpr bool kShowLog = true;
-};
-
-template<typename Service, typename ServiceTraits = DefaultServiceTraits>
-std::shared_ptr<Service> getServiceSingleton() {
- [[clang::no_destroy]] static constinit std::mutex m;
- [[clang::no_destroy]] static constinit std::shared_ptr<Service> service GUARDED_BY(m);
- static int64_t nextTryNs GUARDED_BY(m) = 0;
- static int64_t tries GUARDED_BY(m) = 0;
-
- std::lock_guard l(m);
- if (service
- || tries > ServiceTraits::kMaxRetries // try too many times
- || systemTime(SYSTEM_TIME_BOOTTIME) < nextTryNs) { // try too frequently.
- return service;
- }
-
- const auto serviceName = std::string(Service::descriptor)
- .append(ServiceTraits::kServiceVersion);
- service = Service::fromBinder(
- ::ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
-
- if (!service) {
- // If failed, set a time limit before retry.
- // No need to log an error, it is already done.
- nextTryNs = systemTime(SYSTEM_TIME_BOOTTIME) + ServiceTraits::kThresholdRetryNs;
- ALOGV_IF(ServiceTraits::kShowLog, "service:%s retries:%lld of %lld nextTryNs:%lld",
- Service::descriptor, (long long)tries,
- (long long)kMaxRetries, (long long)nextTryNs);
- ++tries;
- }
-
- return service;
-}
-
-} // namespace android::media::psh_utils
diff --git a/media/psh_utils/tests/Android.bp b/media/psh_utils/tests/Android.bp
index 74589f8..64fc971 100644
--- a/media/psh_utils/tests/Android.bp
+++ b/media/psh_utils/tests/Android.bp
@@ -15,9 +15,11 @@
],
shared_libs: [
"libbase",
+ "libbinder",
"libbinder_ndk",
"libcutils",
"liblog",
+ "libmediautils",
"libutils",
],
static_libs: [
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index e340b40..762984e 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -53,6 +53,7 @@
"Process.cpp",
"ProcessInfo.cpp",
"SchedulingPolicyService.cpp",
+ "ServiceSingleton.cpp",
"ServiceUtilities.cpp",
"ThreadSnapshot.cpp",
"TimeCheck.cpp",
@@ -89,6 +90,7 @@
"libaudioutils", // for clock.h, Statistics.h
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libhidlbase",
"liblog",
@@ -112,6 +114,8 @@
],
export_shared_lib_headers: [
+ "libaudioutils",
+ "libbinder_ndk",
"libpermission",
"packagemanager_aidl-cpp",
],
diff --git a/media/utils/ServiceSingleton.cpp b/media/utils/ServiceSingleton.cpp
new file mode 100644
index 0000000..ade7a3e
--- /dev/null
+++ b/media/utils/ServiceSingleton.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ServiceSingleton"
+
+#include <mediautils/ServiceSingleton.h>
+
+namespace android::mediautils {
+
+namespace details {
+
+// To prevent multiple instances in different linkages,
+// we anchor the singleton in a .cpp instead of inlining in the header.
+
+template<typename T>
+requires (std::is_same_v<T, const char*> || std::is_same_v<T, String16>)
+std::shared_ptr<ServiceHandler> ServiceHandler::getInstance(const T& name) {
+ using Key = std::conditional_t<std::is_same_v<T, String16>, String16, std::string>;
+ [[clang::no_destroy]] static constinit std::mutex mutex;
+ [[clang::no_destroy]] static constinit std::shared_ptr<
+ std::map<Key, std::shared_ptr<ServiceHandler>>> map GUARDED_BY(mutex);
+ static constinit bool init GUARDED_BY(mutex) = false;
+
+ std::lock_guard l(mutex);
+ if (!init) {
+ map = std::make_shared<std::map<Key, std::shared_ptr<ServiceHandler>>>();
+ init = true;
+ }
+
+ auto& handler = (*map)[name];
+ if (!handler) {
+ handler = std::make_shared<ServiceHandler>();
+ if constexpr (std::is_same_v<T, String16>) {
+ handler->init_cpp();
+ } else /* constexpr */ {
+ handler->init_ndk();
+ }
+ }
+ return handler;
+}
+
+// Explicit template function instantiation.
+template
+std::shared_ptr<ServiceHandler> ServiceHandler::getInstance<const char*>(const char* const& name);
+
+template
+std::shared_ptr<ServiceHandler> ServiceHandler::getInstance<String16>(const String16& name);
+
+} // details
+
+} // namespace android::mediautils
+
diff --git a/media/utils/include/mediautils/BinderGenericUtils.h b/media/utils/include/mediautils/BinderGenericUtils.h
new file mode 100644
index 0000000..c2bbde1
--- /dev/null
+++ b/media/utils/include/mediautils/BinderGenericUtils.h
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+
+namespace android::mediautils {
+// General Template Binder Utilities.
+//
+// In order to write generic Template methods, we need to have utility methods
+// that provide seamless template overload resolution between NDK and CPP variants.
+//
+
+// Returns true or false based on whether the Interface is a NDK Interface.
+template<typename Interface>
+inline constexpr bool is_ndk = std::derived_from<Interface, ::ndk::ICInterface>;
+
+// Returns the Interface ptr type (shared_ptr or sp) based on the Interface.
+template<typename Interface>
+using InterfaceType =
+ std::conditional_t <is_ndk<Interface>, std::shared_ptr<Interface>, sp<Interface>>;
+
+template<typename Interface>
+using BaseInterfaceType = std::conditional_t <is_ndk<Interface>,
+std::shared_ptr<::ndk::ICInterface>, sp<::android::IInterface>>;
+
+/**
+ * Returns either a sp<IBinder> or an SpAIBinder object
+ * for the AIDL interface given.
+ *
+ * A -cpp interface will return sp<IBinder>.
+ * A -ndk interface will return SpAIBinder
+ */
+template<typename Interface>
+sp<IBinder> binderFromInterface(const sp<Interface> &interface) {
+ return IInterface::asBinder(interface);
+}
+
+template<typename Interface>
+::ndk::SpAIBinder binderFromInterface(const std::shared_ptr<Interface> &interface) {
+ return interface->asBinder();
+}
+
+/**
+ * Returns either a sp<Interface> or a std::shared_ptr<Interface> from a Binder object.
+ *
+ * A -cpp interface will return sp<Interface>.
+ * A -ndk interface will return std::shared_ptr<Interface>
+ */
+template<typename Interface>
+sp<Interface> interfaceFromBinder(const sp<IBinder> &binder) {
+ return interface_cast<Interface>(binder);
+}
+
+template<typename Interface>
+std::shared_ptr<Interface> interfaceFromBinder(const ::ndk::SpAIBinder &binder) {
+ return Interface::fromBinder(binder);
+}
+
+/**
+ * Returns either a sp<Interface> or a std::shared_ptr<Interface> from
+ * the NDK/CPP base interface class.
+ */
+template<typename Interface>
+sp<Interface> interfaceFromBase(const sp<::android::IInterface> &interface) {
+ // this is unvalidated, though could verify getInterfaceDescriptor() == Interface::descriptor
+ return sp<Interface>::cast(interface);
+}
+
+template<typename Interface>
+std::shared_ptr<Interface> interfaceFromBase(
+ const std::shared_ptr<::ndk::ICInterface> &interface) {
+ // this is unvalidated, though could verify
+ // !strcmp(AIBinder_Class_getDescriptor(AIBinder_getClass(...), Interface::descriptor)
+ return std::static_pointer_cast<Interface>(interface);
+}
+
+/**
+ * Returns a fully qualified service name.
+ *
+ * @param name
+ * If name is empty, it returns the name from the Service descriptor.
+ * If name starts with '/', it appends the name as a version to the Service descriptor,
+ * e.g. "/default".
+ * Otherwise the name is assumed to be the full Service name, overriding the
+ * Service descriptor.
+ */
+template<typename Service>
+auto fullyQualifiedServiceName(const char* const name) {
+ using StringType = std::conditional_t<is_ndk<Service>, std::string, String16>;
+ return name == nullptr ? StringType(Service::descriptor)
+ : name[0] != 0 && name[0] != '/' ? StringType(name)
+ : StringType(Service::descriptor) + StringType(name);
+}
+
+/**
+ * Returns either a std::shared_ptr<Interface> or sp<Interface>
+ * for the AIDL interface given.
+ *
+ * A -cpp interface will return sp<Service>.
+ * A -ndk interface will return std::shared_ptr<Service>
+ *
+ * @param name if non-empty should contain either a suffix if it starts
+ * with a '/' such as "/default", or the full service name.
+ */
+template<typename Service>
+auto checkServicePassThrough(const char *const name = "") {
+ if constexpr(is_ndk<Service>)
+ {
+ const auto serviceName = fullyQualifiedServiceName<Service>(name);
+ return Service::fromBinder(
+ ::ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
+ } else /* constexpr */ {
+ const auto serviceName = fullyQualifiedServiceName<Service>(name);
+ auto binder = defaultServiceManager()->checkService(serviceName);
+ return interface_cast<Service>(binder);
+ }
+}
+
+template<typename Service>
+void addService(const std::shared_ptr<Service> &service) {
+ AServiceManager_addService(binderFromInterface(service), Service::descriptor);
+}
+
+template<typename Service>
+void addService(const sp<Service> &service) {
+ defaultServiceManager()->addService(Service::descriptor, binderFromInterface(service));
+}
+
+namespace details {
+
+// Use the APIs below, not the details here.
+
+/**
+ * RequestServiceManagerCallback(Cpp|Ndk) is a RAII class that
+ * requests a ServiceManager callback.
+ *
+ * Note the ServiceManager is a single threaded "apartment" and only one
+ * transaction is active, hence:
+ *
+ * 1) After the RequestServiceManagerCallback object is destroyed no
+ * calls to the onBinder function is pending or will occur.
+ * 2) To prevent deadlock, do not construct or destroy the class with
+ * a lock held that the onService function also requires.
+ */
+template<typename Service>
+class RequestServiceManagerCallbackCpp {
+public:
+ explicit RequestServiceManagerCallbackCpp(
+ std::function<void(const sp<Service> &)> &&onService,
+ const char *const serviceName = ""
+ )
+ : mServiceName{fullyQualifiedServiceName<Service>(serviceName)},
+ mWaiter{sp<Waiter>::make(std::move(onService))},
+ mStatus{defaultServiceManager()->registerForNotifications(mServiceName,
+ mWaiter)} {
+ }
+
+ ~RequestServiceManagerCallbackCpp() {
+ if (mStatus == OK) {
+ defaultServiceManager()->unregisterForNotifications(mServiceName, mWaiter);
+ }
+ }
+
+ status_t getStatus() const {
+ return mStatus;
+ }
+
+private:
+ const String16 mServiceName;
+ const sp<IServiceManager::LocalRegistrationCallback> mWaiter;
+ const status_t mStatus;
+
+ // With some work here, we could make this a singleton to improve
+ // performance and reduce binder clutter.
+ class Waiter : public IServiceManager::LocalRegistrationCallback {
+ public:
+ explicit Waiter(std::function<void(const sp<Service> &)> &&onService)
+ : mOnService{std::move(onService)} {}
+
+ private:
+ void onServiceRegistration(
+ const String16 & /*name*/, const sp<IBinder> &binder) final {
+ mOnService(interface_cast<Service>(binder));
+ }
+
+ const std::function<void(const sp<Service> &)> mOnService;
+ };
+};
+
+template<typename Service>
+class RequestServiceManagerCallbackNdk {
+public:
+ explicit RequestServiceManagerCallbackNdk(
+ std::function<void(const std::shared_ptr<Service> &)> &&onService,
+ const char *const serviceName = ""
+ )
+ : mServiceName{fullyQualifiedServiceName<Service>(serviceName)},
+ mOnService{std::move(onService)},
+ mWaiter{AServiceManager_registerForServiceNotifications(
+ mServiceName.c_str(),
+ onRegister, this)} // must be registered after mOnService.
+ {}
+
+ ~RequestServiceManagerCallbackNdk() {
+ if (mWaiter) {
+ AServiceManager_NotificationRegistration_delete(mWaiter);
+ }
+ }
+
+ status_t getStatus() const {
+ return mWaiter != nullptr ? OK : INVALID_OPERATION;
+ }
+
+private:
+ const std::string mServiceName; // must keep a local copy.
+ const std::function<void(const std::shared_ptr<Service> &)> mOnService;
+ AServiceManager_NotificationRegistration *const mWaiter; // last.
+
+ static void onRegister(const char *instance, AIBinder *registered, void *cookie) {
+ (void) instance;
+ auto *callbackHandler = static_cast<RequestServiceManagerCallbackNdk<Service> *>(cookie);
+ callbackHandler->mOnService(Service::fromBinder(::ndk::SpAIBinder(registered)));
+ }
+};
+
+/**
+ * RequestDeathNotification(Cpp|Ndk) is a RAII class that
+ * requests a death notification.
+ *
+ * Note the ServiceManager is a single threaded "apartment" and only one
+ * transaction is active, hence:
+ *
+ * 1) After the RequestDeathNotification object is destroyed no
+ * calls to the onBinder function is pending or will occur.
+ * 2) To prevent deadlock, do not construct or destroy the class with
+ * a lock held that the onBinderDied function also requires.
+ */
+
+class RequestDeathNotificationCpp {
+ class DeathRecipientHelper : public IBinder::DeathRecipient {
+ public:
+ explicit DeathRecipientHelper(std::function<void()> &&onBinderDied)
+ : mOnBinderDied{std::move(onBinderDied)} {
+ }
+
+ void binderDied(const wp<IBinder> &weakBinder) final {
+ (void) weakBinder;
+ mOnBinderDied();
+ }
+
+ private:
+ const std::function<void()> mOnBinderDied;
+ };
+
+public:
+ RequestDeathNotificationCpp(const sp<IBinder> &binder,
+ std::function<void()> &&onBinderDied)
+ : mHelper{sp<DeathRecipientHelper>::make(std::move(onBinderDied))},
+ mWeakBinder{binder}, mStatus{binder->linkToDeath(mHelper)} {
+ ALOGW_IF(mStatus != OK, "%s: linkToDeath status:%d", __func__, mStatus);
+ }
+
+ ~RequestDeathNotificationCpp() {
+ if (mStatus == OK) {
+ const auto binder = mWeakBinder.promote();
+ if (binder) binder->unlinkToDeath(mHelper);
+ }
+ }
+
+ status_t getStatus() const {
+ return mStatus;
+ }
+
+private:
+ const sp<DeathRecipientHelper> mHelper;
+ const wp<IBinder> mWeakBinder;
+ const status_t mStatus;
+};
+
+class RequestDeathNotificationNdk {
+public:
+ RequestDeathNotificationNdk(
+ const ::ndk::SpAIBinder &binder, std::function<void()> &&onBinderDied)
+ : mOnBinderDied(std::move(onBinderDied)),
+ mRecipient(::AIBinder_DeathRecipient_new(OnBinderDiedStatic),
+ &AIBinder_DeathRecipient_delete), mStatus{AIBinder_linkToDeath(
+ binder.get(), mRecipient.get(), /* cookie */ this)} {
+ ALOGW_IF(mStatus != OK, "%s: AIBinder_linkToDeath status:%d", __func__, mStatus);
+ // We do not use AIBinder_DeathRecipient_setOnUnlinked() to do resource deallocation
+ // as the functor mOnBinderDied is kept alive by this class.
+ }
+
+ ~RequestDeathNotificationNdk() {
+ // The AIBinder_DeathRecipient dtor automatically unlinks all registered notifications,
+ // so AIBinder_unlinkToDeath() is not needed here (elsewise we need to maintain a
+ // AIBinder_Weak here).
+ }
+
+ status_t getStatus() const {
+ return mStatus;
+ }
+
+private:
+ void onBinderDied() {
+ mOnBinderDied();
+ }
+
+ static void OnBinderDiedStatic(void *cookie) {
+ reinterpret_cast<RequestDeathNotificationNdk *>(cookie)->onBinderDied();
+ }
+
+ const std::function<void()> mOnBinderDied;
+ const std::unique_ptr<AIBinder_DeathRecipient, decltype(
+ &AIBinder_DeathRecipient_delete)>
+ mRecipient;
+ const status_t mStatus; // binder_status_t is a limited subset of status_t
+};
+
+} // details
+
+/**
+ * Requests a notification that service is available.
+ *
+ * An opaque handle is returned - after clearing it is guaranteed that
+ * no callback will occur.
+ *
+ * The callback will be of form:
+ * onService(const sp<Service>& service);
+ * onService(const std::shared_ptr<Service>& service);
+ */
+template<typename Service, typename F>
+std::shared_ptr<void> requestServiceNotification(
+ F onService, const char *const serviceName = "") {
+ // the following are used for callbacks but placed here for invalidate.
+ using RequestServiceManagerCallback = std::conditional_t<is_ndk<Service>,
+ details::RequestServiceManagerCallbackNdk<Service>,
+ details::RequestServiceManagerCallbackCpp<Service>>;
+ const auto ptr = std::make_shared<RequestServiceManagerCallback>(
+ onService, serviceName);
+ const auto status = ptr->getStatus();
+ return status == OK ? ptr : nullptr;
+}
+
+/**
+ * Requests a death notification.
+ *
+ * An opaque handle is returned - after clearing it is guaranteed that
+ * no notification will occur.
+ *
+ * The callback will be of form void onBinderDied();
+ */
+template<typename Service>
+std::shared_ptr<void> requestDeathNotification(
+ const sp<Service> &service, std::function<void()> &&onBinderDied) {
+ const auto ptr = std::make_shared<details::RequestDeathNotificationCpp>(
+ binderFromInterface(service), std::move(onBinderDied));
+ const auto status = ptr->getStatus();
+ return status == OK ? ptr : nullptr;
+}
+
+template<typename Service>
+std::shared_ptr<void> requestDeathNotification(
+ const std::shared_ptr<Service> &service, std::function<void()> &&onBinderDied) {
+ const auto ptr = std::make_shared<details::RequestDeathNotificationNdk>(
+ binderFromInterface(service), std::move(onBinderDied));
+ const auto status = ptr->getStatus();
+ return status == OK ? ptr : nullptr;
+}
+
+} // namespace android::mediautils
diff --git a/media/utils/include/mediautils/ServiceSingleton.h b/media/utils/include/mediautils/ServiceSingleton.h
new file mode 100644
index 0000000..644d9cd
--- /dev/null
+++ b/media/utils/include/mediautils/ServiceSingleton.h
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BinderGenericUtils.h"
+
+#include <android-base/thread_annotations.h>
+#include <audio_utils/mutex.h>
+#include <chrono>
+#include <map>
+#include <mutex>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+/**
+ * ServiceSingleton provides a non-blocking NDK/CPP compatible service cache.
+ *
+ * This is a specialized cache that allows per-service configuration.
+ *
+ * Features:
+ *
+ * 1) Seamless compatibility with NDK and CPP based interfaces.
+ * 2) Time-out based service acquisition.
+ * Set the maximum time to wait for any service.
+ * 3) Service prefetch:
+ * Reduce start-up by prefetching service in advance (not on demand).
+ * Prefetch is automatically installed by getService().
+ * 4) Manual interface setting for test and non-service manager acquisition support.
+ *
+ * If both NDK and CPP interfaces are available, we prefer the CPP version
+ * for the following reasons:
+ * 1) Established sp<> reference counting avoids mistakes. NDK tends to be error-prone.
+ * 2) Possible reduced binder object clutter by a singleton notification binder object.
+ * Fewer binder objects are more efficient for the binder driver and ServiceManager.
+ * For example, fewer binder deaths means less ServiceManager (linear time) cleanup.
+ * A single binder object also offers binder access serialization.
+ * 3) CPP offers slightly better efficiency as it is closer to the
+ * actual implementation, a minor detail and effect.
+ *
+ * We use a per-service ServiceHandler object to collect methods and implementation details.
+ * Currently this is separate for NDK and CPP interfaces to the same service;
+ * unification is possible by using ibinder_internals.h.
+ */
+namespace android::mediautils {
+
+enum ServiceOptions {
+ kNone = 0,
+ kNonNull = (1 << 0), // don't return a null interface unless disabled.
+ // partially implemented and experimental.
+};
+
+// Traits may come through a constexpr static function collection.
+// This participates in small buffer optimization SBO in std::function impl.
+template <typename Service>
+struct DefaultServiceTraits {
+ // getServiceName() returns the name associated with Service.
+ //
+ // If name is empty, it returns the name from the Service descriptor.
+ // If name starts with '/', it appends the name as a version to the Service descriptor,
+ // e.g. "/default".
+ // Otherwise the name is assumed to be the Service name.
+ static constexpr const char* getServiceName() { return "/default"; }
+
+ // This callback is called when a new service is received.
+ // The callback requires at least one thread in the Binder threadpool.
+ static constexpr void onNewService(const InterfaceType<Service>&) {}
+
+ // This callback is called if the service has died.
+ // The callback requires at least one thread in the Binder threadpool.
+ static constexpr void onServiceDied(const InterfaceType<Service>&) {}
+
+ // ServiceOptions configured for the Service.
+ static constexpr ServiceOptions options() { return ServiceOptions::kNone; }
+};
+
+// We store the traits as functors.
+template <typename Service>
+struct FunctionalServiceTraits {
+ template <typename ServiceTraits>
+ explicit FunctionalServiceTraits(const ServiceTraits& serviceTraits)
+ : getServiceName{serviceTraits.getServiceName}
+ , onNewService{serviceTraits.onNewService}
+ , onServiceDied{serviceTraits.onServiceDied}
+ , options{serviceTraits.options} {
+ }
+ std::function<const char*()> getServiceName;
+ std::function<void(const InterfaceType<Service>& service)> onNewService;
+ std::function<void(const InterfaceType<Service>& service)> onServiceDied;
+ std::function<ServiceOptions()> options;
+};
+
+namespace details {
+
+class ServiceHandler
+{
+public:
+ /**
+ * Returns a ServiceHandler, templated type T is String16 for the native type
+ * of the CPP service descriptors and const char* for the native type of the NDK
+ * service descriptors.
+ */
+ template<typename T>
+ requires (std::is_same_v<T, const char*> || std::is_same_v<T, String16>)
+ static std::shared_ptr<ServiceHandler> getInstance(const T& name);
+
+ /**
+ * Initializes the service handler with new service traits
+ * (methods that are triggered on service events).
+ *
+ * This is optional. Default construction of traits is allowed for
+ * services that do not require special handling.
+ *
+ * @param serviceTraits
+ * @return true if the service handler had been previously initialized.
+ */
+ template<typename Service, typename ServiceTraits>
+ bool init(const ServiceTraits& serviceTraits) {
+ auto traits = std::make_shared<FunctionalServiceTraits<Service>>(serviceTraits);
+ std::shared_ptr<void> oldTraits;
+ std::lock_guard l(mMutex);
+ std::swap(oldTraits, mTraits);
+ const bool existing = oldTraits != nullptr;
+ mTraits = std::move(traits);
+ mSkip = false;
+ return existing;
+ }
+
+ /**
+ * Returns the service based on a timeout.
+ *
+ * @param waitNs the time to wait, internally clamped to (0, INT64_MAX / 2) to
+ * avoid numeric overflow.
+ * @param useCallback installs a callback instead of polling.
+ * the Callback persists if the call timeouts. A Callback requires
+ * at least one thread in the threadpool.
+ * @return Service interface.
+ */
+ template <typename Service>
+ auto get(std::chrono::nanoseconds waitNs, bool useCallback) {
+ audio_utils::unique_lock ul(mMutex);
+ auto& service = std::get<BaseInterfaceType<Service>>(mService);
+
+ if (mSkip || (service && mValid)) return service; // early check.
+
+ // clamp to avoid numeric overflow. INT64_MAX / 2 is effectively forever for a device.
+ std::chrono::nanoseconds kWaitLimitNs(
+ std::numeric_limits<decltype(waitNs.count())>::max() / 2);
+ waitNs = std::clamp(waitNs, decltype(waitNs)(0), kWaitLimitNs);
+ const auto end = std::chrono::steady_clock::now() + waitNs;
+
+ for (bool first = true; true; first = false) {
+ // we may have released mMutex, so see if service has been obtained.
+ if (mSkip || (service && mValid)) return service;
+
+ const auto traits = getTraits_l<Service>();
+
+ // first time or not using callback, check the service.
+ if (first || !useCallback) {
+ auto service_new = checkServicePassThrough<Service>(
+ traits->getServiceName());
+ if (service_new) {
+ mValid = true;
+ service = std::move(service_new);
+ setDeathNotifier_l<Service>();
+ auto service_fixed = service; // we're releasing the mutex.
+ ul.unlock();
+ traits->onNewService(interfaceFromBase<Service>(service_fixed));
+ mCv.notify_all();
+ return service_fixed;
+ }
+ }
+
+ // install service callback if needed.
+ if (useCallback && !mServiceNotificationHandle) {
+ setServiceNotifier_l<Service>();
+ }
+
+ // check time expiration.
+ const auto now = std::chrono::steady_clock::now();
+ if (now >= end
+ && (service || !(traits->options() & ServiceOptions::kNonNull))) {
+ return service;
+ }
+
+ // compute time to wait, then wait.
+ if (mServiceNotificationHandle) {
+ mCv.wait_until(ul, end);
+ } else {
+ const auto target = now + kPollTime;
+ mCv.wait_until(ul, std::min(target, end));
+ }
+ // loop back to see if we have any state change.
+ }
+ }
+
+ /**
+ * Sets an externally provided service override.
+ *
+ * @param Service
+ * @param service_new
+ */
+ template<typename Service>
+ void set(const InterfaceType<Service>& service_new) {
+ audio_utils::unique_lock ul(mMutex);
+ auto& service = std::get<BaseInterfaceType<Service>>(mService);
+ const auto traits = getTraits_l<Service>();
+ if (service) {
+ auto orig_service = service;
+ invalidateService_l<Service>();
+ ul.unlock();
+ traits->onServiceDied(interfaceFromBase<Service>(orig_service));
+ }
+ service = service_new;
+ ul.unlock();
+ // should we set the death notifier? It could be a local service.
+ if (service_new) traits->onNewService(service_new);
+ mCv.notify_all();
+ }
+
+ /**
+ * Disables cache management in the ServiceHandler. init() needs to be
+ * called to restart.
+ *
+ * All notifiers removed.
+ * Service pointer is released.
+ */
+ template<typename Service>
+ void skip() {
+ audio_utils::unique_lock ul(mMutex);
+ mSkip = true;
+ // remove notifiers. OK to hold lock as presuming notifications one-way
+ // or manually triggered outside of lock.
+ mDeathNotificationHandle.reset();
+ mServiceNotificationHandle.reset();
+ auto& service = std::get<BaseInterfaceType<Service>>(mService);
+ const auto traits = getTraits_l<Service>();
+ std::shared_ptr<void> oldTraits;
+ std::swap(oldTraits, mTraits); // destroyed outside of lock.
+ if (service) {
+ auto orig_service = service; // keep reference to service to manually notify death.
+ invalidateService_l<Service>(); // sets service to nullptr
+ ul.unlock();
+ traits->onServiceDied(interfaceFromBase<Service>(orig_service));
+ } else {
+ ul.unlock();
+ }
+ mCv.notify_all();
+ }
+
+private:
+
+ // invalidateService_l is called to remove the old death notifier,
+ // invalidate the service, and optionally clear the service pointer.
+ template <typename Service>
+ void invalidateService_l() REQUIRES(mMutex) {
+ mDeathNotificationHandle.reset();
+ const auto traits = getTraits_l<Service>();
+ mValid = false;
+ if (!(traits->options() & ServiceOptions::kNonNull) || mSkip) {
+ auto &service = std::get<BaseInterfaceType<Service>>(mService);
+ service = nullptr;
+ }
+ }
+
+ // gets the traits set by init(), initializes with default if init() not called.
+ template <typename Service>
+ std::shared_ptr<FunctionalServiceTraits<Service>> getTraits_l() REQUIRES(mMutex) {
+ if (!mTraits) {
+ mTraits = std::make_shared<FunctionalServiceTraits<Service>>(
+ DefaultServiceTraits<Service>{});
+ }
+ return std::static_pointer_cast<FunctionalServiceTraits<Service>>(mTraits);
+ }
+
+ // sets the service notification
+ template <typename Service>
+ void setServiceNotifier_l() REQUIRES(mMutex) {
+ const auto traits = getTraits_l<Service>();
+ mServiceNotificationHandle = requestServiceNotification<Service>(
+ [traits, this](const InterfaceType<Service>& service) {
+ audio_utils::unique_lock ul(mMutex);
+ auto originalService = std::get<BaseInterfaceType<Service>>(mService);
+ if (originalService != service) {
+ mService = service;
+ mValid = true;
+ setDeathNotifier_l<Service>();
+ traits->onNewService(service);
+ }
+ ul.unlock();
+ mCv.notify_all();
+ }, traits->getServiceName());
+ ALOGW_IF(!mServiceNotificationHandle, "%s: cannot register service notification %s"
+ " (do we have permission?)",
+ __func__, toString(Service::descriptor).c_str());
+ }
+
+ // sets the death notifier for mService (mService must be non-null).
+ template <typename Service>
+ void setDeathNotifier_l() REQUIRES(mMutex) {
+ auto base = std::get<BaseInterfaceType<Service>>(mService);
+ auto service = interfaceFromBase<Service>(base);
+ const auto binder = binderFromInterface(service);
+ if (binder.get()) {
+ auto traits = getTraits_l<Service>();
+ mDeathNotificationHandle = requestDeathNotification(
+ base, [traits, service, this]() {
+ // as only one death notification is dispatched,
+ // we do not need to generation count.
+ {
+ std::lock_guard l(mMutex);
+ invalidateService_l<Service>();
+ }
+ traits->onServiceDied(service);
+ });
+ ALOGW_IF(!mDeathNotificationHandle, "%s: cannot register death notification %s"
+ " (already died?)",
+ __func__, toString(Service::descriptor).c_str());
+ }
+ }
+
+ // initializes the variant for NDK use (called on first creation in the cache map).
+ void init_ndk() EXCLUDES(mMutex) {
+ std::lock_guard l(mMutex);
+ mService = std::shared_ptr<::ndk::ICInterface>{};
+ }
+
+ // initializes the variant for CPP use (called on first creation in the cache map).
+ void init_cpp() EXCLUDES(mMutex) {
+ std::lock_guard l(mMutex);
+ mService = sp<::android::IInterface>{};
+ }
+
+ static std::string toString(const std::string& s) { return s; }
+ static std::string toString(const String16& s) { return String8(s).c_str(); }
+
+ mutable std::mutex mMutex;
+ std::condition_variable mCv;
+ static constexpr auto kPollTime = std::chrono::seconds(1);
+
+ std::variant<std::shared_ptr<::ndk::ICInterface>,
+ sp<::android::IInterface>> mService GUARDED_BY(mMutex);
+ // aesthetically we place these last, but a ServiceHandler is never deleted in
+ // current operation, so there is no deadlock on destruction.
+ std::shared_ptr<void> mDeathNotificationHandle GUARDED_BY(mMutex);
+ std::shared_ptr<void> mServiceNotificationHandle GUARDED_BY(mMutex);
+ std::shared_ptr<void> mTraits GUARDED_BY(mMutex);
+
+ // mValid is true iff the service is non-null and alive.
+ bool mValid GUARDED_BY(mMutex) = false;
+
+ // mSkip indicates that the service is not cached.
+ bool mSkip GUARDED_BY(mMutex) = false;
+};
+
+} // details
+
+//----------------------------------
+// ServiceSingleton API
+//
+
+/*
+ * Implementation detail:
+ *
+ * Each CPP or NDK service interface has a unique ServiceHandler that
+ * is stored in a singleton cache. The cache key is based on the service descriptor string
+ * so only one version can be chosen. (The particular version may be changed using
+ * ServiceTraits.getName()).
+ */
+
+/**
+ * Sets the service trait parameters for acquiring the Service interface.
+ *
+ * If this is not set before the first service fetch, then default service traits are used.
+ *
+ * @return true if there is a preexisting (including prior default set) traits.
+ */
+template<typename Service, typename ServiceTraits>
+bool initService(const ServiceTraits& serviceTraits = {}) {
+ const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
+ return serviceHandler->template init<Service>(serviceTraits);
+}
+
+/**
+ * Returns either a std::shared_ptr<Interface> or sp<Interface>
+ * for the AIDL service. If the service is not available within waitNs,
+ * the method will return nullptr
+ * (or the previous invalidated service if Service.options() & kNonNull).
+ *
+ * This method installs a callback to obtain the service, so with waitNs == 0, it may be used to
+ * prefetch the service before it is actually needed.
+ *
+ * @param waitNs wait time for the service to become available.
+ * @return
+ * a sp<> for a CPP interface
+ * a std::shared_ptr<> for a NDK interface
+ *
+ */
+template<typename Service>
+auto getService(std::chrono::nanoseconds waitNs = {}) {
+ const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
+ return interfaceFromBase<Service>(serviceHandler->template get<Service>(
+ waitNs, true /* useCallback */));
+}
+
+/**
+ * Returns either a std::shared_ptr<Interface> or sp<Interface>
+ * for the AIDL service. If the service is not available within waitNs,
+ * the method will return nullptr
+ * (or the previous invalidated service if Service.options() & kNonNull).
+ *
+ * This method polls to obtain the service, which
+ * is useful if the service is restricted due to permissions or
+ * one is concerned about ThreadPool starvation.
+ *
+ * @param waitNs wait time for the service to become available.
+ * @return
+ * a sp<> for a CPP interface
+ * a std::shared_ptr<> for a NDK interface
+ */
+template<typename Service>
+auto checkService(std::chrono::nanoseconds waitNs = {}) {
+ const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
+ return interfaceFromBase<Service>(serviceHandler->template get<Service>(
+ waitNs, false /* useCallback */));
+}
+
+/**
+ * Sets a service implementation override, replacing any fetched service from ServiceManager.
+ *
+ * An empty service clears the cache.
+ */
+template<typename Service>
+void setService(const InterfaceType<Service>& service) {
+ const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
+ serviceHandler->template set<Service>(service);
+}
+
+/**
+ * Disables the service cache.
+ *
+ * This releases any service and notification callbacks. After this,
+ * another initService() can be called seamlessly.
+ */
+template<typename Service>
+void skipService() {
+ const auto serviceHandler = details::ServiceHandler::getInstance(Service::descriptor);
+ serviceHandler->template skip<Service>();
+}
+
+} // namespace android::mediautils
diff --git a/media/utils/tests/Android.bp b/media/utils/tests/Android.bp
index ff11b42..4456df2 100644
--- a/media/utils/tests/Android.bp
+++ b/media/utils/tests/Android.bp
@@ -12,8 +12,6 @@
cc_defaults {
name: "libmediautils_tests_config",
- host_supported: true,
-
cflags: [
"-Wall",
"-Werror",
@@ -67,6 +65,22 @@
],
}
+aidl_interface {
+ name: "ServiceSingletonTestInterface",
+ unstable: true,
+ srcs: [
+ "IServiceSingletonTest.aidl",
+ ],
+ backend: {
+ cpp: {
+ enabled: true,
+ },
+ ndk: {
+ enabled: true,
+ },
+ },
+}
+
cc_test_library {
name: "libsharedtest",
@@ -178,6 +192,34 @@
}
cc_test {
+ name: "service_singleton_tests",
+
+ defaults: ["libmediautils_tests_config"],
+
+ // to add and get services, we need to be root.
+ require_root: true,
+ host_supported: false,
+
+ srcs: [
+ "service_singleton_tests.cpp",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "libbinder",
+ "libbinder_ndk",
+ "liblog",
+ "libmediautils",
+ "libutils",
+ ],
+
+ static_libs: [
+ "ServiceSingletonTestInterface-cpp",
+ "ServiceSingletonTestInterface-ndk",
+ ],
+}
+
+cc_test {
name: "static_string_tests",
defaults: ["libmediautils_tests_defaults"],
diff --git a/media/utils/tests/IServiceSingletonTest.aidl b/media/utils/tests/IServiceSingletonTest.aidl
new file mode 100644
index 0000000..9f889a6
--- /dev/null
+++ b/media/utils/tests/IServiceSingletonTest.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+interface IServiceSingletonTest {
+ int inc();
+}
diff --git a/media/utils/tests/service_singleton_tests.cpp b/media/utils/tests/service_singleton_tests.cpp
new file mode 100644
index 0000000..8656a20
--- /dev/null
+++ b/media/utils/tests/service_singleton_tests.cpp
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "service_singleton_tests"
+
+#include <mediautils/ServiceSingleton.h>
+
+#include "BnServiceSingletonTest.h"
+#include "aidl/BnServiceSingletonTest.h"
+#include <audio_utils/RunRemote.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+using namespace android;
+
+/**
+ * Service Singleton Test uses a worker process to spawn new binder services.
+ *
+ * A worker process is required since we cannot fork after registering
+ * with the binder driver.
+ *
+ * Test Process -> Worker_Process -> Service Process(1)
+ * -> Service Process(2)
+ * -> ....
+ */
+
+// Service implementation.
+class ServiceSingletonTestCpp : public BnServiceSingletonTest {
+public:
+ binder::Status inc(int32_t* _aidl_return) final {
+ *_aidl_return = ++mValue;
+ return binder::Status::ok();
+ }
+ std::atomic_int32_t mValue = 0;
+};
+
+// The service traits increment static atomic counters, which
+// validates that the trait callbacks are invoked.
+static std::atomic_int32_t sNewService = 0;
+static std::atomic_int32_t sServiceDied = 0;
+
+template <typename Service>
+struct TestServiceTraits : public mediautils::DefaultServiceTraits<Service> {
+ static constexpr const char* getServiceName() { return ""; }
+ static constexpr void onNewService(const mediautils::InterfaceType<Service>&) {
+ ++sNewService;
+ }
+ static constexpr void onServiceDied(const mediautils::InterfaceType<Service>&) {
+ ++sServiceDied;
+ }
+};
+
+// Here we have an alternative set of service traits,
+// used to validate that we can switch traits for the service singleton.
+static std::atomic_int32_t sNewService2 = 0;
+static std::atomic_int32_t sServiceDied2 = 0;
+
+template <typename Service>
+struct TestServiceTraits2 : public mediautils::DefaultServiceTraits<Service> {
+ static constexpr const char* getServiceName() { return ""; }
+ static constexpr void onNewService(const mediautils::InterfaceType<Service>&) {
+ ++sNewService2;
+ }
+ static constexpr void onServiceDied(const mediautils::InterfaceType<Service>&) {
+ ++sServiceDied2;
+ }
+};
+
+/*
+ * ServiceThreads run in a remote process.
+ *
+ * The WorkerThread is used to launch and kill the ServiceThread in a remote process.
+ */
+static void ServiceThread(audio_utils::RunRemote& runRemote) {
+ int c = runRemote.getc(); // requires any character to launch
+ auto service = sp<IServiceSingletonTest>::cast(sp<ServiceSingletonTestCpp>::make());
+ mediautils::addService(service);
+ ProcessState::self()->startThreadPool();
+ runRemote.putc(c); // echo character.
+ IPCThreadState::self()->joinThreadPool();
+}
+
+/*
+ * The WorkerThread is run in a remote process from the test. It communicates with
+ * the test process through pipes.
+ */
+static void WorkerThread(audio_utils::RunRemote& runRemote) {
+ std::shared_ptr<audio_utils::RunRemote> remoteService;
+ while (true) {
+ const int c = runRemote.getc();
+ switch (c) {
+ case 'a': // launch a new service.
+ // if the old service isn't destroyed, it will be destroyed here
+ // when the RunRemote is replaced.
+ remoteService = std::make_shared<audio_utils::RunRemote>(ServiceThread);
+ remoteService->run();
+ remoteService->putc('a'); // create service.
+ (void)remoteService->getc(); // ensure it is created.
+ runRemote.putc(c); // echo
+ break;
+ case 'b': // destroys the old service.
+ remoteService.reset(); // this kills the service.
+ runRemote.putc(c); // echo
+ break;
+ default: // respond that we don't know what happened!
+ runRemote.putc('?');
+ break;
+ }
+ }
+}
+
+// This is a monolithic test.
+TEST(service_singleton_tests, one_and_only) {
+ std::atomic_int32_t listenerServiceCreated = 0;
+ std::atomic_int32_t listenerServiceDied = 0;
+
+ // initialize the service cache with a custom handler.
+ mediautils::initService<
+ IServiceSingletonTest, TestServiceTraits<IServiceSingletonTest>>({});
+ mediautils::initService<
+ aidl::IServiceSingletonTest, TestServiceTraits<aidl::IServiceSingletonTest>>({});
+
+ // start the worker thread that spawns the services.
+ auto remoteWorker = std::make_shared<audio_utils::RunRemote>(WorkerThread);
+ remoteWorker->run();
+
+ // now we are ready for binder.
+ ProcessState::self()->startThreadPool();
+
+ // check that our service isn't preexisting.
+ {
+ auto service = mediautils::checkServicePassThrough<IServiceSingletonTest>();
+ EXPECT_FALSE(service);
+
+ auto service2 = mediautils::checkServicePassThrough<aidl::IServiceSingletonTest>();
+ EXPECT_FALSE(service2);
+ }
+ EXPECT_EQ(0, sNewService);
+ EXPECT_EQ(0, sServiceDied);
+
+ {
+ auto service = mediautils::checkService<IServiceSingletonTest>();
+ EXPECT_FALSE(service);
+
+ auto service2 = mediautils::checkService<aidl::IServiceSingletonTest>();
+ EXPECT_FALSE(service2);
+ }
+ EXPECT_EQ(0, sNewService);
+ EXPECT_EQ(0, sServiceDied);
+
+ // getService will register a notification handler that fetches the
+ // service in the background.
+ {
+ auto service = mediautils::getService<IServiceSingletonTest>();
+ EXPECT_FALSE(service);
+
+ auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
+ EXPECT_FALSE(service2);
+ }
+ EXPECT_EQ(0, sNewService);
+ EXPECT_EQ(0, sServiceDied);
+
+ // now spawn the service.
+ remoteWorker->putc('a');
+ EXPECT_EQ('a', remoteWorker->getc());
+
+ sleep(1); // In the background, 2 services were fetched.
+
+ EXPECT_EQ(2, sNewService);
+ EXPECT_EQ(0, sServiceDied);
+
+ // we repeat the prior checks, but the service is cached now.
+ {
+ auto service = mediautils::checkServicePassThrough<IServiceSingletonTest>();
+ EXPECT_TRUE(service);
+
+ auto service2 = mediautils::checkServicePassThrough<aidl::IServiceSingletonTest>();
+ EXPECT_TRUE(service2);
+ }
+ EXPECT_EQ(2, sNewService);
+ EXPECT_EQ(0, sServiceDied);
+
+ {
+ auto service = mediautils::checkService<IServiceSingletonTest>();
+ EXPECT_TRUE(service);
+
+ auto service2 = mediautils::checkService<aidl::IServiceSingletonTest>();
+ EXPECT_TRUE(service2);
+ }
+ EXPECT_EQ(2, sNewService);
+ EXPECT_EQ(0, sServiceDied);
+
+ {
+ auto service = mediautils::getService<IServiceSingletonTest>();
+ EXPECT_TRUE(service);
+
+ auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
+ EXPECT_TRUE(service2);
+ }
+ EXPECT_EQ(2, sNewService);
+ EXPECT_EQ(0, sServiceDied);
+
+ // destroy the service.
+ remoteWorker->putc('b');
+ EXPECT_EQ('b', remoteWorker->getc());
+
+ sleep(1);
+
+ // We expect the died callbacks.
+ EXPECT_EQ(2, sNewService);
+ EXPECT_EQ(2, sServiceDied);
+
+ // we can also manually check whether there is a new service by
+ // requesting service notifications. This is outside of the service singleton
+ // traits.
+ auto handle1 = mediautils::requestServiceNotification<IServiceSingletonTest>(
+ [&](const sp<IServiceSingletonTest>&) { ++listenerServiceCreated; });
+ auto handle2 = mediautils::requestServiceNotification<aidl::IServiceSingletonTest>(
+ [&](const std::shared_ptr<aidl::IServiceSingletonTest>&) {
+ ++listenerServiceCreated; });
+
+ // Spawn the service again.
+ remoteWorker->putc('a');
+ EXPECT_EQ('a', remoteWorker->getc());
+
+ sleep(1); // In the background, 2 services were fetched.
+
+ EXPECT_EQ(4, sNewService);
+ EXPECT_EQ(2, sServiceDied);
+
+ EXPECT_EQ(2, listenerServiceCreated); // our listener picked up the service creation.
+
+ std::shared_ptr<void> handle3, handle4;
+ std::shared_ptr<aidl::IServiceSingletonTest> keepAlive; // NDK Workaround!
+ {
+ auto service = mediautils::getService<IServiceSingletonTest>();
+ EXPECT_TRUE(service);
+
+ auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
+ EXPECT_TRUE(service2);
+
+ keepAlive = service2;
+
+ // we can also request our own death notifications (outside of the service traits).
+ handle3 = mediautils::requestDeathNotification(service, [&] { ++listenerServiceDied; });
+ handle4 = mediautils::requestDeathNotification(service2, [&] { ++listenerServiceDied; });
+ }
+
+ EXPECT_EQ(4, sNewService);
+ EXPECT_EQ(2, sServiceDied);
+
+ // destroy the service.
+
+ remoteWorker->putc('b');
+ EXPECT_EQ('b', remoteWorker->getc());
+
+ sleep(1);
+
+ // We expect the died callbacks.
+ EXPECT_EQ(4, sNewService);
+ EXPECT_EQ(4, sServiceDied);
+
+ EXPECT_EQ(2, listenerServiceCreated);
+ EXPECT_EQ(2, listenerServiceDied); // NDK Workaround - without keepAlive, this is 1.
+ // the death notification is invalidated without a
+ // pointer to the binder object.
+
+ keepAlive.reset();
+
+ // Cancel the singleton cache.
+ mediautils::skipService<IServiceSingletonTest>();
+ mediautils::skipService<aidl::IServiceSingletonTest>();
+
+ // Spawn the service again.
+ remoteWorker->putc('a');
+ EXPECT_EQ('a', remoteWorker->getc());
+
+ sleep(1);
+
+ // We expect no change from the service traits (service not cached).
+ EXPECT_EQ(4, sNewService);
+ EXPECT_EQ(4, sServiceDied);
+ EXPECT_EQ(4, listenerServiceCreated); // our listener picks it up.
+
+ // remove service
+ remoteWorker->putc('b');
+ EXPECT_EQ('b', remoteWorker->getc());
+
+ sleep(1);
+
+ // We expect no change from the service traits (service not cached).
+ EXPECT_EQ(4, sNewService);
+ EXPECT_EQ(4, sServiceDied);
+ EXPECT_EQ(4, listenerServiceCreated);
+ EXPECT_EQ(2, listenerServiceDied); // binder died is associated with the actual handle.
+
+ // replace the service traits.
+ {
+ auto previous = mediautils::initService<
+ IServiceSingletonTest, TestServiceTraits2<IServiceSingletonTest>>({});
+ auto previous2 = mediautils::initService<
+ aidl::IServiceSingletonTest, TestServiceTraits2<aidl::IServiceSingletonTest>>({});
+
+ EXPECT_FALSE(previous);
+ EXPECT_FALSE(previous2);
+ }
+
+ // We expect no change with old counters.
+ EXPECT_EQ(4, sNewService);
+ EXPECT_EQ(4, sServiceDied);
+ EXPECT_EQ(0, sNewService2);
+ EXPECT_EQ(0, sServiceDied2);
+
+ {
+ auto service = mediautils::getService<IServiceSingletonTest>();
+ EXPECT_FALSE(service);
+
+ auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
+ EXPECT_FALSE(service2);
+ }
+
+ EXPECT_EQ(4, sNewService);
+ EXPECT_EQ(4, sServiceDied);
+ EXPECT_EQ(0, sNewService2);
+ EXPECT_EQ(0, sServiceDied2);
+
+ // Spawn the service again.
+ remoteWorker->putc('a');
+ EXPECT_EQ('a', remoteWorker->getc());
+
+ sleep(1);
+
+ EXPECT_EQ(4, sNewService); // old counters do not change.
+ EXPECT_EQ(4, sServiceDied);
+ EXPECT_EQ(2, sNewService2); // new counters change
+ EXPECT_EQ(0, sServiceDied2);
+
+ EXPECT_EQ(6, listenerServiceCreated); // listener associated with service name picks up info.
+
+ // Release the service.
+ remoteWorker->putc('b');
+ EXPECT_EQ('b', remoteWorker->getc());
+
+ sleep(1);
+
+ EXPECT_EQ(4, sNewService); // old counters do not change.
+ EXPECT_EQ(4, sServiceDied);
+ EXPECT_EQ(2, sNewService2); // new counters change
+ EXPECT_EQ(2, sServiceDied2);
+}
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index 1b10f81..d27d52a 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -299,7 +299,7 @@
return "Type Id Active Client(pid/uid) Session Port Id S Flags "
" Format Chn mask SRate "
"ST Usg CT "
- " G db L dB R dB VS dB PortVol dB PortMuted"
+ " G db L dB R dB VS dB PortVol dB PortMuted "
" Server FrmCnt FrmRdy F Underruns Flushed BitPerfect InternalMute"
" Latency\n"sv;
}
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 3de9968..83cd024 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -73,7 +73,7 @@
bool isDirect() const final
{ return (mFlags & AUDIO_INPUT_FLAG_DIRECT) != 0; }
- void setSilenced(bool silenced) final { if (!isPatchTrack()) mSilenced = silenced; }
+ void setSilenced(bool silenced) final;
bool isSilenced() const final { return mSilenced; }
status_t getActiveMicrophones(
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 1c0b749..060c72b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3560,26 +3560,8 @@
void PlaybackThread::checkSilentMode_l()
{
- if (!mMasterMute) {
- char value[PROPERTY_VALUE_MAX];
- if (mOutDeviceTypeAddrs.empty()) {
- ALOGD("ro.audio.silent is ignored since no output device is set");
- return;
- }
- if (isSingleDeviceType(outDeviceTypes_l(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
- ALOGD("ro.audio.silent will be ignored for threads on AUDIO_DEVICE_OUT_REMOTE_SUBMIX");
- return;
- }
- if (property_get("ro.audio.silent", value, "0") > 0) {
- char *endptr;
- unsigned long ul = strtoul(value, &endptr, 0);
- if (*endptr == '\0' && ul != 0) {
- ALOGW("%s: mute from ro.audio.silent. Silence is golden", __func__);
- // The setprop command will not allow a property to be changed after
- // the first time it is set, so we don't have to worry about un-muting.
- setMasterMute_l(true);
- }
- }
+ if (property_get_bool("ro.audio.silent", false)) {
+ ALOGW("ro.audio.silent is now ignored");
}
}
@@ -7872,6 +7854,7 @@
ssize_t DuplicatingThread::threadLoop_write()
{
+ ATRACE_BEGIN("write");
for (size_t i = 0; i < outputTracks.size(); i++) {
const ssize_t actualWritten = outputTracks[i]->write(mSinkBuffer, writeFrames);
@@ -7890,6 +7873,7 @@
// TODO: Report correction for the other output tracks and show in the dump.
}
+ ATRACE_END();
if (mStandby) {
mThreadMetrics.logBeginInterval();
mThreadSnapshot.onBegin();
@@ -11438,18 +11422,8 @@
void MmapPlaybackThread::checkSilentMode_l()
{
- if (!mMasterMute) {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("ro.audio.silent", value, "0") > 0) {
- char *endptr;
- unsigned long ul = strtoul(value, &endptr, 0);
- if (*endptr == '\0' && ul != 0) {
- ALOGW("%s: mute from ro.audio.silent. Silence is golden", __func__);
- // The setprop command will not allow a property to be changed after
- // the first time it is set, so we don't have to worry about un-muting.
- setMasterMute_l(true);
- }
- }
+ if (property_get_bool("ro.audio.silent", false)) {
+ ALOGW("ro.audio.silent is now ignored");
}
}
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 14cfb40..867561a 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1090,7 +1090,7 @@
result.appendFormat("%7s %7u/%7u %7u %7u %2s 0x%03X "
"%08X %08X %6u "
"%2u %3x %2x "
- "%5.2g %5.2g %5.2g %5.2g%c %11.2g %12s"
+ "%5.2g %5.2g %5.2g %5.2g%c %11.2g %10s "
"%08X %6zu%c %6zu %c %9u%c %7u %10s %12s",
active ? "yes" : "no",
mClient ? mClient->pid() : getpid() ,
@@ -3197,6 +3197,14 @@
*backInserter++ = metadata;
}
+void RecordTrack::setSilenced(bool silenced) {
+ if (!isPatchTrack() && mSilenced != silenced) {
+ mSilenced = silenced;
+ ALOGD("%s: track with port id: %d, (%s)", __func__, mPortId,
+ mSilenced ? "silenced" : "unsilenced");
+ }
+}
+
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AF::PatchRecord"
diff --git a/services/audioflinger/timing/MonotonicFrameCounter.cpp b/services/audioflinger/timing/MonotonicFrameCounter.cpp
index 286f549..175e2f5 100644
--- a/services/audioflinger/timing/MonotonicFrameCounter.cpp
+++ b/services/audioflinger/timing/MonotonicFrameCounter.cpp
@@ -26,9 +26,9 @@
int64_t newFrameCount, int64_t newTime) {
if (newFrameCount < 0 || newTime < 0) {
const auto result = getLastReportedFrameCount();
- ALOGW("%s: invalid (frame, time) pair newFrameCount:%lld newFrameCount:%lld,"
+ ALOGW("%s: invalid (frame, time) pair newFrameCount:%lld newTime:%lld,"
" using %lld as frameCount",
- __func__, (long long) newFrameCount, (long long)newFrameCount,
+ __func__, (long long)newFrameCount, (long long)newTime,
(long long)result);
return result;
}
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index c4bf64a..229c5e2 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -131,6 +131,8 @@
{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
AUDIO_FLAG_BEACON, ""},
{AUDIO_CONTENT_TYPE_ULTRASOUND, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_NONE, ""},
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_SPEAKER_CLEANUP, AUDIO_SOURCE_DEFAULT,
AUDIO_FLAG_NONE, ""}
}
}
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 7de6939..1082d31 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -156,40 +156,21 @@
return EngineBase::setForceUse(usage, config);
}
-bool Engine::isBtScoActive(DeviceVector& availableOutputDevices,
- const SwAudioOutputCollection &outputs) const {
+bool Engine::isBtScoActive(DeviceVector& availableOutputDevices) const {
+ // SCO is considered active if:
+ // 1) a SCO device is connected
+ // 2) the preferred device for PHONE strategy is BT SCO: this is controlled only by java
+ // AudioService and is only true if the SCO audio link as been confirmed active by BT.
if (availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
return false;
}
- // SCO is active if:
- // 1) we are in a call and SCO is the preferred device for PHONE strategy
- if (isInCall() && audio_is_bluetooth_out_sco_device(
+
+ if (!audio_is_bluetooth_out_sco_device(
getPreferredDeviceTypeForLegacyStrategy(availableOutputDevices, STRATEGY_PHONE))) {
- return true;
+ return false;
}
- // 2) A strategy for which the preferred device is SCO is active
- for (const auto &ps : getOrderedProductStrategies()) {
- if (outputs.isStrategyActive(ps) &&
- !getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps)
- .getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
- return true;
- }
- }
- // 3) a ringtone is active and SCO is used for ringing
- if (outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_RING))
- && (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
- == AUDIO_POLICY_FORCE_BT_SCO)) {
- return true;
- }
- // 4) an active input is routed from SCO
- DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
- const auto &inputs = getApmObserver()->getInputs();
- if (inputs.activeInputsCountOnDevices(availableInputDevices.getDevicesFromType(
- AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) > 0) {
- return true;
- }
- return false;
+ return true;
}
void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
@@ -200,7 +181,7 @@
if (com::android::media::audioserver::use_bt_sco_for_media()) {
// remove A2DP and LE Audio devices whenever BT SCO is in use
- if (isBtScoActive(availableOutputDevices, outputs)) {
+ if (isBtScoActive(availableOutputDevices)) {
availableOutputDevices.remove(
availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllA2dpSet()));
availableOutputDevices.remove(
@@ -372,69 +353,58 @@
// if SCO headset is connected and we are told to use it, play ringtone over
// speaker and BT SCO
- if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
- DeviceVector devices2;
- devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+ if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()
+ && audio_is_bluetooth_out_sco_device(getPreferredDeviceTypeForLegacyStrategy(
+ availableOutputDevices, STRATEGY_PHONE))) {
+ DeviceVector devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+ // devices2 cannot be empty at this point
// Use ONLY Bluetooth SCO output when ringing in vibration mode
if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
- && (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
- if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
- == AUDIO_POLICY_FORCE_BT_SCO) {
- if (!devices2.isEmpty()) {
- devices = devices2;
- break;
- }
- }
+ && (strategy == STRATEGY_ENFORCED_AUDIBLE))
+ && (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
+ == AUDIO_POLICY_FORCE_BT_SCO)) {
+ devices = devices2;
+ break;
}
// Use both Bluetooth SCO and phone default output when ringing in normal mode
- if (audio_is_bluetooth_out_sco_device(getPreferredDeviceTypeForLegacyStrategy(
- availableOutputDevices, STRATEGY_PHONE))) {
- if (strategy == STRATEGY_SONIFICATION) {
- devices.replaceDevicesByType(
- AUDIO_DEVICE_OUT_SPEAKER,
- availableOutputDevices.getDevicesFromType(
- AUDIO_DEVICE_OUT_SPEAKER_SAFE));
- }
- if (!devices2.isEmpty()) {
- devices.add(devices2);
- break;
- }
+ if (strategy == STRATEGY_SONIFICATION) {
+ devices.replaceDevicesByType(
+ AUDIO_DEVICE_OUT_SPEAKER,
+ availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
+ devices.add(devices2);
+ break;
}
// if LEA headset is connected and we are told to use it, play ringtone over
// speaker and BT LEA
- if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllBleSet()).isEmpty()) {
+ if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllBleSet()).isEmpty()
+ && audio_is_ble_out_device(getPreferredDeviceTypeForLegacyStrategy(
+ availableOutputDevices, STRATEGY_PHONE))) {
DeviceVector devices2;
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLE_HEADSET, AUDIO_DEVICE_OUT_BLE_SPEAKER});
+ // devices2 cannot be empty at this point
// Use ONLY Bluetooth LEA output when ringing in vibration mode
if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
- && (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
- if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
- == AUDIO_POLICY_FORCE_BT_BLE) {
- if (!devices2.isEmpty()) {
- devices = devices2;
- break;
- }
- }
+ && (strategy == STRATEGY_ENFORCED_AUDIBLE))
+ && (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
+ == AUDIO_POLICY_FORCE_BT_BLE)) {
+ devices = devices2;
+ break;
}
// Use both Bluetooth LEA and phone default output when ringing in normal mode
- if (audio_is_ble_out_device(getPreferredDeviceTypeForLegacyStrategy(
- availableOutputDevices, STRATEGY_PHONE))) {
- if (strategy == STRATEGY_SONIFICATION) {
- devices.replaceDevicesByType(
- AUDIO_DEVICE_OUT_SPEAKER,
- availableOutputDevices.getDevicesFromType(
- AUDIO_DEVICE_OUT_SPEAKER_SAFE));
- }
- if (!devices2.isEmpty()) {
- devices.add(devices2);
- break;
- }
+ if (strategy == STRATEGY_SONIFICATION) {
+ devices.replaceDevicesByType(
+ AUDIO_DEVICE_OUT_SPEAKER,
+ availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
+ devices.add(devices2);
+ break;
}
// The second device used for sonification is the same as the device used by media strategy
@@ -497,6 +467,18 @@
// Get the last connected device of wired and bluetooth a2dp
devices2 = availableOutputDevices.getFirstDevicesFromTypes(
getLastRemovableMediaDevices(GROUP_NONE, excludedDevices));
+ if (com::android::media::audioserver::use_bt_sco_for_media()) {
+ if (isBtScoActive(availableOutputDevices)
+ && !(devices2.getDevicesFromTypes(
+ getAudioDeviceOutAllA2dpSet()).isEmpty()
+ && devices2.getDevicesFromTypes(
+ getAudioDeviceOutAllBleSet()).isEmpty())) {
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+ { AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+ }
+ }
} else {
// Get the last connected device of wired except bluetooth a2dp
devices2 = availableOutputDevices.getFirstDevicesFromTypes(
@@ -504,15 +486,6 @@
}
}
- if (com::android::media::audioserver::use_bt_sco_for_media()) {
- if (devices2.isEmpty() && isBtScoActive(availableOutputDevices, outputs)) {
- devices2 = availableOutputDevices.getFirstDevicesFromTypes(
- { AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
- }
- }
-
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
devices2 = availableOutputDevices.getDevicesFromType(
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 862b5fd..e9c71dd 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -95,8 +95,7 @@
DeviceVector getDisabledDevicesForInputSource(
const DeviceVector& availableInputDevices, audio_source_t inputSource) const;
- bool isBtScoActive(DeviceVector& availableOutputDevices,
- const SwAudioOutputCollection &outputs) const;
+ bool isBtScoActive(DeviceVector& availableOutputDevices) const;
std::map<product_strategy_t, legacy_strategy> mLegacyStrategyMap;
};
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 54ef5d5..000b571 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3564,19 +3564,26 @@
ALOGI("%s: deviceType 0x%X, enabled %d, streamToDriveAbs %d", __func__, deviceType, enabled,
streamToDriveAbs);
- if (!enabled) {
- mAbsoluteVolumeDrivingStreams.erase(deviceType);
- return NO_ERROR;
- }
-
audio_attributes_t attributesToDriveAbs = mEngine->getAttributesForStreamType(streamToDriveAbs);
- if (attributesToDriveAbs == AUDIO_ATTRIBUTES_INITIALIZER) {
- ALOGW("%s: no attributes for stream %s, bailing out", __func__,
- toString(streamToDriveAbs).c_str());
- return BAD_VALUE;
+ if (enabled) {
+ if (attributesToDriveAbs == AUDIO_ATTRIBUTES_INITIALIZER) {
+ ALOGW("%s: no attributes for stream %s, bailing out", __func__,
+ toString(streamToDriveAbs).c_str());
+ return BAD_VALUE;
+ }
+
+ mAbsoluteVolumeDrivingStreams[deviceType] = attributesToDriveAbs;
+ } else {
+ mAbsoluteVolumeDrivingStreams.erase(deviceType);
}
- mAbsoluteVolumeDrivingStreams[deviceType] = attributesToDriveAbs;
+ // apply the stream volumes regarding the new absolute mode to all the outputs
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ ALOGV("%s: apply stream volumes for portId %d", __func__, desc->getId());
+ applyStreamVolumes(desc, {deviceType}, static_cast<int>(desc->latency()) * 2);
+ }
+
return NO_ERROR;
}
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 1ffa176..0d9427a 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -425,6 +425,17 @@
}
}
+ //TODO this permission check should extend to all system usages
+ if (attr.usage == AUDIO_USAGE_SPEAKER_CLEANUP) {
+ if (!(audioserver_permissions() ?
+ CHECK_PERM(MODIFY_AUDIO_ROUTING, attributionSource.uid)
+ : modifyAudioRoutingAllowed())) {
+ ALOGE("%s: permission denied: SPEAKER_CLEANUP not allowed for uid %d pid %d",
+ __func__, attributionSource.uid, attributionSource.pid);
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ }
+
AutoCallerClear acc;
AudioPolicyInterface::output_type_t outputType;
bool isSpatialized = false;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 03dbce2..6da1606 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -105,6 +105,20 @@
const auto &deviceIdEntry = cameraInfo.find(ANDROID_INFO_DEVICE_ID);
return deviceIdEntry.data.i32[0];
}
+
+ static android::PermissionChecker::PermissionResult appOpModeToPermissionResult(int32_t res) {
+ switch (res) {
+ case android::AppOpsManager::MODE_ERRORED:
+ return android::PermissionChecker::PERMISSION_HARD_DENIED;
+ case android::AppOpsManager::MODE_IGNORED:
+ return android::PermissionChecker::PERMISSION_SOFT_DENIED;
+ case android::AppOpsManager::MODE_ALLOWED:
+ return android::PermissionChecker::PERMISSION_GRANTED;
+ }
+
+ ALOGE("%s: Unexpected appOpMode %d", __FUNCTION__, res);
+ return android::PermissionChecker::PERMISSION_HARD_DENIED;
+ }
} // namespace anonymous
namespace android {
@@ -4073,8 +4087,8 @@
mRotationOverride(rotationOverride),
mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE),
mRemoteBinder(remoteCallback),
- mOpsActive(false),
- mOpsStreaming(false) {
+ mCameraOpen(false),
+ mCameraStreaming(false) {
if (sCameraService == nullptr) {
sCameraService = cameraService;
}
@@ -4119,7 +4133,7 @@
remote->unlinkToDeath(sCameraService);
}
- finishCameraOps();
+ notifyCameraClosing();
// Notify flashlight that a camera device is closed.
sCameraService->mFlashlight->deviceClosed(mCameraIdStr);
ALOGI("%s: Disconnected client for camera %s for PID %d", __FUNCTION__, mCameraIdStr.c_str(),
@@ -4219,14 +4233,15 @@
}
}
-status_t CameraService::BasicClient::handleAppOpMode(int32_t mode) {
- if (mode == AppOpsManager::MODE_ERRORED) {
+status_t CameraService::BasicClient::handlePermissionResult(
+ PermissionChecker::PermissionResult result) {
+ if (result == PermissionChecker::PERMISSION_HARD_DENIED) {
ALOGI("Camera %s: Access for \"%s\" has been revoked", mCameraIdStr.c_str(),
getPackageName().c_str());
return PERMISSION_DENIED;
- } else if (!mUidIsTrusted && mode == AppOpsManager::MODE_IGNORED) {
- // If the calling Uid is trusted (a native service), the AppOpsManager could
- // return MODE_IGNORED. Do not treat such case as error.
+ } else if (!mUidIsTrusted && result == PermissionChecker::PERMISSION_SOFT_DENIED) {
+ // If the calling Uid is trusted (a native service), the AppOpsManager/PermissionChecker
+ // could return MODE_IGNORED/PERMISSION_SOFT_DENIED. Do not treat such case as error.
bool isUidActive =
sCameraService->mUidPolicy->isUidActive(getClientUid(), getPackageName());
@@ -4255,31 +4270,41 @@
return OK;
}
-status_t CameraService::BasicClient::startCameraOps() {
+status_t CameraService::BasicClient::handleAppOpMode(int32_t mode) {
+ return handlePermissionResult(appOpModeToPermissionResult(mode));
+}
+
+status_t CameraService::BasicClient::notifyCameraOpening() {
ATRACE_CALL();
- {
- ALOGV("%s: Start camera ops, package name = %s, client UID = %d", __FUNCTION__,
+ // Don't start watching until we're streaming when using permissionChecker for data delivery
+ if (!flags::check_full_attribution_source_chain()) {
+ ALOGD("%s: Start camera ops, package name = %s, client UID = %d", __FUNCTION__,
getPackageName().c_str(), getClientUid());
- }
- if (mAppOpsManager != nullptr) {
- // Notify app ops that the camera is not available
- mOpsCallback = new OpsCallback(this);
- mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA, toString16(getPackageName()),
- AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
+ if (mAppOpsManager != nullptr) {
+ // Notify app ops that the camera is not available
+ mOpsCallback = new OpsCallback(this);
- // Just check for camera acccess here on open - delay startOp until
- // camera frames start streaming in startCameraStreamingOps
- int32_t mode = mAppOpsManager->checkOp(AppOpsManager::OP_CAMERA, getClientUid(),
- toString16(getPackageName()));
- status_t res = handleAppOpMode(mode);
- if (res != OK) {
- return res;
+ mAppOpsManager->startWatchingMode(
+ AppOpsManager::OP_CAMERA, toString16(getPackageName()),
+ AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
+
+ // Just check for camera access here on open - delay startOp until
+ // camera frames start streaming in startCameraStreamingOps
+ int32_t mode = mAppOpsManager->checkOp(AppOpsManager::OP_CAMERA, getClientUid(),
+ toString16(getPackageName()));
+ status_t res = handleAppOpMode(mode);
+ if (res != OK) {
+ return res;
+ }
}
+ } else {
+ // TODO: Remove when removing the check_full_attribution_source_chain flag
+ ALOGD("%s: Bypassing checkOp for uid %d", __FUNCTION__, getClientUid());
}
- mOpsActive = true;
+ mCameraOpen = true;
// Transition device availability listeners from PRESENT -> NOT_AVAILABLE
sCameraService->updateStatus(StatusInternal::NOT_AVAILABLE, mCameraIdStr);
@@ -4295,11 +4320,12 @@
status_t CameraService::BasicClient::startCameraStreamingOps() {
ATRACE_CALL();
- if (!mOpsActive) {
+ if (!mCameraOpen) {
ALOGE("%s: Calling streaming start when not yet active", __FUNCTION__);
return INVALID_OPERATION;
}
- if (mOpsStreaming) {
+
+ if (mCameraStreaming) {
ALOGV("%s: Streaming already active!", __FUNCTION__);
return OK;
}
@@ -4308,17 +4334,38 @@
getPackageName().c_str(), getClientUid());
if (mAppOpsManager != nullptr) {
- int32_t mode = mAppOpsManager->startOpNoThrow(
- AppOpsManager::OP_CAMERA, getClientUid(), toString16(getPackageName()),
- /*startIfModeDefault*/ false, toString16(getClientAttributionTag()),
- toString16("start camera ") + toString16(mCameraIdStr));
- status_t res = handleAppOpMode(mode);
- if (res != OK) {
- return res;
+ if (flags::check_full_attribution_source_chain()) {
+ ALOGD("%s: Start data delivery for uid %d", __FUNCTION__, getClientUid());
+
+ const PermissionChecker::PermissionResult result =
+ checkPermissionsForCameraForStartDataDelivery(mCameraIdStr, mClientAttribution);
+ status_t res = handlePermissionResult(result);
+ if (res != OK) {
+ return res;
+ }
+
+ mOpsCallback = new OpsCallback(this);
+ std::for_each(AttrSourceItr{mClientAttribution}, AttrSourceItr::end(),
+ [&](const auto& attr) {
+ mAppOpsManager->startWatchingMode(
+ AppOpsManager::OP_CAMERA,
+ toString16(attr.packageName.value_or("")),
+ AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
+ });
+ } else {
+ ALOGD("%s: startOp for uid %d", __FUNCTION__, getClientUid());
+ int32_t mode = mAppOpsManager->startOpNoThrow(
+ AppOpsManager::OP_CAMERA, getClientUid(), toString16(getPackageName()),
+ /*startIfModeDefault*/ false, toString16(getClientAttributionTag()),
+ toString16("start camera ") + toString16(mCameraIdStr));
+ status_t res = handleAppOpMode(mode);
+ if (res != OK) {
+ return res;
+ }
}
}
- mOpsStreaming = true;
+ mCameraStreaming = true;
return OK;
}
@@ -4331,7 +4378,12 @@
// noteAppOp is only used for when camera mute is not supported, in order
// to trigger the sensor privacy "Unblock" dialog
- if (mAppOpsManager != nullptr) {
+ if (flags::check_full_attribution_source_chain()) {
+ // Ignore the result, since we're only triggering the dialog
+ ALOGD("%s: Check data delivery permissions for uid %d", __FUNCTION__, getClientUid());
+ hasPermissionsForCameraForDataDelivery(std::string(), mClientAttribution);
+ } else if (mAppOpsManager != nullptr) {
+ ALOGD("%s: noteOp for uid %d", __FUNCTION__, getClientUid());
int32_t mode = mAppOpsManager->noteOp(
AppOpsManager::OP_CAMERA, getClientUid(), toString16(getPackageName()),
toString16(getClientAttributionTag()),
@@ -4348,36 +4400,48 @@
status_t CameraService::BasicClient::finishCameraStreamingOps() {
ATRACE_CALL();
- if (!mOpsActive) {
+ if (!mCameraOpen) {
ALOGE("%s: Calling streaming start when not yet active", __FUNCTION__);
return INVALID_OPERATION;
}
- if (!mOpsStreaming) {
+ if (!mCameraStreaming) {
ALOGV("%s: Streaming not active!", __FUNCTION__);
return OK;
}
if (mAppOpsManager != nullptr) {
- mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, getClientUid(),
- toString16(getPackageName()),
- toString16(getClientAttributionTag()));
- mOpsStreaming = false;
+ if (flags::check_full_attribution_source_chain()) {
+ ALOGD("%s: finishDataDelivery for uid %d", __FUNCTION__, getClientUid());
+ finishDataDelivery(mClientAttribution);
+
+ // Stop watching app op changes after stop streaming
+ if (mOpsCallback != nullptr) {
+ mAppOpsManager->stopWatchingMode(mOpsCallback);
+ mOpsCallback.clear();
+ }
+ } else {
+ ALOGD("%s: finishOp for uid %d", __FUNCTION__, getClientUid());
+ mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, getClientUid(),
+ toString16(getPackageName()),
+ toString16(getClientAttributionTag()));
+ }
+ mCameraStreaming = false;
}
return OK;
}
-status_t CameraService::BasicClient::finishCameraOps() {
+status_t CameraService::BasicClient::notifyCameraClosing() {
ATRACE_CALL();
- if (mOpsStreaming) {
+ if (mCameraStreaming) {
// Make sure we've notified everyone about camera stopping
finishCameraStreamingOps();
}
- // Check if startCameraOps succeeded, and if so, finish the camera op
- if (mOpsActive) {
- mOpsActive = false;
+ // Check if notifyCameraOpening succeeded, and if so, finish the camera op if necessary
+ if (mCameraOpen) {
+ mCameraOpen = false;
// This function is called when a client disconnects. This should
// release the camera, but actually only if it was in a proper
@@ -4389,11 +4453,15 @@
sCameraService->updateStatus(StatusInternal::PRESENT,
mCameraIdStr, rejected);
}
- // Always stop watching, even if no camera op is active
- if (mOpsCallback != nullptr && mAppOpsManager != nullptr) {
- mAppOpsManager->stopWatchingMode(mOpsCallback);
+
+ // When using the data delivery permission checks, the open state does not involve AppOps
+ if (!flags::check_full_attribution_source_chain()) {
+ // Always stop watching, even if no camera op is active
+ if (mOpsCallback != nullptr && mAppOpsManager != nullptr) {
+ mAppOpsManager->stopWatchingMode(mOpsCallback);
+ }
+ mOpsCallback.clear();
}
- mOpsCallback.clear();
sCameraService->mUidPolicy->unregisterMonitorUid(getClientUid(), /*closeCamera*/ true);
@@ -4414,26 +4482,60 @@
return;
}
- int32_t res;
- res = mAppOpsManager->checkOp(AppOpsManager::OP_CAMERA, getClientUid(),
- toString16(getPackageName()));
- ALOGV("checkOp returns: %d, %s ", res,
- res == AppOpsManager::MODE_ALLOWED ? "ALLOWED" :
- res == AppOpsManager::MODE_IGNORED ? "IGNORED" :
- res == AppOpsManager::MODE_ERRORED ? "ERRORED" :
- "UNKNOWN");
+ PermissionChecker::PermissionResult res;
+ if (flags::check_full_attribution_source_chain()) {
+ int32_t appOpMode = AppOpsManager::MODE_ALLOWED;
+ std::for_each(AttrSourceItr{mClientAttribution}, AttrSourceItr::end(),
+ [&](const auto& attr) {
+ appOpMode = std::max(appOpMode, mAppOpsManager->checkOp(
+ AppOpsManager::OP_CAMERA, attr.uid,
+ toString16(attr.packageName.value_or(""))));
+ });
+ ALOGV("checkOp returns: %d, %s ", res,
+ appOpMode == AppOpsManager::MODE_ALLOWED ? "ALLOWED"
+ : appOpMode == AppOpsManager::MODE_IGNORED ? "IGNORED"
+ : appOpMode == AppOpsManager::MODE_ERRORED ? "ERRORED"
+ : "UNKNOWN");
+ res = appOpModeToPermissionResult(appOpMode);
+ } else {
+ int32_t appOpMode = mAppOpsManager->checkOp(AppOpsManager::OP_CAMERA, getClientUid(),
+ toString16(getPackageName()));
+ ALOGV("checkOp returns: %d, %s ", res,
+ appOpMode == AppOpsManager::MODE_ALLOWED ? "ALLOWED"
+ : appOpMode == AppOpsManager::MODE_IGNORED ? "IGNORED"
+ : appOpMode == AppOpsManager::MODE_ERRORED ? "ERRORED"
+ : "UNKNOWN");
+ res = appOpModeToPermissionResult(appOpMode);
+ }
- if (res == AppOpsManager::MODE_ERRORED) {
+ if (res == PermissionChecker::PERMISSION_HARD_DENIED) {
ALOGI("Camera %s: Access for \"%s\" revoked", mCameraIdStr.c_str(),
getPackageName().c_str());
block();
- } else if (res == AppOpsManager::MODE_IGNORED) {
+ } else if (res == PermissionChecker::PERMISSION_SOFT_DENIED) {
bool isUidActive =
sCameraService->mUidPolicy->isUidActive(getClientUid(), getPackageName());
// Uid may be active, but not visible to the user (e.g. PROCESS_STATE_FOREGROUND_SERVICE).
// If not visible, but still active, then we want to block instead of muting the camera.
- int32_t procState = sCameraService->mUidPolicy->getProcState(getClientUid());
+ int32_t procState = ActivityManager::PROCESS_STATE_NONEXISTENT;
+ if (flags::check_full_attribution_source_chain()) {
+ // Use the proc state of the last uid in the chain (ultimately receiving the data)
+ // when determining whether to mute or block
+ int32_t uid = -1;
+ std::for_each(AttrSourceItr{mClientAttribution}, AttrSourceItr::end(),
+ [&](const auto& attr) {
+ uid = static_cast<uid_t>(attr.uid);
+ });
+ const auto& activityManager = getActivityManager();
+ if (activityManager != nullptr) {
+ procState = activityManager->getUidProcessState(uid, toString16(kServiceName));
+ } else {
+ ALOGD("%s: getActivityManager returned nullptr.", __FUNCTION__);
+ }
+ } else {
+ procState = sCameraService->mUidPolicy->getProcState(getClientUid());
+ }
bool isUidVisible = (procState <= ActivityManager::PROCESS_STATE_BOUND_TOP);
bool isCameraPrivacyEnabled;
@@ -4446,9 +4548,9 @@
}
ALOGI("Camera %s: Access for \"%s\" has been restricted, isUidTrusted %d, isUidActive %d"
- " isUidVisible %d, isCameraPrivacyEnabled %d",
+ " isUidVisible %d, isCameraPrivacyEnabled %d procState %d",
mCameraIdStr.c_str(), getPackageName().c_str(), mUidIsTrusted, isUidActive,
- isUidVisible, isCameraPrivacyEnabled);
+ isUidVisible, isCameraPrivacyEnabled, procState);
// If the calling Uid is trusted (a native service), or the client Uid is active / visible
// (WAR for b/175320666)the AppOpsManager could return MODE_IGNORED. Do not treat such
// cases as error.
@@ -4459,7 +4561,7 @@
block();
}
}
- } else if (res == AppOpsManager::MODE_ALLOWED) {
+ } else if (res == PermissionChecker::PERMISSION_GRANTED) {
setCameraMute(sCameraService->mOverrideCameraMuteMode);
}
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 07c59fc..4c93ae1 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -462,13 +462,13 @@
virtual ~BasicClient();
- // the instance is in the middle of destruction. When this is set,
+ // The instance is in the middle of destruction. When this is set,
// the instance should not be accessed from callback.
// CameraService's mClientLock should be acquired to access this.
// - subclasses should set this to true in their destructors.
bool mDestructionStarted;
- // these are initialized in the constructor.
+ // These are initialized in the constructor.
static sp<CameraService> sCameraService;
const std::string mCameraIdStr;
const int mCameraFacing;
@@ -489,16 +489,18 @@
// Permissions management methods for camera lifecycle
- // Notify rest of system/apps about camera opening, and check appops
- virtual status_t startCameraOps();
+ // Notify rest of system/apps about camera opening, and (legacy) check appops
+ virtual status_t notifyCameraOpening();
// Notify rest of system/apps about camera starting to stream data, and confirm appops
virtual status_t startCameraStreamingOps();
// Notify rest of system/apps about camera stopping streaming data
virtual status_t finishCameraStreamingOps();
// Notify rest of system/apps about camera closing
- virtual status_t finishCameraOps();
- // Handle errors for start/checkOps
+ virtual status_t notifyCameraClosing();
+ // Handle errors for start/checkOps, startDataDelivery
virtual status_t handleAppOpMode(int32_t mode);
+ virtual status_t handlePermissionResult(
+ PermissionChecker::PermissionResult result);
// Just notify camera appops to trigger unblocking dialog if sensor
// privacy is enabled and camera mute is not supported
virtual status_t noteAppOp();
@@ -516,12 +518,10 @@
}; // class OpsCallback
sp<OpsCallback> mOpsCallback;
- // Track whether checkOps was called successfully, to avoid
- // finishing what we didn't start, on camera open.
- bool mOpsActive;
- // Track whether startOps was called successfully on start of
- // camera streaming.
- bool mOpsStreaming;
+ // Track if the camera is currently active.
+ bool mCameraOpen;
+ // Track if the camera is currently streaming.
+ bool mCameraStreaming;
// IAppOpsCallback interface, indirected through opListener
virtual void opChanged(int32_t op, const String16& packageName);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 1750492..17a6dc3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -880,7 +880,6 @@
int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
int64_t streamUseCase = outputConfiguration.getStreamUseCase();
int timestampBase = outputConfiguration.getTimestampBase();
- int mirrorMode = outputConfiguration.getMirrorMode();
int32_t colorSpace = outputConfiguration.getColorSpace();
bool useReadoutTimestamp = outputConfiguration.useReadoutTimestamp();
@@ -899,7 +898,7 @@
return res;
}
- std::vector<sp<Surface>> surfaces;
+ std::vector<SurfaceHolder> surfaces;
std::vector<sp<IBinder>> binders;
status_t err;
@@ -924,6 +923,7 @@
return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.c_str());
}
+ int mirrorMode = outputConfiguration.getMirrorMode(bufferProducer);
sp<Surface> surface;
res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
@@ -938,7 +938,7 @@
}
binders.push_back(IInterface::asBinder(bufferProducer));
- surfaces.push_back(surface);
+ surfaces.push_back({surface, mirrorMode});
}
// If mOverrideForPerfClass is true, do not fail createStream() for small
@@ -948,10 +948,11 @@
int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
std::vector<int> surfaceIds;
bool isDepthCompositeStream =
- camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]);
- bool isHeicCompositeStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]);
+ camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0].mSurface);
+ bool isHeicCompositeStream = camera3::HeicCompositeStream::isHeicCompositeStream(
+ surfaces[0].mSurface);
bool isJpegRCompositeStream =
- camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaces[0]) &&
+ camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaces[0].mSurface) &&
!mDevice->isCompositeJpegRDisabled();
if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) {
sp<CompositeStream> compositeStream;
@@ -972,7 +973,8 @@
useReadoutTimestamp);
if (err == OK) {
Mutex::Autolock l(mCompositeLock);
- mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
+ mCompositeStreamMap.add(
+ IInterface::asBinder(surfaces[0].mSurface->getIGraphicBufferProducer()),
compositeStream);
}
} else {
@@ -982,8 +984,7 @@
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution,
/*consumerUsage*/0, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase,
- streamInfo.timestampBase, streamInfo.mirrorMode, streamInfo.colorSpace,
- useReadoutTimestamp);
+ streamInfo.timestampBase, streamInfo.colorSpace, useReadoutTimestamp);
}
if (err != OK) {
@@ -1008,9 +1009,6 @@
__FUNCTION__, mCameraIdStr.c_str(), streamId, streamInfo.width,
streamInfo.height, streamInfo.format);
- // Set transform flags to ensure preview to be rotated correctly.
- res = setStreamTransformLocked(streamId, streamInfo.mirrorMode);
-
// Fill in mHighResolutionCameraIdToStreamIdSet map
const std::string &cameraIdUsed =
physicalCameraId.size() != 0 ? physicalCameraId : mCameraIdStr;
@@ -1059,7 +1057,7 @@
consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
}
int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
- std::vector<sp<Surface>> noSurface;
+ std::vector<SurfaceHolder> noSurface;
std::vector<int> surfaceIds;
const std::string &physicalCameraId = outputConfiguration.getPhysicalCameraId();
const std::string &cameraIdUsed =
@@ -1085,7 +1083,6 @@
outputConfiguration.isMultiResolution(), consumerUsage,
outputConfiguration.getDynamicRangeProfile(),
outputConfiguration.getStreamUseCase(),
- outputConfiguration.getMirrorMode(),
outputConfiguration.useReadoutTimestamp());
if (err != OK) {
@@ -1104,16 +1101,12 @@
outputConfiguration.getDynamicRangeProfile(),
outputConfiguration.getStreamUseCase(),
outputConfiguration.getTimestampBase(),
- outputConfiguration.getMirrorMode(),
colorSpace));
ALOGV("%s: Camera %s: Successfully created a new stream ID %d for a deferred surface"
" (%d x %d) stream with format 0x%x.",
__FUNCTION__, mCameraIdStr.c_str(), streamId, width, height, format);
- // Set transform flags to ensure preview to be rotated correctly.
- res = setStreamTransformLocked(streamId, outputConfiguration.getMirrorMode());
-
*newStreamId = streamId;
// Fill in mHighResolutionCameraIdToStreamIdSet
// Only needed for high resolution sensors
@@ -1125,33 +1118,6 @@
return res;
}
-binder::Status CameraDeviceClient::setStreamTransformLocked(int streamId, int mirrorMode) {
- int32_t transform = 0;
- status_t err;
- binder::Status res;
-
- if (!mDevice.get()) {
- return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
- }
-
- err = getRotationTransformLocked(mirrorMode, &transform);
- if (err != OK) {
- // Error logged by getRotationTransformLocked.
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
- "Unable to calculate rotation transform for new stream");
- }
-
- err = mDevice->setStreamTransform(streamId, transform);
- if (err != OK) {
- std::string msg = fmt::sprintf("Failed to set stream transform (stream id %d)",
- streamId);
- ALOGE("%s: %s", __FUNCTION__, msg.c_str());
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
- }
-
- return res;
-}
-
binder::Status CameraDeviceClient::createInputStream(
int width, int height, int format, bool isMultiResolution,
/*out*/
@@ -1284,7 +1250,7 @@
std::vector<size_t> removedSurfaceIds;
std::vector<sp<IBinder>> removedOutputs;
- std::vector<sp<Surface>> newOutputs;
+ std::vector<SurfaceHolder> newOutputs;
std::vector<OutputStreamInfo> streamInfos;
KeyedVector<sp<IBinder>, sp<IGraphicBufferProducer>> newOutputsMap;
for (auto &it : bufferProducers) {
@@ -1313,11 +1279,11 @@
int timestampBase = outputConfiguration.getTimestampBase();
int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
int32_t colorSpace = outputConfiguration.getColorSpace();
- int mirrorMode = outputConfiguration.getMirrorMode();
for (size_t i = 0; i < newOutputsMap.size(); i++) {
OutputStreamInfo outInfo;
sp<Surface> surface;
+ int mirrorMode = outputConfiguration.getMirrorMode(newOutputsMap.valueAt(i));
res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
/*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
@@ -1326,7 +1292,7 @@
return res;
streamInfos.push_back(outInfo);
- newOutputs.push_back(surface);
+ newOutputs.push_back({surface, mirrorMode});
}
//Trivial case no changes required
@@ -1683,14 +1649,13 @@
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- std::vector<sp<Surface>> consumerSurfaces;
+ std::vector<SurfaceHolder> consumerSurfaceHolders;
const std::vector<int32_t> &sensorPixelModesUsed =
outputConfiguration.getSensorPixelModesUsed();
int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
int32_t colorSpace = outputConfiguration.getColorSpace();
int64_t streamUseCase = outputConfiguration.getStreamUseCase();
int timestampBase = outputConfiguration.getTimestampBase();
- int mirrorMode = outputConfiguration.getMirrorMode();
for (auto& bufferProducer : bufferProducers) {
// Don't create multiple streams for the same target surface
ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
@@ -1701,6 +1666,7 @@
}
sp<Surface> surface;
+ int mirrorMode = outputConfiguration.getMirrorMode(bufferProducer);
res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile,
@@ -1709,12 +1675,12 @@
if (!res.isOk())
return res;
- consumerSurfaces.push_back(surface);
+ consumerSurfaceHolders.push_back({surface, mirrorMode});
}
// Gracefully handle case where finalizeOutputConfigurations is called
// without any new surface.
- if (consumerSurfaces.size() == 0) {
+ if (consumerSurfaceHolders.size() == 0) {
mStreamInfoMap[streamId].finalized = true;
return res;
}
@@ -1722,11 +1688,11 @@
// Finish the deferred stream configuration with the surface.
status_t err;
std::vector<int> consumerSurfaceIds;
- err = mDevice->setConsumerSurfaces(streamId, consumerSurfaces, &consumerSurfaceIds);
+ err = mDevice->setConsumerSurfaces(streamId, consumerSurfaceHolders, &consumerSurfaceIds);
if (err == OK) {
- for (size_t i = 0; i < consumerSurfaces.size(); i++) {
+ for (size_t i = 0; i < consumerSurfaceHolders.size(); i++) {
sp<IBinder> binder = IInterface::asBinder(
- consumerSurfaces[i]->getIGraphicBufferProducer());
+ consumerSurfaceHolders[i].mSurface->getIGraphicBufferProducer());
ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d", __FUNCTION__,
binder.get(), streamId, consumerSurfaceIds[i]);
mStreamMap.add(binder, StreamSurfaceId(streamId, consumerSurfaceIds[i]));
@@ -2243,14 +2209,6 @@
return true;
}
-status_t CameraDeviceClient::getRotationTransformLocked(int mirrorMode,
- int32_t* transform) {
- ALOGV("%s: begin", __FUNCTION__);
-
- const CameraMetadata& staticInfo = mDevice->info();
- return CameraUtils::getRotationTransform(staticInfo, mirrorMode, transform);
-}
-
const CameraMetadata &CameraDeviceClient::getStaticInfo(const std::string &cameraId) {
if (mDevice->getId() == cameraId) {
return mDevice->info();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 1e3924f..0858633 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -232,9 +232,6 @@
virtual void onResultAvailable(const CaptureResult& result);
virtual void detachDevice();
- // Calculate the ANativeWindow transform from android.sensor.orientation
- status_t getRotationTransformLocked(int mirrorMode, /*out*/int32_t* transform);
-
bool supportsUltraHighResolutionCapture(const std::string &cameraId);
bool isSensorPixelModeConsistent(const std::list<int> &streamIdList,
@@ -291,10 +288,6 @@
bool isShared,
int* newStreamId = NULL);
- // Set the stream transform flags to automatically rotate the camera stream for preview use
- // cases.
- binder::Status setStreamTransformLocked(int streamId, int mirrorMode);
-
// Utility method to insert the surface into SurfaceMap
binder::Status insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
/*out*/SurfaceMap* surfaceMap, /*out*/Vector<int32_t>* streamIds,
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 277a8cf..e783cbc 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -34,8 +34,8 @@
return OK;
}
- // Verify ops permissions
- auto res = startCameraOps();
+ // Verify ops permissions and/or open camera
+ auto res = notifyCameraOpening();
if (res != OK) {
return res;
}
@@ -184,7 +184,7 @@
mFrameProcessor->requestExit();
mFrameProcessor->join();
- finishCameraOps();
+ notifyCameraClosing();
ALOGI("%s: Disconnected client for offline camera %s for PID %d", __FUNCTION__,
mCameraIdStr.c_str(), mCallingPid);
@@ -227,10 +227,10 @@
}
}
-status_t CameraOfflineSessionClient::startCameraOps() {
+status_t CameraOfflineSessionClient::notifyCameraOpening() {
ATRACE_CALL();
{
- ALOGV("%s: Start camera ops, package name = %s, client UID = %d", __FUNCTION__,
+ ALOGV("%s: Notify camera opening, package name = %s, client UID = %d", __FUNCTION__,
getPackageName().c_str(), getClientUid());
}
@@ -262,7 +262,7 @@
}
}
- mOpsActive = true;
+ mCameraOpen = true;
// Transition device state to OPEN
sCameraService->mUidPolicy->registerMonitorUid(getClientUid(), /*openCamera*/ true);
@@ -270,17 +270,17 @@
return OK;
}
-status_t CameraOfflineSessionClient::finishCameraOps() {
+status_t CameraOfflineSessionClient::notifyCameraClosing() {
ATRACE_CALL();
- // Check if startCameraOps succeeded, and if so, finish the camera op
- if (mOpsActive) {
+ // Check if notifyCameraOpening succeeded, and if so, finish the camera op if necessary
+ if (mCameraOpen) {
// Notify app ops that the camera is available again
if (mAppOpsManager != nullptr) {
// TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, getClientUid(),
toString16(getPackageName()));
- mOpsActive = false;
+ mCameraOpen = false;
}
}
// Always stop watching, even if no camera op is active
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 29dd72c..574ff9a 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -98,8 +98,8 @@
status_t setZoomOverride(int32_t zoomOverride) override;
// permissions management
- status_t startCameraOps() override;
- status_t finishCameraOps() override;
+ status_t notifyCameraOpening() override;
+ status_t notifyCameraClosing() override;
// FilteredResultListener API
void onResultAvailable(const CaptureResult& result) override;
diff --git a/services/camera/libcameraservice/api2/CompositeStream.cpp b/services/camera/libcameraservice/api2/CompositeStream.cpp
index 8f53458..6d7fabd 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/CompositeStream.cpp
@@ -44,7 +44,7 @@
}
}
-status_t CompositeStream::createStream(const std::vector<sp<Surface>>& consumers,
+status_t CompositeStream::createStream(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int * id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
index fa569ce..2b158c9 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.h
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -41,7 +41,7 @@
CompositeStream(sp<CameraDeviceBase> device, wp<hardware::camera2::ICameraDeviceCallbacks> cb);
virtual ~CompositeStream() {}
- status_t createStream(const std::vector<sp<Surface>>& consumers,
+ status_t createStream(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
@@ -55,7 +55,7 @@
void switchToOffline();
// Create and register all internal camera streams.
- virtual status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+ virtual status_t createInternalStreams(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 244a1e5..14618c4 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -588,7 +588,7 @@
}
-status_t DepthCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
+status_t DepthCompositeStream::createInternalStreams(const std::vector<SurfaceHolder>& consumers,
bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
@@ -643,7 +643,7 @@
if (ret == OK) {
mBlobStreamId = *id;
mBlobSurfaceId = (*surfaceIds)[0];
- mOutputSurface = consumers[0];
+ mOutputSurface = consumers[0].mSurface;
} else {
return ret;
}
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index 75deef7..9c0311e 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -49,7 +49,7 @@
static bool isDepthCompositeStreamInfo(const OutputStreamInfo& streamInfo);
// CompositeStream overrides
- status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+ status_t createInternalStreams(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 3af673b..0f4ba65 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -123,7 +123,7 @@
return ((format == HAL_PIXEL_FORMAT_BLOB) && (dataspace == HAL_DATASPACE_HEIF));
}
-status_t HeicCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
+status_t HeicCompositeStream::createInternalStreams(const std::vector<SurfaceHolder>& consumers,
bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
@@ -228,7 +228,7 @@
return res;
}
- mOutputSurface = consumers[0];
+ mOutputSurface = consumers[0].mSurface;
res = registerCompositeStreamListener(mMainImageStreamId);
if (res != OK) {
ALOGE("%s: Failed to register HAL main image stream: %s (%d)", __FUNCTION__,
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index ba10e05..fad968a 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -43,7 +43,7 @@
static bool isHeicCompositeStream(const sp<Surface> &surface);
static bool isHeicCompositeStreamInfo(const OutputStreamInfo& streamInfo);
- status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+ status_t createInternalStreams(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
index c5bd7a9..e0d7604 100644
--- a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
@@ -557,7 +557,7 @@
}
-status_t JpegRCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
+status_t JpegRCompositeStream::createInternalStreams(const std::vector<SurfaceHolder>& consumers,
bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
@@ -600,7 +600,7 @@
if (ret == OK) {
mP010StreamId = *id;
mP010SurfaceId = (*surfaceIds)[0];
- mOutputSurface = consumers[0];
+ mOutputSurface = consumers[0].mSurface;
} else {
return ret;
}
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.h b/services/camera/libcameraservice/api2/JpegRCompositeStream.h
index d3ab19c..efd31da 100644
--- a/services/camera/libcameraservice/api2/JpegRCompositeStream.h
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.h
@@ -46,7 +46,7 @@
static bool isJpegRCompositeStreamInfo(const OutputStreamInfo& streamInfo);
// CompositeStream overrides
- status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+ status_t createInternalStreams(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 1f13492..f6b1e80 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -131,10 +131,10 @@
return NO_INIT;
}
- // Verify ops permissions
- res = TClientBase::startCameraOps();
+ // Notify camera opening (check op if check_full_attribution_source_chain flag is off).
+ res = TClientBase::notifyCameraOpening();
if (res != OK) {
- TClientBase::finishCameraOps();
+ TClientBase::notifyCameraClosing();
return res;
}
@@ -142,7 +142,7 @@
if (res != OK) {
ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
__FUNCTION__, TClientBase::mCameraIdStr.c_str(), strerror(-res), res);
- TClientBase::finishCameraOps();
+ TClientBase::notifyCameraClosing();
return res;
}
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 9c8f5ad..f5e960b 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -68,6 +68,7 @@
using camera3::camera_request_template_t;;
using camera3::camera_stream_configuration_mode_t;
using camera3::camera_stream_rotation_t;
+using camera3::SurfaceHolder;
class CameraProviderManager;
@@ -200,7 +201,7 @@
* For HAL_PIXEL_FORMAT_BLOB formats, the width and height should be the
* logical dimensions of the buffer, not the number of bytes.
*/
- virtual status_t createStream(const std::vector<sp<Surface>>& consumers,
+ virtual status_t createStream(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const std::string& physicalCameraId,
@@ -212,7 +213,6 @@
int64_t dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
- int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
bool useReadoutTimestamp = false)
= 0;
@@ -404,12 +404,12 @@
* Set the deferred consumer surface and finish the rest of the stream configuration.
*/
virtual status_t setConsumerSurfaces(int streamId,
- const std::vector<sp<Surface>>& consumers, std::vector<int> *surfaceIds /*out*/) = 0;
+ const std::vector<SurfaceHolder>& consumers, std::vector<int> *surfaceIds /*out*/) = 0;
/**
* Update a given stream.
*/
- virtual status_t updateStream(int streamId, const std::vector<sp<Surface>> &newSurfaces,
+ virtual status_t updateStream(int streamId, const std::vector<SurfaceHolder> &newSurfaces,
const std::vector<android::camera3::OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/) = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 5721745..eb8cb9d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -50,6 +50,7 @@
#include <utils/Trace.h>
#include <utils/Timers.h>
#include <cutils/properties.h>
+#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
#include <android-base/properties.h>
@@ -1046,13 +1047,13 @@
return BAD_VALUE;
}
- std::vector<sp<Surface>> consumers;
- consumers.push_back(consumer);
+ std::vector<SurfaceHolder> consumers;
+ consumers.push_back(SurfaceHolder{consumer, mirrorMode});
return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
format, dataSpace, rotation, id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
streamSetId, isShared, isMultiResolution, consumerUsage, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
+ streamUseCase, timestampBase, colorSpace, useReadoutTimestamp);
}
static bool isRawFormat(int format) {
@@ -1067,14 +1068,14 @@
}
}
-status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
+status_t Camera3Device::createStream(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
uint64_t consumerUsage, int64_t dynamicRangeProfile, int64_t streamUseCase,
- int timestampBase, int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) {
+ int timestampBase, int32_t colorSpace, bool useReadoutTimestamp) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
@@ -1083,10 +1084,10 @@
ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
" consumer usage %" PRIu64 ", isShared %d, physicalCameraId %s, isMultiResolution %d"
" dynamicRangeProfile 0x%" PRIx64 ", streamUseCase %" PRId64 ", timestampBase %d,"
- " mirrorMode %d, colorSpace %d, useReadoutTimestamp %d",
+ " colorSpace %d, useReadoutTimestamp %d",
mId.c_str(), mNextStreamId, width, height, format, dataSpace, rotation,
consumerUsage, isShared, physicalCameraId.c_str(), isMultiResolution,
- dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode, colorSpace,
+ dynamicRangeProfile, streamUseCase, timestampBase, colorSpace,
useReadoutTimestamp);
status_t res;
@@ -1155,11 +1156,11 @@
return BAD_VALUE;
}
}
- newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
+ newStream = new Camera3OutputStream(mNextStreamId, consumers[0].mSurface,
width, height, blobBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
+ timestampBase, consumers[0].mMirrorMode, colorSpace, useReadoutTimestamp);
} else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
bool maxResolution =
sensorPixelModesUsed.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
@@ -1170,34 +1171,34 @@
SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
return BAD_VALUE;
}
- newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
+ newStream = new Camera3OutputStream(mNextStreamId, consumers[0].mSurface,
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
+ timestampBase, consumers[0].mMirrorMode, colorSpace, useReadoutTimestamp);
} else if (isShared) {
newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
mUseHalBufManager, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
+ timestampBase, colorSpace, useReadoutTimestamp);
} else if (consumers.size() == 0 && hasDeferredConsumer) {
newStream = new Camera3OutputStream(mNextStreamId,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
+ timestampBase, colorSpace, useReadoutTimestamp);
} else {
- newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
+ newStream = new Camera3OutputStream(mNextStreamId, consumers[0].mSurface,
width, height, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
+ timestampBase, consumers[0].mMirrorMode, colorSpace, useReadoutTimestamp);
}
size_t consumerCount = consumers.size();
for (size_t i = 0; i < consumerCount; i++) {
- int id = newStream->getSurfaceId(consumers[i]);
+ int id = newStream->getSurfaceId(consumers[i].mSurface);
if (id < 0) {
SET_ERR_L("Invalid surface id");
return BAD_VALUE;
@@ -1205,6 +1206,11 @@
if (surfaceIds != nullptr) {
surfaceIds->push_back(id);
}
+
+ res = deriveAndSetTransformLocked(*newStream, consumers[i].mMirrorMode, id);
+ if (res < 0) {
+ return res;
+ }
}
newStream->setStatusTracker(mStatusTracker);
@@ -2038,7 +2044,7 @@
}
status_t Camera3Device::setConsumerSurfaces(int streamId,
- const std::vector<sp<Surface>>& consumers, std::vector<int> *surfaceIds) {
+ const std::vector<SurfaceHolder>& consumers, std::vector<int> *surfaceIds) {
ATRACE_CALL();
ALOGV("%s: Camera %s: set consumer surface for stream %d",
__FUNCTION__, mId.c_str(), streamId);
@@ -2070,12 +2076,17 @@
}
for (auto &consumer : consumers) {
- int id = stream->getSurfaceId(consumer);
+ int id = stream->getSurfaceId(consumer.mSurface);
if (id < 0) {
CLOGE("Invalid surface id!");
return BAD_VALUE;
}
surfaceIds->push_back(id);
+
+ res = deriveAndSetTransformLocked(*stream, consumer.mMirrorMode, id);
+ if (res != OK) {
+ return res;
+ }
}
if (isDeferred) {
@@ -2101,7 +2112,7 @@
return OK;
}
-status_t Camera3Device::updateStream(int streamId, const std::vector<sp<Surface>> &newSurfaces,
+status_t Camera3Device::updateStream(int streamId, const std::vector<SurfaceHolder> &newSurfaces,
const std::vector<OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds, KeyedVector<sp<Surface>, size_t> *outputMap) {
Mutex::Autolock il(mInterfaceLock);
@@ -2131,6 +2142,14 @@
return res;
}
+ for (size_t i = 0; i < outputMap->size(); i++) {
+ res = deriveAndSetTransformLocked(
+ *stream, newSurfaces[i].mMirrorMode, outputMap->valueAt(i));
+ if (res != OK) {
+ return res;
+ }
+ }
+
return res;
}
@@ -5786,4 +5805,15 @@
}
}
+status_t Camera3Device::deriveAndSetTransformLocked(
+ Camera3OutputStreamInterface& stream, int mirrorMode, int surfaceId) {
+ int transform = -1;
+ int res = CameraUtils::getRotationTransform(mDeviceInfo, mirrorMode, &transform);
+ if (res != OK) {
+ return res;
+ }
+ stream.setTransform(transform, false /*mayChangeMirror*/, surfaceId);
+ return OK;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 3c45c1a..397ec5c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -63,6 +63,7 @@
using android::camera3::camera_stream_configuration_mode_t;
using android::camera3::CAMERA_TEMPLATE_COUNT;
using android::camera3::OutputStreamInfo;
+using android::camera3::SurfaceHolder;
namespace android {
@@ -168,7 +169,7 @@
bool useReadoutTimestamp = false)
override;
- status_t createStream(const std::vector<sp<Surface>>& consumers,
+ status_t createStream(const std::vector<SurfaceHolder>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const std::string& physicalCameraId,
@@ -181,7 +182,6 @@
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
- int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
bool useReadoutTimestamp = false)
override;
@@ -247,13 +247,13 @@
* consumer configuration.
*/
status_t setConsumerSurfaces(
- int streamId, const std::vector<sp<Surface>>& consumers,
+ int streamId, const std::vector<SurfaceHolder>& consumers,
std::vector<int> *surfaceIds /*out*/) override;
/**
* Update a given stream.
*/
- status_t updateStream(int streamId, const std::vector<sp<Surface>> &newSurfaces,
+ status_t updateStream(int streamId, const std::vector<SurfaceHolder> &newSurfaces,
const std::vector<OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
@@ -1644,6 +1644,8 @@
sp<Camera3DeviceInjectionMethods> mInjectionMethods;
void overrideStreamUseCaseLocked();
+ status_t deriveAndSetTransformLocked(camera3::Camera3OutputStreamInterface& stream,
+ int mirrorMode, int surfaceId);
}; // class Camera3Device
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
index 55467c3..79b88f8 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
@@ -76,7 +76,7 @@
Camera3IOStreamBase::dump(fd, args);
}
-status_t Camera3FakeStream::setTransform(int, bool) {
+status_t Camera3FakeStream::setTransform(int, bool, int) {
ATRACE_CALL();
// Do nothing
return OK;
@@ -120,13 +120,13 @@
return FAKE_ID;
}
-status_t Camera3FakeStream::setConsumers(const std::vector<sp<Surface>>& /*consumers*/) {
+status_t Camera3FakeStream::setConsumers(const std::vector<SurfaceHolder>& /*consumers*/) {
ALOGE("%s: Stream %d: Fake stream doesn't support set consumer surface!",
__FUNCTION__, mId);
return INVALID_OPERATION;
}
-status_t Camera3FakeStream::updateStream(const std::vector<sp<Surface>> &/*outputSurfaces*/,
+status_t Camera3FakeStream::updateStream(const std::vector<SurfaceHolder> &/*outputSurfaces*/,
const std::vector<OutputStreamInfo> &/*outputInfo*/,
const std::vector<size_t> &/*removedSurfaceIds*/,
KeyedVector<sp<Surface>, size_t> * /*outputMap*/) {
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.h b/services/camera/libcameraservice/device3/Camera3FakeStream.h
index 7addb90..9291bd0 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.h
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.h
@@ -52,7 +52,7 @@
virtual void dump(int fd, const Vector<String16> &args);
- status_t setTransform(int transform, bool mayChangeMirror);
+ status_t setTransform(int transform, bool mayChangeMirror, int surfaceId);
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
@@ -80,7 +80,7 @@
/**
* Set the consumer surfaces to the output stream.
*/
- virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
+ virtual status_t setConsumers(const std::vector<SurfaceHolder>& consumers);
/**
* Query the output surface id.
@@ -93,7 +93,7 @@
/**
* Update the stream output surfaces.
*/
- virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+ virtual status_t updateStream(const std::vector<SurfaceHolder> &outputSurfaces,
const std::vector<OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 83c8a38..dc663f3 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -136,7 +136,7 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool isMultiResolution, int64_t dynamicRangeProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) :
+ int32_t colorSpace, bool useReadoutTimestamp) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
@@ -150,7 +150,7 @@
mUseReadoutTime(useReadoutTimestamp),
mConsumerUsage(consumerUsage),
mDropBuffers(false),
- mMirrorMode(mirrorMode),
+ mMirrorMode(OutputConfiguration::MIRROR_MODE_AUTO),
mDequeueBufferLatency(kDequeueLatencyBinSize),
mIPCTransport(transport) {
// Deferred consumer only support preview surface format now.
@@ -184,8 +184,7 @@
int setId, bool isMultiResolution,
int64_t dynamicRangeProfile, int64_t streamUseCase,
bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace,
- bool useReadoutTimestamp) :
+ int32_t colorSpace, bool useReadoutTimestamp) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
format, dataSpace, rotation,
@@ -199,7 +198,7 @@
mUseReadoutTime(useReadoutTimestamp),
mConsumerUsage(consumerUsage),
mDropBuffers(false),
- mMirrorMode(mirrorMode),
+ mMirrorMode(OutputConfiguration::MIRROR_MODE_AUTO),
mDequeueBufferLatency(kDequeueLatencyBinSize),
mIPCTransport(transport) {
@@ -479,21 +478,23 @@
" DequeueBuffer latency histogram:");
}
-status_t Camera3OutputStream::setTransform(int transform, bool mayChangeMirror) {
+status_t Camera3OutputStream::setTransform(int transform, bool mayChangeMirror, int surfaceId) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
+
if (mMirrorMode != OutputConfiguration::MIRROR_MODE_AUTO && mayChangeMirror) {
// If the mirroring mode is not AUTO, do not allow transform update
// which may change mirror.
return OK;
}
- return setTransformLocked(transform);
-}
-
-status_t Camera3OutputStream::setTransformLocked(int transform) {
status_t res = OK;
+ if (surfaceId != 0) {
+ ALOGE("%s: Invalid surfaceId %d", __FUNCTION__, surfaceId);
+ return BAD_VALUE;
+ }
+
if (transform == -1) return res;
if (mState == STATE_ERROR) {
@@ -525,6 +526,12 @@
return res;
}
+ if ((res = native_window_set_buffers_transform(mConsumer.get(), mTransform)) != OK) {
+ ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
+ __FUNCTION__, mTransform, strerror(-res), res);
+ return res;
+ }
+
// Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
// We need skip these cases as timeout will disable the non-blocking (async) mode.
if (!(isConsumedByHWComposer() || isConsumedByHWTexture())) {
@@ -694,14 +701,6 @@
return res;
}
- res = native_window_set_buffers_transform(mConsumer.get(),
- mTransform);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
- __FUNCTION__, mTransform, strerror(-res), res);
- return res;
- }
-
/**
* Camera3 Buffer manager is only supported by HAL3.3 onwards, as the older HALs requires
* buffers to be statically allocated for internal static buffer registration, while the
@@ -1069,7 +1068,7 @@
return OK;
}
-status_t Camera3OutputStream::updateStream(const std::vector<sp<Surface>> &/*outputSurfaces*/,
+status_t Camera3OutputStream::updateStream(const std::vector<SurfaceHolder> &/*outputSurfaces*/,
const std::vector<OutputStreamInfo> &/*outputInfo*/,
const std::vector<size_t> &/*removedSurfaceIds*/,
KeyedVector<sp<Surface>, size_t> * /*outputMapo*/) {
@@ -1206,14 +1205,14 @@
return mConsumer == nullptr;
}
-status_t Camera3OutputStream::setConsumers(const std::vector<sp<Surface>>& consumers) {
+status_t Camera3OutputStream::setConsumers(const std::vector<SurfaceHolder>& consumers) {
Mutex::Autolock l(mLock);
if (consumers.size() != 1) {
ALOGE("%s: it's illegal to set %zu consumer surfaces!",
__FUNCTION__, consumers.size());
return INVALID_OPERATION;
}
- if (consumers[0] == nullptr) {
+ if (consumers[0].mSurface == nullptr) {
ALOGE("%s: it's illegal to set null consumer surface!", __FUNCTION__);
return INVALID_OPERATION;
}
@@ -1223,7 +1222,8 @@
return INVALID_OPERATION;
}
- mConsumer = consumers[0];
+ mConsumer = consumers[0].mSurface;
+ mMirrorMode = consumers[0].mMirrorMode;
return OK;
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index f8b78c1..a547f82 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -134,7 +134,6 @@
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
bool deviceTimeBaseIsRealtime = false,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
- int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
bool useReadoutTimestamp = false);
@@ -150,7 +149,7 @@
* Set the transform on the output stream; one of the
* HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants.
*/
- status_t setTransform(int transform, bool mayChangeMirror);
+ virtual status_t setTransform(int transform, bool mayChangeMirror, int surfaceId = 0);
/**
* Return if this output stream is for video encoding.
@@ -179,7 +178,7 @@
/**
* Set the consumer surfaces to the output stream.
*/
- virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
+ virtual status_t setConsumers(const std::vector<SurfaceHolder>& consumers);
class BufferProducerListener : public SurfaceListener {
public:
@@ -236,7 +235,7 @@
/**
* Update the stream output surfaces.
*/
- virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+ virtual status_t updateStream(const std::vector<SurfaceHolder> &outputSurfaces,
const std::vector<OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
@@ -286,7 +285,6 @@
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
bool deviceTimeBaseIsRealtime = false,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
- int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
bool useReadoutTimestamp = false);
@@ -323,8 +321,6 @@
int mTransform;
- virtual status_t setTransformLocked(int transform);
-
bool mTraceFirstBuffer;
/**
@@ -383,7 +379,7 @@
std::vector<Surface::BatchBuffer> mBatchedBuffers;
// ---- End of mBatchLock protected scope ----
- const int mMirrorMode;
+ int mMirrorMode;
/**
* Internal Camera3Stream interface
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 77edfbe..ff7ad56 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -34,7 +34,7 @@
* Set the transform on the output stream; one of the
* HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants.
*/
- virtual status_t setTransform(int transform, bool mayChangeMirror) = 0;
+ virtual status_t setTransform(int transform, bool mayChangeMirror, int surfaceId = 0) = 0;
/**
* Return if this output stream is for video encoding.
@@ -49,7 +49,7 @@
/**
* Set the consumer surfaces to the output stream.
*/
- virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers) = 0;
+ virtual status_t setConsumers(const std::vector<SurfaceHolder>& consumers) = 0;
/**
* Detach an unused buffer from the stream.
@@ -81,7 +81,7 @@
/**
* Update the stream output surfaces.
*/
- virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+ virtual status_t updateStream(const std::vector<SurfaceHolder> &outputSurfaces,
const std::vector<OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/) = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 187bd93..b436d2e 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -18,6 +18,8 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <utils/Trace.h>
+
#include "Flags.h"
#include "Camera3SharedOutputStream.h"
@@ -29,7 +31,7 @@
const size_t Camera3SharedOutputStream::kMaxOutputs;
Camera3SharedOutputStream::Camera3SharedOutputStream(int id,
- const std::vector<sp<Surface>>& surfaces,
+ const std::vector<SurfaceHolder>& surfaces,
uint32_t width, uint32_t height, int format,
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation,
@@ -37,12 +39,12 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool useHalBufManager, int64_t dynamicProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) :
+ int32_t colorSpace, bool useReadoutTimestamp) :
Camera3OutputStream(id, CAMERA_STREAM_OUTPUT, width, height,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
transport, consumerUsage, timestampOffset, setId,
/*isMultiResolution*/false, dynamicProfile, streamUseCase,
- deviceTimeBaseIsRealtime, timestampBase, mirrorMode, colorSpace,
+ deviceTimeBaseIsRealtime, timestampBase, colorSpace,
useReadoutTimestamp),
mUseHalBufManager(useHalBufManager) {
size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
@@ -50,7 +52,7 @@
ALOGE("%s: Trying to add more consumers than the maximum ", __func__);
}
for (size_t i = 0; i < consumerCount; i++) {
- mSurfaceUniqueIds[i] = std::make_pair(surfaces[i], mNextUniqueSurfaceId++);
+ mSurfaceUniqueIds[i] = SurfaceHolderUniqueId{surfaces[i], mNextUniqueSurfaceId++};
}
}
@@ -72,8 +74,8 @@
std::unordered_map<size_t, sp<Surface>> initialSurfaces;
for (size_t i = 0; i < kMaxOutputs; i++) {
- if (mSurfaceUniqueIds[i].first != nullptr) {
- initialSurfaces.emplace(i, mSurfaceUniqueIds[i].first);
+ if (mSurfaceUniqueIds[i].mSurfaceHolder.mSurface != nullptr) {
+ initialSurfaces.emplace(i, mSurfaceUniqueIds[i].mSurfaceHolder.mSurface);
}
}
@@ -142,19 +144,19 @@
return true;
}
- return (mSurfaceUniqueIds[surface_id].first == nullptr);
+ return (mSurfaceUniqueIds[surface_id].mSurfaceHolder.mSurface == nullptr);
}
-status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
+status_t Camera3SharedOutputStream::setConsumers(const std::vector<SurfaceHolder>& surfaceHolders) {
Mutex::Autolock l(mLock);
- if (surfaces.size() == 0) {
+ if (surfaceHolders.size() == 0) {
ALOGE("%s: it's illegal to set zero consumer surfaces!", __FUNCTION__);
return INVALID_OPERATION;
}
status_t ret = OK;
- for (auto& surface : surfaces) {
- if (surface == nullptr) {
+ for (auto& surfaceHolder : surfaceHolders) {
+ if (surfaceHolder.mSurface == nullptr) {
ALOGE("%s: it's illegal to set a null consumer surface!", __FUNCTION__);
return INVALID_OPERATION;
}
@@ -165,11 +167,11 @@
return NO_MEMORY;
}
- mSurfaceUniqueIds[id] = std::make_pair(surface, mNextUniqueSurfaceId++);
+ mSurfaceUniqueIds[id] = SurfaceHolderUniqueId{surfaceHolder, mNextUniqueSurfaceId++};
// Only call addOutput if the splitter has been connected.
if (mStreamSplitter != nullptr) {
- ret = mStreamSplitter->addOutput(id, surface);
+ ret = mStreamSplitter->addOutput(id, surfaceHolder.mSurface);
if (ret != OK) {
ALOGE("%s: addOutput failed with error code %d", __FUNCTION__, ret);
return ret;
@@ -222,7 +224,7 @@
for (const auto& uniqueId : uniqueSurfaceIds) {
bool uniqueIdFound = false;
for (size_t i = 0; i < kMaxOutputs; i++) {
- if (mSurfaceUniqueIds[i].second == uniqueId) {
+ if (mSurfaceUniqueIds[i].mId == uniqueId) {
surfaceIds.push_back(i);
uniqueIdFound = true;
break;
@@ -275,6 +277,23 @@
return res;
}
+ // Set buffer transform for all configured surfaces
+ for (const auto& surfaceUniqueId : mSurfaceUniqueIds) {
+ const sp<Surface>& surface = surfaceUniqueId.mSurfaceHolder.mSurface;
+ int surfaceId = surfaceUniqueId.mId;
+ int32_t transform = surfaceUniqueId.mTransform;
+ if (transform == -1 || surface == nullptr) {
+ continue;
+ }
+
+ res = mStreamSplitter->setTransform(surfaceId, transform);
+ if (res != OK) {
+ ALOGE("%s: StreamSplitter failed to setTransform: %s(%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ }
+
return OK;
}
@@ -299,8 +318,9 @@
*usage = getPresetConsumerUsage();
for (size_t id = 0; id < kMaxOutputs; id++) {
- if (mSurfaceUniqueIds[id].first != nullptr) {
- res = getEndpointUsageForSurface(&u, mSurfaceUniqueIds[id].first);
+ const auto& surface = mSurfaceUniqueIds[id].mSurfaceHolder.mSurface;
+ if (surface != nullptr) {
+ res = getEndpointUsageForSurface(&u, surface);
*usage |= u;
}
}
@@ -316,7 +336,7 @@
ssize_t Camera3SharedOutputStream::getNextSurfaceIdLocked() {
ssize_t id = -1;
for (size_t i = 0; i < kMaxOutputs; i++) {
- if (mSurfaceUniqueIds[i].first == nullptr) {
+ if (mSurfaceUniqueIds[i].mSurfaceHolder.mSurface == nullptr) {
id = i;
break;
}
@@ -329,7 +349,7 @@
Mutex::Autolock l(mLock);
ssize_t id = -1;
for (size_t i = 0; i < kMaxOutputs; i++) {
- if (mSurfaceUniqueIds[i].first == surface) {
+ if (mSurfaceUniqueIds[i].mSurfaceHolder.mSurface == surface) {
id = i;
break;
}
@@ -353,13 +373,13 @@
if (surfaceId >= kMaxOutputs) {
return BAD_VALUE;
}
- outUniqueIds->push_back(mSurfaceUniqueIds[surfaceId].second);
+ outUniqueIds->push_back(mSurfaceUniqueIds[surfaceId].mId);
}
return OK;
}
status_t Camera3SharedOutputStream::revertPartialUpdateLocked(
- const KeyedVector<sp<Surface>, size_t> &removedSurfaces,
+ const KeyedVector<size_t, SurfaceHolder> &removedSurfaces,
const KeyedVector<sp<Surface>, size_t> &attachedSurfaces) {
status_t ret = OK;
@@ -371,25 +391,25 @@
return UNKNOWN_ERROR;
}
}
- mSurfaceUniqueIds[index] = std::make_pair(nullptr, mNextUniqueSurfaceId++);
+ mSurfaceUniqueIds[index] = SurfaceHolderUniqueId{mNextUniqueSurfaceId++};
}
for (size_t i = 0; i < removedSurfaces.size(); i++) {
- size_t index = removedSurfaces.valueAt(i);
+ size_t index = removedSurfaces.keyAt(i);
if (mStreamSplitter != nullptr) {
- ret = mStreamSplitter->addOutput(index, removedSurfaces.keyAt(i));
+ ret = mStreamSplitter->addOutput(index, removedSurfaces.valueAt(i).mSurface);
if (ret != OK) {
return UNKNOWN_ERROR;
}
}
- mSurfaceUniqueIds[index] = std::make_pair(
- removedSurfaces.keyAt(i), mNextUniqueSurfaceId++);
+ mSurfaceUniqueIds[index] = SurfaceHolderUniqueId{removedSurfaces.valueAt(i),
+ mNextUniqueSurfaceId++};
}
return ret;
}
-status_t Camera3SharedOutputStream::updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+status_t Camera3SharedOutputStream::updateStream(const std::vector<SurfaceHolder> &outputSurfaces,
const std::vector<OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap) {
@@ -403,7 +423,7 @@
uint64_t usage;
getEndpointUsage(&usage);
- KeyedVector<sp<Surface>, size_t> removedSurfaces;
+ KeyedVector<size_t, SurfaceHolder> removedSurfaces;
//Check whether the new surfaces are compatible.
for (const auto &infoIt : outputInfo) {
bool imgReaderUsage = (infoIt.consumerUsage & GRALLOC_USAGE_SW_READ_OFTEN) ? true : false;
@@ -437,8 +457,8 @@
}
}
- removedSurfaces.add(mSurfaceUniqueIds[it].first, it);
- mSurfaceUniqueIds[it] = std::make_pair(nullptr, mNextUniqueSurfaceId++);
+ removedSurfaces.add(it, mSurfaceUniqueIds[it].mSurfaceHolder);
+ mSurfaceUniqueIds[it] = SurfaceHolderUniqueId{mNextUniqueSurfaceId++};
}
//Next add the new outputs
@@ -453,7 +473,7 @@
return NO_MEMORY;
}
if (mStreamSplitter != nullptr) {
- ret = mStreamSplitter->addOutput(surfaceId, it);
+ ret = mStreamSplitter->addOutput(surfaceId, it.mSurface);
if (ret != OK) {
ALOGE("%s: failed with error code %d", __FUNCTION__, ret);
status_t res = revertPartialUpdateLocked(removedSurfaces, *outputMap);
@@ -463,13 +483,54 @@
return ret;
}
}
- mSurfaceUniqueIds[surfaceId] = std::make_pair(it, mNextUniqueSurfaceId++);
- outputMap->add(it, surfaceId);
+ mSurfaceUniqueIds[surfaceId] = SurfaceHolderUniqueId{it, mNextUniqueSurfaceId++};
+ outputMap->add(it.mSurface, surfaceId);
}
return ret;
}
+status_t Camera3SharedOutputStream::setTransform(
+ int transform, bool mayChangeMirror, int surfaceId) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mLock);
+
+ status_t res = OK;
+
+ if (surfaceId < 0 || (size_t)surfaceId >= mSurfaceUniqueIds.size()) {
+ ALOGE("%s: Invalid surfaceId %d", __FUNCTION__, surfaceId);
+ return BAD_VALUE;
+ }
+ if (transform == -1) return res;
+
+ if (mState == STATE_ERROR) {
+ ALOGE("%s: Stream in error state", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ auto& surfaceHolderForId = mSurfaceUniqueIds[surfaceId];
+ if (surfaceHolderForId.mSurfaceHolder.mMirrorMode != OutputConfiguration::MIRROR_MODE_AUTO &&
+ mayChangeMirror) {
+ // If the mirroring mode is not AUTO, do not allow transform update
+ // which may change mirror.
+ return OK;
+ }
+
+ surfaceHolderForId.mTransform = transform;
+ if (mState == STATE_CONFIGURED) {
+ sp<Surface> surface = surfaceHolderForId.mSurfaceHolder.mSurface;
+ if (surface != nullptr) {
+ res = mStreamSplitter->setTransform(surfaceId, transform);
+ if (res != OK) {
+ ALOGE("%s: StreamSplitter fails to setTransform: %s(%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ }
+ }
+ return res;
+}
+
} // namespace camera3
} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index ae11507..1fd676c 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -41,21 +41,15 @@
* surfaces. A valid stream set id needs to be set to support buffer
* sharing between multiple streams.
*/
- Camera3SharedOutputStream(int id, const std::vector<sp<Surface>>& surfaces,
+ Camera3SharedOutputStream(int id, const std::vector<SurfaceHolder>& surfaces,
uint32_t width, uint32_t height, int format,
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const std::string& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
- int setId = CAMERA3_STREAM_SET_ID_INVALID,
- bool useHalBufManager = false,
- int64_t dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
- int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
- bool deviceTimeBaseIsRealtime = false,
- int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
- int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
- bool useReadoutTimestamp = false);
+ int setId, bool useHalBufManager, int64_t dynamicProfile, int64_t streamUseCase,
+ bool deviceTimeBaseIsRealtime, int timestampBase,
+ int32_t colorSpace, bool useReadoutTimestamp);
virtual ~Camera3SharedOutputStream();
@@ -65,7 +59,7 @@
virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
- virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
+ virtual status_t setConsumers(const std::vector<SurfaceHolder>& consumers);
virtual ssize_t getSurfaceId(const sp<Surface> &surface);
@@ -78,7 +72,7 @@
virtual status_t getUniqueSurfaceIds(const std::vector<size_t>& surfaceIds,
/*out*/std::vector<size_t>* outUniqueIds) override;
- virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+ virtual status_t updateStream(const std::vector<SurfaceHolder> &outputSurfaces,
const std::vector<OutputStreamInfo> &outputInfo,
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
@@ -89,6 +83,8 @@
return false;
}
+ virtual status_t setTransform(int transform, bool mayChangeMirror, int surfaceId);
+
private:
static const size_t kMaxOutputs = 4;
@@ -97,17 +93,26 @@
// depends on this flag.
bool mUseHalBufManager;
- // Pair of an output Surface and its unique ID
- typedef std::pair<sp<Surface>, size_t> SurfaceUniqueId;
+ // Struct of an output SurfaceHolder, transform, and its unique ID
+ struct SurfaceHolderUniqueId {
+ SurfaceHolder mSurfaceHolder;
+ int mTransform = -1;
+ size_t mId = -1;
- // Map surfaceId -> (output surface, unique surface ID)
- std::array<SurfaceUniqueId, kMaxOutputs> mSurfaceUniqueIds;
+ SurfaceHolderUniqueId() = default;
+ SurfaceHolderUniqueId(size_t id) : mId(id) {}
+ SurfaceHolderUniqueId(const SurfaceHolder& holder, size_t id) :
+ mSurfaceHolder(holder), mId(id) {}
+ };
+
+ // Map surfaceId -> SurfaceHolderUniqueId
+ std::array<SurfaceHolderUniqueId, kMaxOutputs> mSurfaceUniqueIds;
size_t mNextUniqueSurfaceId = 0;
ssize_t getNextSurfaceIdLocked();
- status_t revertPartialUpdateLocked(const KeyedVector<sp<Surface>, size_t> &removedSurfaces,
+ status_t revertPartialUpdateLocked(const KeyedVector<size_t, SurfaceHolder> &removedSurfaces,
const KeyedVector<sp<Surface>, size_t> &attachedSurfaces);
/**
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 0786622..8f3249d 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -115,7 +115,6 @@
int64_t dynamicRangeProfile;
int64_t streamUseCase;
int timestampBase;
- int mirrorMode;
int32_t colorSpace;
OutputStreamInfo() :
width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
@@ -123,17 +122,21 @@
dynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
streamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
timestampBase(OutputConfiguration::TIMESTAMP_BASE_DEFAULT),
- mirrorMode(OutputConfiguration::MIRROR_MODE_AUTO),
colorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED) {}
OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
uint64_t _consumerUsage, const std::unordered_set<int32_t>& _sensorPixelModesUsed,
- int64_t _dynamicRangeProfile, int _streamUseCase, int _timestampBase, int _mirrorMode,
+ int64_t _dynamicRangeProfile, int _streamUseCase, int _timestampBase,
int32_t _colorSpace) :
width(_width), height(_height), format(_format),
dataSpace(_dataSpace), consumerUsage(_consumerUsage),
sensorPixelModesUsed(_sensorPixelModesUsed), dynamicRangeProfile(_dynamicRangeProfile),
- streamUseCase(_streamUseCase), timestampBase(_timestampBase), mirrorMode(_mirrorMode),
- colorSpace(_colorSpace) {}
+ streamUseCase(_streamUseCase), timestampBase(_timestampBase), colorSpace(_colorSpace) {}
+};
+
+// A holder containing a surface and its corresponding mirroring mode
+struct SurfaceHolder {
+ sp<Surface> mSurface;
+ int mMirrorMode = OutputConfiguration::MIRROR_MODE_AUTO;
};
// Utility class to lock and unlock a GraphicBuffer
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 7090545..a360abf 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -201,6 +201,17 @@
mUseHalBufManager = enabled;
}
+status_t Camera3StreamSplitter::setTransform(size_t surfaceId, int transform) {
+ Mutex::Autolock lock(mMutex);
+ if (!mOutputSurfaces.contains(surfaceId) || mOutputSurfaces[surfaceId] == nullptr) {
+ SP_LOGE("%s: No surface at id %zu", __FUNCTION__, surfaceId);
+ return BAD_VALUE;
+ }
+
+ mOutputTransforms[surfaceId] = transform;
+ return OK;
+}
+
status_t Camera3StreamSplitter::addOutputLocked(size_t surfaceId, const sp<Surface>& outputQueue) {
ATRACE_CALL();
if (outputQueue == nullptr) {
@@ -374,7 +385,12 @@
output->setBuffersDataSpace(static_cast<ui::Dataspace>(bufferItem.mDataSpace));
output->setCrop(&bufferItem.mCrop);
output->setScalingMode(bufferItem.mScalingMode);
- output->setBuffersTransform(bufferItem.mTransform);
+
+ int transform = bufferItem.mTransform;
+ if (mOutputTransforms.contains(surfaceId)) {
+ transform = mOutputTransforms[surfaceId];
+ }
+ output->setBuffersTransform(transform);
// In case the output BufferQueue has its own lock, if we hold splitter lock while calling
// queueBuffer (which will try to acquire the output lock), the output could be holding its
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 0440e08..6e5d8f7 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -96,6 +96,7 @@
void setHalBufferManager(bool enabled);
+ status_t setTransform(size_t surfaceId, int transform);
private:
// From BufferItemConsumer::FrameAvailableListener
//
@@ -237,6 +238,9 @@
//Map surface ids -> gbp outputs
std::unordered_map<int, sp<Surface>> mOutputSurfaces;
+ // Map surface ids -> transform
+ std::unordered_map<int, int> mOutputTransforms;
+
//Map surface ids -> consumer buffer count
std::unordered_map<int, size_t > mConsumerBufferCount;
diff --git a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp
index c1113e5..00bbde3 100644
--- a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp
@@ -189,6 +189,17 @@
mUseHalBufManager = enabled;
}
+status_t DeprecatedCamera3StreamSplitter::setTransform(size_t surfaceId, int transform) {
+ Mutex::Autolock lock(mMutex);
+ if (!mOutputs.contains(surfaceId) || mOutputs[surfaceId] == nullptr) {
+ SP_LOGE("%s: No surface at id %zu", __FUNCTION__, surfaceId);
+ return BAD_VALUE;
+ }
+
+ mOutputTransforms[surfaceId] = transform;
+ return OK;
+}
+
status_t DeprecatedCamera3StreamSplitter::addOutputLocked(size_t surfaceId,
const sp<Surface>& outputQueue) {
ATRACE_CALL();
@@ -355,9 +366,13 @@
const sp<IGraphicBufferProducer>& output, const BufferItem& bufferItem, size_t surfaceId) {
ATRACE_CALL();
status_t res;
+ int transform = bufferItem.mTransform;
+ if (mOutputTransforms.contains(surfaceId)) {
+ transform = mOutputTransforms[surfaceId];
+ }
IGraphicBufferProducer::QueueBufferInput queueInput(
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp, bufferItem.mDataSpace,
- bufferItem.mCrop, static_cast<int32_t>(bufferItem.mScalingMode), bufferItem.mTransform,
+ bufferItem.mCrop, static_cast<int32_t>(bufferItem.mScalingMode), transform,
bufferItem.mFence);
IGraphicBufferProducer::QueueBufferOutput queueOutput;
diff --git a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.h b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.h
index 4610985..61b43a8 100644
--- a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.h
@@ -95,6 +95,7 @@
void setHalBufferManager(bool enabled);
+ status_t setTransform(size_t surfaceId, int transform);
private:
// From IConsumerListener
//
@@ -259,6 +260,9 @@
// Map surface ids -> gbp outputs
std::unordered_map<int, sp<Surface>> mOutputSurfaces;
+ // Map surface ids -> transform
+ std::unordered_map<int, int> mOutputTransforms;
+
// Map surface ids -> consumer buffer count
std::unordered_map<int, size_t> mConsumerBufferCount;
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
index b213218..4b63704 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -132,26 +132,78 @@
return binder::Status::ok();
}
-bool AttributionAndPermissionUtils::checkPermissionForPreflight(
+PermissionChecker::PermissionResult AttributionAndPermissionUtils::checkPermission(
const std::string& cameraId, const std::string& permission,
const AttributionSourceState& attributionSource, const std::string& message,
- int32_t attributedOpCode) {
+ int32_t attributedOpCode, bool forDataDelivery, bool startDataDelivery,
+ bool checkAutomotive) {
AttributionSourceState clientAttribution = attributionSource;
if (!flags::check_full_attribution_source_chain() && !clientAttribution.next.empty()) {
clientAttribution.next.clear();
}
- if (checkAutomotivePrivilegedClient(cameraId, clientAttribution)) {
- return true;
+ if (checkAutomotive && checkAutomotivePrivilegedClient(cameraId, clientAttribution)) {
+ return PermissionChecker::PERMISSION_GRANTED;
}
- PermissionChecker::PermissionResult result = mPermissionChecker->checkPermissionForPreflight(
- toString16(permission), clientAttribution, toString16(message), attributedOpCode);
+ PermissionChecker::PermissionResult result;
+ if (forDataDelivery) {
+ if (startDataDelivery) {
+ result = mPermissionChecker->checkPermissionForStartDataDeliveryFromDatasource(
+ toString16(permission), clientAttribution, toString16(message),
+ attributedOpCode);
+ } else {
+ result = mPermissionChecker->checkPermissionForDataDeliveryFromDatasource(
+ toString16(permission), clientAttribution, toString16(message),
+ attributedOpCode);
+ }
+ } else {
+ result = mPermissionChecker->checkPermissionForPreflight(
+ toString16(permission), clientAttribution, toString16(message), attributedOpCode);
+ }
+
if (result == PermissionChecker::PERMISSION_HARD_DENIED) {
- ALOGE("%s: Permission denied for client attribution %s", __FUNCTION__,
+ ALOGI("%s (forDataDelivery %d startDataDelivery %d): Permission hard denied "
+ "for client attribution %s",
+ __FUNCTION__, forDataDelivery, startDataDelivery,
+ getAttributionString(clientAttribution).c_str());
+ } else if (result == PermissionChecker::PERMISSION_SOFT_DENIED) {
+ ALOGI("%s checkPermission (forDataDelivery %d startDataDelivery %d): Permission soft "
+ "denied "
+ "for client attribution %s",
+ __FUNCTION__, forDataDelivery, startDataDelivery,
getAttributionString(clientAttribution).c_str());
}
- return result != PermissionChecker::PERMISSION_HARD_DENIED;
+ return result;
+}
+
+bool AttributionAndPermissionUtils::checkPermissionForPreflight(
+ const std::string& cameraId, const std::string& permission,
+ const AttributionSourceState& attributionSource, const std::string& message,
+ int32_t attributedOpCode) {
+ return checkPermission(cameraId, permission, attributionSource, message, attributedOpCode,
+ /* forDataDelivery */ false, /* startDataDelivery */ false,
+ /* checkAutomotive */ true) != PermissionChecker::PERMISSION_HARD_DENIED;
+}
+
+bool AttributionAndPermissionUtils::checkPermissionForDataDelivery(
+ const std::string& cameraId, const std::string& permission,
+ const AttributionSourceState& attributionSource, const std::string& message,
+ int32_t attributedOpCode) {
+ return checkPermission(cameraId, permission, attributionSource, message, attributedOpCode,
+ /* forDataDelivery */ true, /* startDataDelivery */ false,
+ /* checkAutomotive */ false) !=
+ PermissionChecker::PERMISSION_HARD_DENIED;
+}
+
+PermissionChecker::PermissionResult
+AttributionAndPermissionUtils::checkPermissionForStartDataDelivery(
+ const std::string& cameraId, const std::string& permission,
+ const AttributionSourceState& attributionSource, const std::string& message,
+ int32_t attributedOpCode) {
+ return checkPermission(cameraId, permission, attributionSource, message, attributedOpCode,
+ /* forDataDelivery */ true, /* startDataDelivery */ true,
+ /* checkAutomotive */ false);
}
// Can camera service trust the caller based on the calling UID?
@@ -244,9 +296,35 @@
}
bool AttributionAndPermissionUtils::hasPermissionsForCamera(
+ const std::string& cameraId, const AttributionSourceState& attributionSource,
+ bool forDataDelivery, bool checkAutomotive) {
+ return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
+ AppOpsManager::OP_NONE, forDataDelivery, /* startDataDelivery */ false,
+ checkAutomotive) != PermissionChecker::PERMISSION_HARD_DENIED;
+}
+
+PermissionChecker::PermissionResult
+AttributionAndPermissionUtils::checkPermissionsForCameraForPreflight(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
- return checkPermissionForPreflight(cameraId, sCameraPermission, attributionSource,
- std::string(), AppOpsManager::OP_NONE);
+ return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
+ AppOpsManager::OP_NONE, /* forDataDelivery */ false,
+ /* startDataDelivery */ false, /* checkAutomotive */ false);
+}
+
+PermissionChecker::PermissionResult
+AttributionAndPermissionUtils::checkPermissionsForCameraForDataDelivery(
+ const std::string& cameraId, const AttributionSourceState& attributionSource) {
+ return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
+ AppOpsManager::OP_NONE, /* forDataDelivery */ true,
+ /* startDataDelivery */ false, /* checkAutomotive */ false);
+}
+
+PermissionChecker::PermissionResult
+AttributionAndPermissionUtils::checkPermissionsForCameraForStartDataDelivery(
+ const std::string& cameraId, const AttributionSourceState& attributionSource) {
+ return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
+ AppOpsManager::OP_NONE, /* forDataDelivery */ true,
+ /* startDataDelivery */ true, /* checkAutomotive */ false);
}
bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(
@@ -277,6 +355,12 @@
attributionSource, std::string(), AppOpsManager::OP_NONE);
}
+void AttributionAndPermissionUtils::finishDataDelivery(
+ const AttributionSourceState& attributionSource) {
+ mPermissionChecker->finishDataDeliveryFromDatasource(AppOpsManager::OP_CAMERA,
+ attributionSource);
+}
+
bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
if (isAutomotivePrivilegedClient(attributionSource.uid)) {
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
index 9ed7fa2..3361eaa 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
@@ -29,6 +29,37 @@
using content::AttributionSourceState;
using permission::PermissionChecker;
+class AttrSourceItr {
+ public:
+ using value_type = AttributionSourceState;
+ using pointer = const value_type*;
+ using reference = const value_type&;
+
+ AttrSourceItr() : mAttr(nullptr) {}
+
+ AttrSourceItr(const AttributionSourceState& attr) : mAttr(&attr) {}
+
+ reference operator*() const { return *mAttr; }
+ pointer operator->() const { return mAttr; }
+
+ AttrSourceItr& operator++() {
+ mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
+ return *this;
+ }
+
+ AttrSourceItr operator++(int) {
+ AttrSourceItr tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const AttrSourceItr& a, const AttrSourceItr& b) = default;
+
+ static AttrSourceItr end() { return AttrSourceItr{}; }
+private:
+ const AttributionSourceState * mAttr;
+};
+
/**
* Utility class consolidating methods/data for verifying permissions and the identity of the
* caller.
@@ -87,6 +118,15 @@
const std::string& permission,
const AttributionSourceState& attributionSource,
const std::string& message, int32_t attributedOpCode);
+ virtual bool checkPermissionForDataDelivery(const std::string& cameraId,
+ const std::string& permission,
+ const AttributionSourceState& attributionSource,
+ const std::string& message,
+ int32_t attributedOpCode);
+ virtual PermissionChecker::PermissionResult checkPermissionForStartDataDelivery(
+ const std::string& cameraId, const std::string& permission,
+ const AttributionSourceState& attributionSource, const std::string& message,
+ int32_t attributedOpCode);
// Can camera service trust the caller based on the calling UID?
virtual bool isTrustedCallingUid(uid_t uid);
@@ -114,7 +154,14 @@
// Utils for checking specific permissions
virtual bool hasPermissionsForCamera(const std::string& cameraId,
- const AttributionSourceState& attributionSource);
+ const AttributionSourceState& attributionSource,
+ bool forDataDelivery = false, bool checkAutomotive = true);
+ virtual PermissionChecker::PermissionResult checkPermissionsForCameraForPreflight(
+ const std::string& cameraId, const AttributionSourceState& attributionSource);
+ virtual PermissionChecker::PermissionResult checkPermissionsForCameraForDataDelivery(
+ const std::string& cameraId, const AttributionSourceState& attributionSource);
+ virtual PermissionChecker::PermissionResult checkPermissionsForCameraForStartDataDelivery(
+ const std::string& cameraId, const AttributionSourceState& attributionSource);
virtual bool hasPermissionsForSystemCamera(const std::string& cameraId,
const AttributionSourceState& attributionSource,
bool checkCameraPermissions = true);
@@ -125,6 +172,8 @@
virtual bool hasPermissionsForOpenCloseListener(
const AttributionSourceState& attributionSource);
+ virtual void finishDataDelivery(const AttributionSourceState& attributionSource);
+
static const std::string sDumpPermission;
static const std::string sManageCameraPermission;
static const std::string sCameraPermission;
@@ -156,6 +205,12 @@
private:
virtual const sp<IPermissionController>& getPermissionController() const;
+ virtual PermissionChecker::PermissionResult checkPermission(
+ const std::string& cameraId, const std::string& permission,
+ const AttributionSourceState& attributionSource, const std::string& message,
+ int32_t attributedOpCode, bool forDataDelivery, bool startDataDelivery,
+ bool checkAutomotive);
+
std::unique_ptr<permission::PermissionChecker> mPermissionChecker =
std::make_unique<permission::PermissionChecker>();
};
@@ -230,12 +285,39 @@
bool hasPermissionsForCamera(const std::string& cameraId, int callingPid, int callingUid,
int32_t deviceId) const {
auto attributionSource = buildAttributionSource(callingPid, callingUid, deviceId);
- return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
+ return hasPermissionsForCamera(cameraId, attributionSource);
}
bool hasPermissionsForCamera(const std::string& cameraId,
const AttributionSourceState& clientAttribution) const {
- return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, clientAttribution);
+ return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, clientAttribution,
+ /* forDataDelivery */ false,
+ /* checkAutomotive */ true);
+ }
+
+ bool hasPermissionsForCameraForDataDelivery(
+ const std::string& cameraId, const AttributionSourceState& clientAttribution) const {
+ return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, clientAttribution,
+ /* forDataDelivery */ true,
+ /* checkAutomotive */ false);
+ }
+
+ PermissionChecker::PermissionResult checkPermissionsForCameraForPreflight(
+ const std::string& cameraId, const AttributionSourceState& clientAttribution) const {
+ return mAttributionAndPermissionUtils->checkPermissionsForCameraForPreflight(
+ cameraId, clientAttribution);
+ }
+
+ PermissionChecker::PermissionResult checkPermissionsForCameraForDataDelivery(
+ const std::string& cameraId, const AttributionSourceState& clientAttribution) const {
+ return mAttributionAndPermissionUtils->checkPermissionsForCameraForDataDelivery(
+ cameraId, clientAttribution);
+ }
+
+ PermissionChecker::PermissionResult checkPermissionsForCameraForStartDataDelivery(
+ const std::string& cameraId, const AttributionSourceState& clientAttribution) const {
+ return mAttributionAndPermissionUtils->checkPermissionsForCameraForStartDataDelivery(
+ cameraId, clientAttribution);
}
bool hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid, int callingUid,
@@ -264,6 +346,10 @@
attributionSource);
}
+ void finishDataDelivery(const AttributionSourceState& attributionSource) {
+ mAttributionAndPermissionUtils->finishDataDelivery(attributionSource);
+ }
+
bool isAutomotiveDevice() const { return mAttributionAndPermissionUtils->isAutomotiveDevice(); }
bool isAutomotivePrivilegedClient(int32_t uid) const {
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 40ca276..d937fe9 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -602,7 +602,6 @@
streamInfo.dynamicRangeProfile = dynamicRangeProfile;
streamInfo.streamUseCase = streamUseCase;
streamInfo.timestampBase = timestampBase;
- streamInfo.mirrorMode = mirrorMode;
streamInfo.colorSpace = colorSpace;
return binder::Status::ok();
}
@@ -848,7 +847,6 @@
int64_t streamUseCase = it.getStreamUseCase();
int timestampBase = it.getTimestampBase();
- int mirrorMode = it.getMirrorMode();
// If the configuration is a deferred consumer, or a not yet completed
// configuration with no buffer producers attached.
if (deferredConsumer || (!isConfigurationComplete && numBufferProducers == 0)) {
@@ -908,6 +906,7 @@
}
for (auto& bufferProducer : bufferProducers) {
+ int mirrorMode = it.getMirrorMode(bufferProducer);
sp<Surface> surface;
res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
diff --git a/services/camera/virtualcamera/VirtualCameraCaptureResult.cc b/services/camera/virtualcamera/VirtualCameraCaptureResult.cc
index a61f553..da1c208 100644
--- a/services/camera/virtualcamera/VirtualCameraCaptureResult.cc
+++ b/services/camera/virtualcamera/VirtualCameraCaptureResult.cc
@@ -16,6 +16,7 @@
#include "VirtualCameraCaptureResult.h"
#include <cstdint>
+#include <memory>
#include "VirtualCameraCaptureRequest.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
@@ -34,7 +35,7 @@
} // namespace
-CameraMetadata createCaptureResultMetadata(
+std::unique_ptr<CameraMetadata> createCaptureResultMetadata(
const std::chrono::nanoseconds timestamp,
const RequestSettings& requestSettings,
const Resolution reportedSensorSize) {
@@ -109,9 +110,9 @@
if (metadata == nullptr) {
ALOGE("%s: Failed to build capture result metadata", __func__);
- return CameraMetadata();
+ return std::make_unique<CameraMetadata>();
}
- return std::move(*metadata);
+ return metadata;
}
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraCaptureResult.h b/services/camera/virtualcamera/VirtualCameraCaptureResult.h
index 9e5b4d7..c3978f7 100644
--- a/services/camera/virtualcamera/VirtualCameraCaptureResult.h
+++ b/services/camera/virtualcamera/VirtualCameraCaptureResult.h
@@ -18,21 +18,10 @@
#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERACAPTURERESULT_H
#include <chrono>
-#include <cstdint>
#include <cstring>
-#include <future>
#include <memory>
-#include <mutex>
-#include <thread>
-#include <utility>
-#include <vector>
-#include "Exif.h"
-#include "GLES/gl.h"
#include "VirtualCameraCaptureRequest.h"
-#include "VirtualCameraDevice.h"
-#include "VirtualCameraRenderThread.h"
-#include "VirtualCameraSessionContext.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
namespace android {
@@ -41,7 +30,7 @@
// Construct the Metadata for the Capture result based on the request
// settings, timestamp and reported sensore size
-::aidl::android::hardware::camera::device::CameraMetadata
+std::unique_ptr<::aidl::android::hardware::camera::device::CameraMetadata>
createCaptureResultMetadata(std::chrono::nanoseconds timestamp,
const RequestSettings& requestSettings,
Resolution reportedSensorSize);
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index becba90..58c6549 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -100,6 +100,9 @@
static constexpr UpdateTextureTask kUpdateTextureTask;
+// The number of nanosecond to wait for the first frame to be drawn on the input surface
+static constexpr std::chrono::nanoseconds kMaxWaitFirstFrame = 3s;
+
NotifyMsg createShutterNotifyMsg(int frameNumber,
std::chrono::nanoseconds timestamp) {
NotifyMsg msg;
@@ -110,11 +113,13 @@
return msg;
}
-NotifyMsg createBufferErrorNotifyMsg(int frameNumber, int streamId) {
+// Create a NotifyMsg for an error case. The default error is ERROR_BUFFER.
+NotifyMsg createErrorNotifyMsg(int frameNumber, int streamId,
+ ErrorCode errorCode = ErrorCode::ERROR_BUFFER) {
NotifyMsg msg;
msg.set<NotifyMsg::Tag::error>(ErrorMsg{.frameNumber = frameNumber,
.errorStreamId = streamId,
- .errorCode = ErrorCode::ERROR_BUFFER});
+ .errorCode = errorCode});
return msg;
}
@@ -421,10 +426,15 @@
}
// Calculate the maximal amount of time we can afford to wait for next frame.
+ const bool isFirstFrameDrawn = mEglSurfaceTexture->isFirstFrameDrawn();
+ ALOGV("First Frame Drawn: %s", isFirstFrameDrawn ? "Yes" : "No");
+
const std::chrono::nanoseconds maxFrameDuration =
- getMaxFrameDuration(request.getRequestSettings());
+ isFirstFrameDrawn ? getMaxFrameDuration(request.getRequestSettings())
+ : kMaxWaitFirstFrame;
const std::chrono::nanoseconds elapsedDuration =
- timestamp - lastAcquisitionTimestamp;
+ isFirstFrameDrawn ? timestamp - lastAcquisitionTimestamp : 0ns;
+
if (elapsedDuration < maxFrameDuration) {
// We can afford to wait for next frame.
// Note that if there's already new frame in the input Surface, the call
@@ -434,6 +444,17 @@
timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch());
if (!gotNewFrame) {
+ if (!mEglSurfaceTexture->isFirstFrameDrawn()) {
+ // We don't have any input ever drawn. This is considered as an error
+ // case. Notify the framework of the failure and return early.
+ ALOGW("Timed out waiting for first frame to be drawn.");
+ std::unique_ptr<CaptureResult> captureResult = createCaptureResult(
+ request.getFrameNumber(), /* metadata = */ nullptr);
+ notifyTimeout(request, *captureResult);
+ submitCaptureResult(std::move(captureResult));
+ return;
+ }
+
ALOGV(
"%s: No new frame received on input surface after waiting for "
"%" PRIu64 "ns, repeating last frame.",
@@ -457,75 +478,20 @@
captureTimestamp.count(), timestamp.count());
}
- CaptureResult captureResult;
- captureResult.fmqResultSize = 0;
- captureResult.frameNumber = request.getFrameNumber();
- // Partial result needs to be set to 1 when metadata are present.
- captureResult.partialResult = 1;
- captureResult.inputBuffer.streamId = -1;
- captureResult.physicalCameraMetadata.resize(0);
- captureResult.result = createCaptureResultMetadata(
- captureTimestamp, request.getRequestSettings(), mReportedSensorSize);
+ std::unique_ptr<CaptureResult> captureResult = createCaptureResult(
+ request.getFrameNumber(),
+ createCaptureResultMetadata(
+ captureTimestamp, request.getRequestSettings(), mReportedSensorSize));
+ renderOutputBuffers(request, *captureResult);
- const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
- captureResult.outputBuffers.resize(buffers.size());
-
- for (int i = 0; i < buffers.size(); ++i) {
- const CaptureRequestBuffer& reqBuffer = buffers[i];
- StreamBuffer& resBuffer = captureResult.outputBuffers[i];
- resBuffer.streamId = reqBuffer.getStreamId();
- resBuffer.bufferId = reqBuffer.getBufferId();
- resBuffer.status = BufferStatus::OK;
-
- const std::optional<Stream> streamConfig =
- mSessionContext.getStreamConfig(reqBuffer.getStreamId());
-
- if (!streamConfig.has_value()) {
- resBuffer.status = BufferStatus::ERROR;
- continue;
- }
-
- auto status = streamConfig->format == PixelFormat::BLOB
- ? renderIntoBlobStreamBuffer(
- reqBuffer.getStreamId(), reqBuffer.getBufferId(),
- captureResult.result, request.getRequestSettings(),
- reqBuffer.getFence())
- : renderIntoImageStreamBuffer(reqBuffer.getStreamId(),
- reqBuffer.getBufferId(),
- reqBuffer.getFence());
- if (!status.isOk()) {
- resBuffer.status = BufferStatus::ERROR;
- }
- }
-
- std::vector<NotifyMsg> notifyMsg{
- createShutterNotifyMsg(request.getFrameNumber(), captureTimestamp)};
- for (const StreamBuffer& resBuffer : captureResult.outputBuffers) {
- if (resBuffer.status != BufferStatus::OK) {
- notifyMsg.push_back(createBufferErrorNotifyMsg(request.getFrameNumber(),
- resBuffer.streamId));
- }
- }
-
- auto status = mCameraDeviceCallback->notify(notifyMsg);
+ auto status = notifyShutter(request, *captureResult, captureTimestamp);
if (!status.isOk()) {
ALOGE("%s: notify call failed: %s", __func__,
status.getDescription().c_str());
return;
}
- std::vector<::aidl::android::hardware::camera::device::CaptureResult>
- captureResults(1);
- captureResults[0] = std::move(captureResult);
-
- status = mCameraDeviceCallback->processCaptureResult(captureResults);
- if (!status.isOk()) {
- ALOGE("%s: processCaptureResult call failed: %s", __func__,
- status.getDescription().c_str());
- return;
- }
-
- ALOGV("%s: Successfully called processCaptureResult", __func__);
+ submitCaptureResult(std::move(captureResult));
}
std::chrono::nanoseconds VirtualCameraRenderThread::throttleRendering(
@@ -558,22 +524,124 @@
std::chrono::nanoseconds timeSinceLastFrame) {
std::chrono::nanoseconds surfaceTimestamp = mEglSurfaceTexture->getTimestamp();
uint64_t lastSurfaceTimestamp = mLastSurfaceTimestampNanoseconds.load();
- if (surfaceTimestamp.count() < 0 ||
- surfaceTimestamp.count() == lastSurfaceTimestamp) {
- if (lastSurfaceTimestamp > 0) {
- // The timestamps were provided by the producer but we are
- // repeating the last frame, so we increase the previous timestamp by
- // the elapsed time sinced its capture, otherwise the camera framework
- // will discard the frame.
- surfaceTimestamp = std::chrono::nanoseconds(lastSurfaceTimestamp +
- timeSinceLastFrame.count());
- }
+ if (lastSurfaceTimestamp > 0 &&
+ surfaceTimestamp.count() <= lastSurfaceTimestamp) {
+ // The timestamps were provided by the producer but we are
+ // repeating the last frame, so we increase the previous timestamp by
+ // the elapsed time sinced its capture, otherwise the camera framework
+ // will discard the frame.
+ surfaceTimestamp = std::chrono::nanoseconds(lastSurfaceTimestamp +
+ timeSinceLastFrame.count());
+ ALOGI(
+ "Surface's timestamp is stall. Artificially increasing the surface "
+ "timestamp by %lld",
+ timeSinceLastFrame.count());
}
mLastSurfaceTimestampNanoseconds.store(surfaceTimestamp.count(),
std::memory_order_relaxed);
return surfaceTimestamp;
}
+std::unique_ptr<CaptureResult> VirtualCameraRenderThread::createCaptureResult(
+ int frameNumber, std::unique_ptr<CameraMetadata> metadata) {
+ std::unique_ptr<CaptureResult> captureResult =
+ std::make_unique<CaptureResult>();
+ captureResult->fmqResultSize = 0;
+ captureResult->frameNumber = frameNumber;
+ // Partial result needs to be set to 1 when metadata are present.
+ captureResult->partialResult = 1;
+ captureResult->inputBuffer.streamId = -1;
+ captureResult->physicalCameraMetadata.resize(0);
+ captureResult->result = metadata != nullptr ? *metadata : CameraMetadata();
+ return captureResult;
+}
+
+void VirtualCameraRenderThread::renderOutputBuffers(
+ const ProcessCaptureRequestTask& request, CaptureResult& captureResult) {
+ const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
+ captureResult.outputBuffers.resize(buffers.size());
+
+ for (int i = 0; i < buffers.size(); ++i) {
+ const CaptureRequestBuffer& reqBuffer = buffers[i];
+ StreamBuffer& resBuffer = captureResult.outputBuffers[i];
+ resBuffer.streamId = reqBuffer.getStreamId();
+ resBuffer.bufferId = reqBuffer.getBufferId();
+ resBuffer.status = BufferStatus::OK;
+
+ const std::optional<Stream> streamConfig =
+ mSessionContext.getStreamConfig(reqBuffer.getStreamId());
+
+ if (!streamConfig.has_value()) {
+ resBuffer.status = BufferStatus::ERROR;
+ continue;
+ }
+
+ auto status = streamConfig->format == PixelFormat::BLOB
+ ? renderIntoBlobStreamBuffer(
+ reqBuffer.getStreamId(), reqBuffer.getBufferId(),
+ captureResult.result, request.getRequestSettings(),
+ reqBuffer.getFence())
+ : renderIntoImageStreamBuffer(reqBuffer.getStreamId(),
+ reqBuffer.getBufferId(),
+ reqBuffer.getFence());
+ if (!status.isOk()) {
+ resBuffer.status = BufferStatus::ERROR;
+ }
+ }
+}
+
+::ndk::ScopedAStatus VirtualCameraRenderThread::notifyTimeout(
+ const ProcessCaptureRequestTask& request, CaptureResult& captureResult) {
+ const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
+ captureResult.outputBuffers.resize(buffers.size());
+
+ std::vector<NotifyMsg> notifyMsgs;
+
+ for (int i = 0; i < buffers.size(); ++i) {
+ const CaptureRequestBuffer& reqBuffer = buffers[i];
+ StreamBuffer& resBuffer = captureResult.outputBuffers[i];
+ resBuffer.streamId = reqBuffer.getStreamId();
+ resBuffer.bufferId = reqBuffer.getBufferId();
+ resBuffer.status = BufferStatus::ERROR;
+ notifyMsgs.push_back(createErrorNotifyMsg(
+ request.getFrameNumber(), resBuffer.streamId, ErrorCode::ERROR_REQUEST));
+ }
+ return mCameraDeviceCallback->notify(notifyMsgs);
+}
+
+::ndk::ScopedAStatus VirtualCameraRenderThread::notifyShutter(
+ const ProcessCaptureRequestTask& request, const CaptureResult& captureResult,
+ std::chrono::nanoseconds captureTimestamp) {
+ std::vector<NotifyMsg> notifyMsgs{
+ createShutterNotifyMsg(request.getFrameNumber(), captureTimestamp)};
+ for (const StreamBuffer& resBuffer : captureResult.outputBuffers) {
+ if (resBuffer.status != BufferStatus::OK) {
+ notifyMsgs.push_back(
+ createErrorNotifyMsg(request.getFrameNumber(), resBuffer.streamId));
+ }
+ }
+
+ return mCameraDeviceCallback->notify(notifyMsgs);
+}
+
+::ndk::ScopedAStatus VirtualCameraRenderThread::submitCaptureResult(
+ std::unique_ptr<CaptureResult> captureResult) {
+ std::vector<::aidl::android::hardware::camera::device::CaptureResult>
+ captureResults;
+ captureResults.push_back(std::move(*captureResult));
+
+ ::ndk::ScopedAStatus status =
+ mCameraDeviceCallback->processCaptureResult(captureResults);
+ if (!status.isOk()) {
+ ALOGE("%s: processCaptureResult call failed: %s", __func__,
+ status.getDescription().c_str());
+ return status;
+ }
+
+ ALOGV("%s: Successfully called processCaptureResult", __func__);
+ return status;
+}
+
void VirtualCameraRenderThread::flushCaptureRequest(
const ProcessCaptureRequestTask& request) {
CaptureResult captureResult;
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index 1fb4e84..4cad39e 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -19,6 +19,7 @@
#include <atomic>
#include <chrono>
+#include <cstddef>
#include <cstdint>
#include <deque>
#include <future>
@@ -205,6 +206,35 @@
std::chrono::nanoseconds getSurfaceTimestamp(
std::chrono::nanoseconds timeSinceLastFrame);
+ // Build a default capture result object populating the metadata from the request.
+ std::unique_ptr<::aidl::android::hardware::camera::device::CaptureResult>
+ createCaptureResult(
+ int frameNumber,
+ std::unique_ptr<aidl::android::hardware::camera::device::CameraMetadata>
+ metadata);
+
+ // Renders the images from the input surface into the request's buffers.
+ void renderOutputBuffers(
+ const ProcessCaptureRequestTask& request,
+ ::aidl::android::hardware::camera::device::CaptureResult& captureResult);
+
+ // Notify a shutter event for all the buffers in this request.
+ ::ndk::ScopedAStatus notifyShutter(
+ const ProcessCaptureRequestTask& request,
+ const ::aidl::android::hardware::camera::device::CaptureResult& captureResult,
+ std::chrono::nanoseconds captureTimestamp);
+
+ // Notify a timeout error for this request. The capture result still needs to
+ // be submitted after this call.
+ ::ndk::ScopedAStatus notifyTimeout(
+ const ProcessCaptureRequestTask& request,
+ ::aidl::android::hardware::camera::device::CaptureResult& captureResult);
+
+ // Submit the capture result to the camera callback.
+ ::ndk::ScopedAStatus submitCaptureResult(
+ std::unique_ptr<::aidl::android::hardware::camera::device::CaptureResult>
+ captureResult);
+
// Camera callback
const std::shared_ptr<
::aidl::android::hardware::camera::device::ICameraDeviceCallback>
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index de09a62..67225c9 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -395,7 +395,7 @@
status = enableTestCameraCmd(out, err, cmd.optionToValueMap);
break;
case Command::DISABLE_TEST_CAMERA:
- disableTestCameraCmd(out);
+ status = disableTestCameraCmd(out);
break;
}
@@ -490,21 +490,23 @@
mTestCameraToken, configuration,
cameraId.value_or(std::to_string(sNextIdNumericalPortion++)),
kDefaultDeviceId, &ret);
- if (ret) {
- dprintf(out, "Successfully registered test camera %s\n",
- getCamera(mTestCameraToken)->getCameraName().c_str());
- } else {
- dprintf(err, "Failed to create test camera\n");
+ if (!ret) {
+ dprintf(err, "Failed to create test camera (error %d)\n", ret);
+ return ret;
}
+
+ dprintf(out, "Successfully registered test camera %s\n",
+ getCamera(mTestCameraToken)->getCameraName().c_str());
return STATUS_OK;
}
-void VirtualCameraService::disableTestCameraCmd(const int out) {
+binder_status_t VirtualCameraService::disableTestCameraCmd(const int out) {
if (mTestCameraToken == nullptr) {
dprintf(out, "Test camera is not registered.");
}
- unregisterCamera(mTestCameraToken);
+ binder_status_t ret = unregisterCamera(mTestCameraToken).getStatus();
mTestCameraToken.set(nullptr);
+ return ret;
}
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraService.h b/services/camera/virtualcamera/VirtualCameraService.h
index 3be5c3e..defa75b 100644
--- a/services/camera/virtualcamera/VirtualCameraService.h
+++ b/services/camera/virtualcamera/VirtualCameraService.h
@@ -85,7 +85,7 @@
binder_status_t enableTestCameraCmd(
int out, int err, const std::map<std::string, std::string>& options);
// Disable and destroy test camera instance if there's one.
- void disableTestCameraCmd(int out);
+ binder_status_t disableTestCameraCmd(int out);
// Register camera corresponding to the binder token without checking for
// caller permission.
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index be36ec4..fc469a0 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -105,6 +105,10 @@
return std::chrono::nanoseconds(mGlConsumer->getTimestamp());
}
+bool EglSurfaceTexture::isFirstFrameDrawn() {
+ return mGlConsumer->getFrameNumber() > 0;
+}
+
GLuint EglSurfaceTexture::updateTexture() {
int previousFrameId;
int framesAdvance = 0;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index c1f1169..9f75315 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -86,6 +86,9 @@
// set by the most recent call to updateTexture.
std::chrono::nanoseconds getTimestamp();
+ // Returns true is a frame has ever been drawn on this surface.
+ bool isFirstFrameDrawn();
+
private:
#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
sp<IGraphicBufferProducer> mBufferProducer;