Merge "cameraserver: rename getConcurrentStreamingCameraIds -> getConcurrentCameraIds." into rvc-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index 140a2e8..259558c 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -14,6 +14,7 @@
apex_defaults {
name: "com.android.media-defaults",
+ updatable: true,
java_libs: ["updatable-media"],
multilib: {
first: {
@@ -43,7 +44,7 @@
// Use a custom AndroidManifest.xml used for API targeting.
androidManifest: ":com.android.media-androidManifest",
-
+ min_sdk_version: "29",
legacy_android10_support: true,
}
@@ -65,6 +66,7 @@
apex_defaults {
name: "com.android.media.swcodec-defaults",
+ updatable: true,
binaries: [
"mediaswcodec",
],
@@ -82,7 +84,7 @@
// Use a custom AndroidManifest.xml used for API targeting.
androidManifest: ":com.android.media.swcodec-androidManifest",
-
+ min_sdk_version: "29",
legacy_android10_support: true,
}
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index 81657fd..c54813c 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -89,4 +89,12 @@
* can retry after receiving this callback.
*/
oneway void onCameraAccessPrioritiesChanged();
+
+ /**
+ * Notify registered clients about cameras being opened/closed.
+ * Only clients with android.permission.CAMERA_OPEN_CLOSE_LISTENER permission
+ * will receive such callbacks.
+ */
+ oneway void onCameraOpened(String cameraId, String clientPackageId);
+ oneway void onCameraClosed(String cameraId);
}
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 836e037..7fba188 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -97,6 +97,12 @@
}
virtual binder::Status onCameraAccessPrioritiesChanged();
+ virtual binder::Status onCameraOpened(const String16&, const String16&) {
+ return binder::Status::ok();
+ }
+ virtual binder::Status onCameraClosed(const String16&) {
+ return binder::Status::ok();
+ }
private:
const wp<CameraManagerGlobal> mCameraManager;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index a95fe2a..e2097b5 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -735,9 +735,8 @@
if (!serviceRet.isOk() || status != Status::NO_ERROR) {
ALOGE("%s: connect camera device failed", __FUNCTION__);
- // TODO: Convert serviceRet to camera_status_t
delete device;
- return ACAMERA_ERROR_UNKNOWN;
+ return utils::convertFromHidl(status);
}
if (deviceRemote == nullptr) {
ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 571cf59..8ccded2 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -101,6 +101,17 @@
return binder::Status::ok();
}
+ virtual binder::Status onCameraOpened(const String16& /*cameraId*/,
+ const String16& /*clientPackageName*/) {
+ // No op
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCameraClosed(const String16& /*cameraId*/) {
+ // No op
+ return binder::Status::ok();
+ }
+
bool waitForNumCameras(size_t num) const {
Mutex::Autolock l(mLock);
diff --git a/media/codec2/OWNERS b/media/codec2/OWNERS
new file mode 100644
index 0000000..46a9fca
--- /dev/null
+++ b/media/codec2/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+wonsik@google.com
+lajos@google.com
+pawin@google.com
+taklee@google.com
diff --git a/media/codec2/components/vorbis/Android.bp b/media/codec2/components/vorbis/Android.bp
index a5f485d..bc1c380 100644
--- a/media/codec2/components/vorbis/Android.bp
+++ b/media/codec2/components/vorbis/Android.bp
@@ -7,5 +7,5 @@
srcs: ["C2SoftVorbisDec.cpp"],
- shared_libs: ["libvorbisidec"],
+ static_libs: ["libvorbisidec"],
}
diff --git a/media/codec2/core/OWNERS b/media/codec2/core/OWNERS
new file mode 100644
index 0000000..31ecca5
--- /dev/null
+++ b/media/codec2/core/OWNERS
@@ -0,0 +1,2 @@
+set noparent
+lajos@google.com
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 74fdc8b..9fc0e17 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -59,7 +59,6 @@
enum drc_compression_mode_t : int32_t; ///< DRC compression mode
enum drc_effect_type_t : int32_t; ///< DRC effect type
enum drc_album_mode_t : int32_t; ///< DRC album mode
- enum drc_output_loudness : int32_t; ///< DRC output loudness
enum intra_refresh_mode_t : uint32_t; ///< intra refresh modes
enum level_t : uint32_t; ///< coding level
enum ordinal_key_t : uint32_t; ///< work ordering keys
@@ -248,7 +247,7 @@
kParamIndexSurfaceAllocator, // u32
- // low latency mode for decoders
+ // low latency mode
kParamIndexLowLatencyMode, // bool
};
@@ -812,9 +811,10 @@
constexpr char C2_PARAMKEY_PIPELINE_DELAY[] = "algo.delay";
/**
- * Enable/disable low latency decoding mode.
- * If true, low latency decoding mode is enabled, and the decoder doesn't hold input and output
- * data more than required by the codec standards.
+ * Enable/disable low latency mode.
+ * If true, low latency is preferred over low power. Disable power optimizations that
+ * may result in increased latency. For decoders, this means that the decoder does not
+ * hold input and output data more than required by the codec standards.
*/
typedef C2GlobalParam<C2Tuning, C2EasyBoolValue, kParamIndexLowLatencyMode>
C2GlobalLowLatencyModeTuning;
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 9656eb4..20f4665 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -71,7 +71,8 @@
mDisableTest = false;
ALOGV("Codec2AudioDecHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index 01baf7e..ab6bfb2 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -65,7 +65,8 @@
mDisableTest = false;
ALOGV("Codec2AudioEncHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 9404aa8..256603c 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -78,7 +78,8 @@
mDisableTest = false;
ALOGV("Codec2VideoDecHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index c1f5a92..15f6acd 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -64,7 +64,8 @@
mDisableTest = false;
ALOGV("Codec2VideoEncHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 199a99c..0acab49 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -93,6 +93,69 @@
return i;
}
+class Client2Store : public C2ComponentStore {
+ std::shared_ptr<Codec2Client> mClient;
+
+public:
+ Client2Store(std::shared_ptr<Codec2Client> const& client)
+ : mClient(client) { }
+
+ virtual ~Client2Store() = default;
+
+ virtual c2_status_t config_sm(
+ std::vector<C2Param*> const ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ return mClient->config(params, C2_MAY_BLOCK, failures);
+ };
+
+ virtual c2_status_t copyBuffer(
+ std::shared_ptr<C2GraphicBuffer>,
+ std::shared_ptr<C2GraphicBuffer>) {
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createComponent(
+ C2String, std::shared_ptr<C2Component>* const component) {
+ component->reset();
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createInterface(
+ C2String, std::shared_ptr<C2ComponentInterface>* const interface) {
+ interface->reset();
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t query_sm(
+ std::vector<C2Param*> const& stackParams,
+ std::vector<C2Param::Index> const& heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+ return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
+ }
+
+ virtual c2_status_t querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
+ return mClient->querySupportedParams(params);
+ }
+
+ virtual c2_status_t querySupportedValues_sm(
+ std::vector<C2FieldSupportedValuesQuery>& fields) const {
+ return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
+ }
+
+ virtual C2String getName() const {
+ return mClient->getName();
+ }
+
+ virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
+ return mClient->getParamReflector();
+ }
+
+ virtual std::vector<std::shared_ptr<C2Component::Traits const>> listComponents() {
+ return std::vector<std::shared_ptr<C2Component::Traits const>>();
+ }
+};
+
} // unnamed namespace
// This class caches a Codec2Client object and its component traits. The client
@@ -615,8 +678,13 @@
<< ") -- transaction failed.";
return C2_TRANSACTION_FAILED;
} else if (status != C2_OK) {
- LOG(ERROR) << "createComponent(" << name.c_str()
- << ") -- call failed: " << status << ".";
+ if (status == C2_NOT_FOUND) {
+ LOG(VERBOSE) << "createComponent(" << name.c_str()
+ << ") -- component not found.";
+ } else {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- call failed: " << status << ".";
+ }
return status;
} else if (!*component) {
LOG(ERROR) << "createComponent(" << name.c_str()
@@ -655,8 +723,13 @@
<< ") -- transaction failed.";
return C2_TRANSACTION_FAILED;
} else if (status != C2_OK) {
- LOG(ERROR) << "createComponent(" << name.c_str()
- << ") -- call failed: " << status << ".";
+ if (status == C2_NOT_FOUND) {
+ LOG(VERBOSE) << "createInterface(" << name.c_str()
+ << ") -- component not found.";
+ } else {
+ LOG(ERROR) << "createInterface(" << name.c_str()
+ << ") -- call failed: " << status << ".";
+ }
return status;
}
@@ -850,10 +923,24 @@
}
std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
- const char* name) {
+ const char* name,
+ bool setAsPreferredCodec2ComponentStore) {
size_t index = getServiceIndex(name);
- return index == GetServiceNames().size() ?
- nullptr : _CreateFromIndex(index);
+ if (index == GetServiceNames().size()) {
+ if (setAsPreferredCodec2ComponentStore) {
+ LOG(WARNING) << "CreateFromService(" << name
+ << ") -- preferred C2ComponentStore not set.";
+ }
+ return nullptr;
+ }
+ std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
+ if (setAsPreferredCodec2ComponentStore) {
+ SetPreferredCodec2ComponentStore(
+ std::make_shared<Client2Store>(client));
+ LOG(INFO) << "CreateFromService(" << name
+ << ") -- service set as preferred C2ComponentStore.";
+ }
+ return client;
}
std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
@@ -869,11 +956,11 @@
std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
std::string const& name = GetServiceNames()[index];
- LOG(INFO) << "Creating a Codec2 client to service \"" << name << "\"";
+ LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
sp<Base> baseStore = Base::getService(name);
CHECK(baseStore) << "Codec2 service \"" << name << "\""
" inaccessible for unknown reasons.";
- LOG(INFO) << "Client to Codec2 service \"" << name << "\" created";
+ LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
return std::make_shared<Codec2Client>(baseStore, index);
}
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 649dffd..ffd194a 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -184,8 +184,15 @@
// Note: A software service will have "_software" as a suffix.
static std::vector<std::string> const& GetServiceNames();
- // Create a service with a given service name.
- static std::shared_ptr<Codec2Client> CreateFromService(char const* name);
+ // Create a client to a service with a given name.
+ //
+ // After a client to the service is successfully created, if
+ // setAsPreferredCodec2ComponentStore is true, the component store that the
+ // service hosts will be set as the preferred C2ComponentStore for this
+ // process. (See SetPreferredCodec2ComponentStore() for more information.)
+ static std::shared_ptr<Codec2Client> CreateFromService(
+ char const* name,
+ bool setAsPreferredCodec2ComponentStore = false);
// Get clients to all services.
static std::vector<std::shared_ptr<Codec2Client>> CreateFromAllServices();
diff --git a/media/codec2/hidl/services/Android.bp b/media/codec2/hidl/services/Android.bp
index 46bea2e..a16b106 100644
--- a/media/codec2/hidl/services/Android.bp
+++ b/media/codec2/hidl/services/Android.bp
@@ -47,6 +47,11 @@
"libbinder",
],
required: ["android.hardware.media.c2@1.1-default-seccomp_policy"],
+
+ // The content in manifest_media_c2_V1_1_default.xml can be included
+ // directly in the main device manifest.xml file or via vintf_fragments.
+ // (Remove the line below if the entry is already in the main manifest.)
+ vintf_fragments: ["manifest_media_c2_V1_1_default.xml"],
}
// seccomp policy file.
diff --git a/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml b/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml
new file mode 100644
index 0000000..e97c3ce
--- /dev/null
+++ b/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal>
+ <name>android.hardware.media.c2</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IComponentStore</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml b/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml
new file mode 100644
index 0000000..bf0d72f
--- /dev/null
+++ b/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal>
+ <name>android.hardware.media.c2</name>
+ <transport>hwbinder</transport>
+ <version>1.1</version>
+ <interface>
+ <name>IComponentStore</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index 78d221e..c7588e9 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -62,7 +62,7 @@
android::base::unique_fd &&fd0,
android::base::unique_fd &&fd1) {
Mutexed<Jobs>::Locked jobs(mJobs);
- auto it = jobs->queues.try_emplace(comp, comp, systemTime()).first;
+ auto it = jobs->queues.try_emplace(comp, comp).first;
it->second.workList.emplace_back(
std::move(work), fenceFd, std::move(fd0), std::move(fd1));
jobs->cond.broadcast();
@@ -79,7 +79,8 @@
for (auto it = jobs->queues.begin(); it != jobs->queues.end(); ) {
Queue &queue = it->second;
if (queue.workList.empty()
- || nowNs - queue.lastQueuedTimestampNs < kIntervalNs) {
+ || (queue.lastQueuedTimestampNs != 0 &&
+ nowNs - queue.lastQueuedTimestampNs < kIntervalNs)) {
++it;
continue;
}
@@ -104,6 +105,7 @@
sp<Fence> fence(new Fence(fenceFd));
fence->waitForever(LOG_TAG);
}
+ queue.lastQueuedTimestampNs = nowNs;
comp->queue(&items);
for (android::base::unique_fd &ufd : uniqueFds) {
(void)ufd.release();
@@ -143,8 +145,8 @@
android::base::unique_fd fd1;
};
struct Queue {
- Queue(const std::shared_ptr<Codec2Client::Component> &comp, nsecs_t timestamp)
- : component(comp), lastQueuedTimestampNs(timestamp) {}
+ Queue(const std::shared_ptr<Codec2Client::Component> &comp)
+ : component(comp), lastQueuedTimestampNs(0) {}
Queue(const Queue &) = delete;
Queue &operator =(const Queue &) = delete;
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 0d093da..cc132de 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1320,7 +1320,8 @@
Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
const std::unique_ptr<Config> &config = *configLocked;
inputFormat = config->mInputFormat;
- outputFormat = config->mOutputFormat;
+ // start triggers format dup
+ outputFormat = config->mOutputFormat = config->mOutputFormat->dup();
if (config->mInputSurface) {
err2 = config->mInputSurface->start();
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index b869bd9..6b389d5 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -604,7 +604,12 @@
ssize_t result = -1;
ssize_t codecDataOffset = 0;
- if (mCrypto != nullptr) {
+ if (numSubSamples == 1
+ && subSamples[0].mNumBytesOfClearData == 0
+ && subSamples[0].mNumBytesOfEncryptedData == 0) {
+ // We don't need to go through crypto or descrambler if the input is empty.
+ result = 0;
+ } else if (mCrypto != nullptr) {
hardware::drm::V1_0::DestinationBuffer destination;
if (secure) {
destination.type = DrmBufferType::NATIVE_HANDLE;
@@ -620,6 +625,7 @@
key, iv, mode, pattern, source, buffer->offset(),
subSamples, numSubSamples, destination, errorDetailMsg);
if (result < 0) {
+ ALOGI("[%s] decrypt failed: result=%zd", mName, result);
return result;
}
if (destination.type == DrmBufferType::SHARED_MEMORY) {
@@ -1251,7 +1257,7 @@
} else {
output->buffers.reset(new LinearOutputBuffers(mName));
}
- output->buffers->setFormat(outputFormat->dup());
+ output->buffers->setFormat(outputFormat);
// Try to set output surface to created block pool if given.
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 51d6ffa..f3e37e0 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -95,6 +95,10 @@
name: "libcodec2-internal-defaults",
defaults: ["libcodec2-impl-defaults"],
+ header_libs: [
+ "libcodec2_internal",
+ ],
+
shared_libs: [
"libcutils", // for properties
],
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 5d00d94..8f60f6b 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -181,6 +181,8 @@
}
AACExtractor::~AACExtractor() {
+ mOffsetVector.clear();
+ delete mDataSource;
if (mMeta != nullptr) {
AMediaFormat_delete(mMeta);
}
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index ca721df..bdb724b 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -13,6 +13,9 @@
"libsonivox",
"libstagefright_foundation",
"libwatchdog",
+ ],
+
+ shared_libs: [
"libbase",
- ]
+ ],
}
diff --git a/media/extractors/mp4/AC4Parser.cpp b/media/extractors/mp4/AC4Parser.cpp
index 13d60c8..25fc4cd 100644
--- a/media/extractors/mp4/AC4Parser.cpp
+++ b/media/extractors/mp4/AC4Parser.cpp
@@ -600,6 +600,10 @@
if (ac4_dsi_version == 1) {
uint64_t end = (mDSISize - mBitReader.numBitsLeft()) / 8;
uint64_t presentation_bytes = end - start;
+ if (pres_bytes < presentation_bytes) {
+ ALOGE("pres_bytes is smaller than presentation_bytes.");
+ return false;
+ }
uint64_t skip_bytes = pres_bytes - presentation_bytes;
ALOGV("skipping = %" PRIu64 " bytes", skip_bytes);
CHECK_BITS_LEFT(skip_bytes * 8);
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index d7c4b5c..bc8632c 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -10,6 +10,7 @@
],
shared_libs: [
+ "libbase",
"libcgrouprc#29",
"libvndksupport#29",
],
@@ -28,7 +29,6 @@
"android.hidl.memory@1.0",
"android.hidl.token@1.0",
"android.hidl.token@1.0-utils",
- "libbase",
"libcutils",
"libhidlbase",
"libhidlmemory",
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 3638d2c..65afc8d 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -51,6 +51,7 @@
// AIDL files for audioclient interfaces
// The headers for these interfaces will be available to any modules that
// include libaudioclient, at the path "aidl/package/path/BnFoo.h"
+ ":libaudioclient_aidl_callback",
":libaudioclient_aidl_private",
":libaudioclient_aidl",
@@ -138,3 +139,12 @@
],
path: "aidl",
}
+
+// AIDL interface for audio track callback
+filegroup {
+ name: "libaudioclient_aidl_callback",
+ srcs: [
+ "aidl/android/media/IAudioTrackCallback.aidl",
+ ],
+ path: "aidl",
+}
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 2f67a18..f030ab0 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -792,6 +792,13 @@
// ---------------------------------------------------------------------------
+void AudioSystem::onNewAudioModulesAvailable()
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return;
+ aps->onNewAudioModulesAvailable();
+}
+
status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index d5690fb..2f95886 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -217,7 +217,8 @@
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
+ mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
mAttributes.usage = AUDIO_USAGE_UNKNOWN;
@@ -248,7 +249,8 @@
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
- mPausedPosition(0)
+ mPausedPosition(0),
+ mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -281,7 +283,8 @@
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
- mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+ mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -1527,6 +1530,7 @@
input.notificationFrameCount = mNotificationFramesReq;
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
+ input.audioTrackCallback = mAudioTrackCallback;
IAudioFlinger::CreateTrackOutput output;
@@ -3376,4 +3380,23 @@
mPausedNs = ns;
}
+binder::Status AudioTrack::AudioTrackCallback::onCodecFormatChanged(
+ const std::vector<uint8_t>& audioMetadata)
+{
+ AutoMutex _l(mAudioTrackCbLock);
+ sp<media::IAudioTrackCallback> callback = mCallback.promote();
+ if (callback.get() != nullptr) {
+ callback->onCodecFormatChanged(audioMetadata);
+ } else {
+ mCallback.clear();
+ }
+ return binder::Status::ok();
+}
+
+void AudioTrack::AudioTrackCallback::setAudioTrackCallback(
+ const sp<media::IAudioTrackCallback> &callback) {
+ AutoMutex lock(mAudioTrackCbLock);
+ mCallback = callback;
+}
+
} // namespace android
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index cccb131..f1213a3 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -113,6 +113,7 @@
REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
GET_DEVICES_FOR_ATTRIBUTES,
+ AUDIO_MODULES_UPDATED, // oneway
};
#define MAX_ITEMS_PER_LIST 1024
@@ -1451,6 +1452,13 @@
}
return NO_ERROR;
}
+
+ virtual void onNewAudioModulesAvailable()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ remote()->transact(AUDIO_MODULES_UPDATED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1522,7 +1530,8 @@
case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
case GET_DEVICES_FOR_ATTRIBUTES:
- case SET_ALLOWED_CAPTURE_POLICY: {
+ case SET_ALLOWED_CAPTURE_POLICY:
+ case AUDIO_MODULES_UPDATED: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
@@ -2672,6 +2681,12 @@
return NO_ERROR;
}
+ case AUDIO_MODULES_UPDATED: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ onNewAudioModulesAvailable();
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
new file mode 100644
index 0000000..21553b5
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * @hide
+ */
+interface IAudioTrackCallback {
+ oneway void onCodecFormatChanged(in byte[] audioMetadata);
+}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 07a2292..aebc875 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -221,6 +221,7 @@
//
// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
//
+ static void onNewAudioModulesAvailable();
static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state,
const char *device_address, const char *device_name,
audio_format_t encodedFormat);
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 95cad0a..4adaaea 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -26,6 +26,9 @@
#include <media/Modulo.h>
#include <utils/threads.h>
+#include "android/media/BnAudioTrackCallback.h"
+#include "android/media/IAudioTrackCallback.h"
+
namespace android {
// ----------------------------------------------------------------------------
@@ -885,8 +888,6 @@
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId);
-
-
/* Obtain the pending duration in milliseconds for playback of pure PCM
* (mixable without embedded timing) data remaining in AudioTrack.
*
@@ -933,6 +934,10 @@
*/
audio_port_handle_t getPortId() const { return mPortId; };
+ void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback) {
+ mAudioTrackCallback->setAudioTrackCallback(callback);
+ }
+
protected:
/* copying audio tracks is not allowed */
AudioTrack(const AudioTrack& other);
@@ -1254,6 +1259,18 @@
};
MediaMetrics mMediaMetrics;
std::string mMetricsId; // GUARDED_BY(mLock), could change in createTrack_l().
+
+private:
+ class AudioTrackCallback : public media::BnAudioTrackCallback {
+ public:
+ binder::Status onCodecFormatChanged(const std::vector<uint8_t>& audioMetadata) override;
+
+ void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback);
+ private:
+ Mutex mAudioTrackCbLock;
+ wp<media::IAudioTrackCallback> mCallback;
+ };
+ sp<AudioTrackCallback> mAudioTrackCallback;
};
}; // namespace android
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 8658cfa..f4ce5d7 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -40,6 +40,7 @@
#include <vector>
#include "android/media/IAudioRecord.h"
+#include "android/media/IAudioTrackCallback.h"
namespace android {
@@ -83,6 +84,8 @@
}
notificationsPerBuffer = parcel->readInt32();
speed = parcel->readFloat();
+ audioTrackCallback = interface_cast<media::IAudioTrackCallback>(
+ parcel->readStrongBinder());
/* input/output arguments*/
(void)parcel->read(&flags, sizeof(audio_output_flags_t));
@@ -107,6 +110,7 @@
}
(void)parcel->writeInt32(notificationsPerBuffer);
(void)parcel->writeFloat(speed);
+ (void)parcel->writeStrongBinder(IInterface::asBinder(audioTrackCallback));
/* input/output arguments*/
(void)parcel->write(&flags, sizeof(audio_output_flags_t));
@@ -125,6 +129,7 @@
sp<IMemory> sharedBuffer;
uint32_t notificationsPerBuffer;
float speed;
+ sp<media::IAudioTrackCallback> audioTrackCallback;
/* input/output */
audio_output_flags_t flags;
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 779ca43..ec3461e 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -42,6 +42,7 @@
//
// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
//
+ virtual void onNewAudioModulesAvailable() = 0;
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index e6e9688..1c0eacb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -15,12 +15,13 @@
*/
#include <string.h>
-#include <vector>
+#include <set>
#define LOG_TAG "DevicesFactoryHalHidl"
//#define LOG_NDEBUG 0
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.0/IServiceNotification.h>
#include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
#include <media/audiohal/hidl/HalDeathHandler.h>
#include <utils/Log.h>
@@ -29,33 +30,57 @@
#include "DeviceHalHidl.h"
#include "DevicesFactoryHalHidl.h"
-#include <set>
-
using ::android::hardware::audio::CPP_VERSION::IDevice;
using ::android::hardware::audio::CPP_VERSION::Result;
using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
namespace android {
namespace CPP_VERSION {
-DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
- ALOG_ASSERT(devicesFactory != nullptr, "Provided IDevicesFactory service is NULL");
+class ServiceNotificationListener : public IServiceNotification {
+ public:
+ explicit ServiceNotificationListener(sp<DevicesFactoryHalHidl> factory)
+ : mFactory(factory) {}
- mDeviceFactories.push_back(devicesFactory);
- if (MAJOR_VERSION >= 4) {
- // The MSD factory is optional and only available starting at HAL 4.0
- sp<IDevicesFactory> msdFactory{IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD)};
- if (msdFactory) {
- mDeviceFactories.push_back(msdFactory);
+ Return<void> onRegistration(const hidl_string& /*fully_qualified_name*/,
+ const hidl_string& instance_name,
+ bool /*pre_existing*/) override {
+ if (static_cast<std::string>(instance_name) == "default") return Void();
+ sp<DevicesFactoryHalHidl> factory = mFactory.promote();
+ if (!factory) return Void();
+ sp<IDevicesFactory> halFactory = IDevicesFactory::getService(instance_name);
+ if (halFactory) {
+ factory->addDeviceFactory(halFactory, true /*needToNotify*/);
}
+ return Void();
}
- for (const auto& factory : mDeviceFactories) {
- // It is assumed that the DevicesFactoryHalInterface instance is owned
- // by AudioFlinger and thus have the same lifespan.
- factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
- }
+
+ private:
+ wp<DevicesFactoryHalHidl> mFactory;
+};
+
+DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
+ ALOG_ASSERT(devicesFactory != nullptr, "Provided default IDevicesFactory service is NULL");
+ addDeviceFactory(devicesFactory, false /*needToNotify*/);
}
+void DevicesFactoryHalHidl::onFirstRef() {
+ sp<IServiceManager> sm = IServiceManager::getService();
+ ALOG_ASSERT(sm != nullptr, "Hardware service manager is not running");
+ sp<ServiceNotificationListener> listener = new ServiceNotificationListener(this);
+ Return<bool> result = sm->registerForNotifications(
+ IDevicesFactory::descriptor, "", listener);
+ if (result.isOk()) {
+ ALOGE_IF(!static_cast<bool>(result),
+ "Hardware service manager refused to register listener");
+ } else {
+ ALOGE("Failed to register for hardware service manager notifications: %s",
+ result.description().c_str());
+ }
+}
#if MAJOR_VERSION == 2
static IDevicesFactory::Device idFromHal(const char *name, status_t* status) {
@@ -83,12 +108,13 @@
#endif
status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
- if (mDeviceFactories.empty()) return NO_INIT;
+ auto factories = copyDeviceFactories();
+ if (factories.empty()) return NO_INIT;
status_t status;
auto hidlId = idFromHal(name, &status);
if (status != OK) return status;
Result retval = Result::NOT_INITIALIZED;
- for (const auto& factory : mDeviceFactories) {
+ for (const auto& factory : factories) {
Return<void> ret = factory->openDevice(
hidlId,
[&](Result r, const sp<IDevice>& result) {
@@ -113,10 +139,9 @@
status_t DevicesFactoryHalHidl::getHalPids(std::vector<pid_t> *pids) {
std::set<pid_t> pidsSet;
-
- for (const auto& factory : mDeviceFactories) {
+ auto factories = copyDeviceFactories();
+ for (const auto& factory : factories) {
using ::android::hidl::base::V1_0::DebugInfo;
- using android::hidl::manager::V1_0::IServiceManager;
DebugInfo debugInfo;
auto ret = factory->getDebugInfo([&] (const auto &info) {
@@ -135,5 +160,48 @@
return NO_ERROR;
}
+status_t DevicesFactoryHalHidl::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+ ALOG_ASSERT(callback != nullptr);
+ bool needToCallCallback = false;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mCallback.unsafe_get()) return INVALID_OPERATION;
+ mCallback = callback;
+ if (mHaveUndeliveredNotifications) {
+ needToCallCallback = true;
+ mHaveUndeliveredNotifications = false;
+ }
+ }
+ if (needToCallCallback) {
+ callback->onNewDevicesAvailable();
+ }
+ return NO_ERROR;
+}
+
+void DevicesFactoryHalHidl::addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify) {
+ // It is assumed that the DevicesFactoryHalInterface instance is owned
+ // by AudioFlinger and thus have the same lifespan.
+ factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
+ sp<DevicesFactoryHalCallback> callback;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ mDeviceFactories.push_back(factory);
+ if (needToNotify) {
+ callback = mCallback.promote();
+ if (!callback) {
+ mHaveUndeliveredNotifications = true;
+ }
+ }
+ }
+ if (callback) {
+ callback->onNewDevicesAvailable();
+ }
+}
+
+std::vector<sp<IDevicesFactory>> DevicesFactoryHalHidl::copyDeviceFactories() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mDeviceFactories;
+}
+
} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 52185c8..6f84efe 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
+#include <mutex>
+#include <vector>
+
#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
#include <media/audiohal/DevicesFactoryHalInterface.h>
#include <utils/Errors.h>
@@ -32,16 +35,26 @@
class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
{
public:
- DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+ explicit DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+ void onFirstRef() override;
// Opens a device with the specified name. To close the device, it is
// necessary to release references to the returned object.
- virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+ status_t openDevice(const char *name, sp<DeviceHalInterface> *device) override;
- status_t getHalPids(std::vector<pid_t> *pids) override;
+ status_t getHalPids(std::vector<pid_t> *pids) override;
+
+ status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
private:
- std::vector<sp<IDevicesFactory>> mDeviceFactories;
+ friend class ServiceNotificationListener;
+ void addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify);
+ std::vector<sp<IDevicesFactory>> copyDeviceFactories();
+
+ std::mutex mLock;
+ std::vector<sp<IDevicesFactory>> mDeviceFactories; // GUARDED_BY(mLock)
+ wp<DevicesFactoryHalCallback> mCallback; // GUARDED_BY(mLock)
+ bool mHaveUndeliveredNotifications = false; // GUARDED_BY(mLock)
virtual ~DevicesFactoryHalHidl() = default;
};
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index 52f150a..cde8d85 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -44,6 +44,13 @@
return INVALID_OPERATION;
}
+status_t DevicesFactoryHalHybrid::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+ if (mHidlFactory) {
+ return mHidlFactory->setCallbackOnce(callback);
+ }
+ return INVALID_OPERATION;
+}
+
} // namespace CPP_VERSION
extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() {
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index 2189b36..568a1fb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -38,6 +38,8 @@
status_t getHalPids(std::vector<pid_t> *pids) override;
+ status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
+
private:
sp<DevicesFactoryHalInterface> mLocalFactory;
sp<DevicesFactoryHalInterface> mHidlFactory;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
index 2b011f4..32bf362 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
@@ -37,6 +37,10 @@
return INVALID_OPERATION;
}
+ status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback __unused) override {
+ return INVALID_OPERATION;
+ }
+
private:
friend class DevicesFactoryHalHybrid;
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index c08dddb..2726e36 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -299,10 +299,17 @@
if (mCallback.unsafe_get()) {
processReturn("clearCallback", mStream->clearCallback());
}
+#if MAJOR_VERSION >= 6
+ if (mEventCallback.unsafe_get() != nullptr) {
+ processReturn("setEventCallback",
+ mStream->setEventCallback(nullptr));
+ }
+#endif
processReturn("close", mStream->close());
mStream.clear();
}
mCallback.clear();
+ mEventCallback.clear();
hardware::IPCThreadState::self()->flushCommands();
if (mEfGroup) {
EventFlag::deleteEventFlag(&mEfGroup);
@@ -614,6 +621,50 @@
}
#endif
+#if MAJOR_VERSION < 6
+status_t StreamOutHalHidl::setEventCallback(
+ const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
+ // Codec format callback is supported starting from audio HAL V6.0
+ return INVALID_OPERATION;
+}
+#else
+
+#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
+
+namespace {
+
+struct StreamOutEventCallback : public IStreamOutEventCallback {
+ StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
+
+ // IStreamOutEventCallback implementation
+ Return<void> onCodecFormatChanged(
+ const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
+ sp<StreamOutHalHidl> stream = mStream.promote();
+ if (stream != nullptr) {
+ std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
+ stream->onCodecFormatChanged(metadataBs);
+ }
+ return Void();
+ }
+
+ private:
+ wp<StreamOutHalHidl> mStream;
+};
+
+} // namespace
+
+status_t StreamOutHalHidl::setEventCallback(
+ const sp<StreamOutHalInterfaceEventCallback>& callback) {
+ if (mStream == nullptr) return NO_INIT;
+ mEventCallback = callback;
+ status_t status = processReturn(
+ "setEventCallback",
+ mStream->setEventCallback(
+ callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
+ return status;
+}
+#endif
+
void StreamOutHalHidl::onWriteReady() {
sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
if (callback == 0) return;
@@ -635,6 +686,13 @@
callback->onError();
}
+void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
+ sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.promote();
+ if (callback == nullptr) return;
+ ALOGV("asyncCodecFormatCallback %s", __func__);
+ callback->onCodecFormatChanged(metadataBs);
+}
+
StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
: StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index f587889..88f8587 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -173,6 +173,11 @@
void onDrainReady();
void onError();
+ status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
+ // Methods used by StreamCodecFormatCallback (HIDL).
+ void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
+
private:
friend class DeviceHalHidl;
typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
@@ -180,6 +185,7 @@
typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ;
wp<StreamOutHalInterfaceCallback> mCallback;
+ wp<StreamOutHalInterfaceEventCallback> mEventCallback;
sp<IStreamOut> mStream;
std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<DataMQ> mDataMQ;
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
index 4818fd8..69be303 100644
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -275,6 +275,43 @@
return mStream->get_mmap_position(mStream, position);
}
+status_t StreamOutHalLocal::setEventCallback(
+ const sp<StreamOutHalInterfaceEventCallback>& callback) {
+ if (mStream->set_event_callback == nullptr) {
+ return INVALID_OPERATION;
+ }
+ stream_event_callback_t asyncCallback =
+ callback == nullptr ? nullptr : StreamOutHalLocal::asyncEventCallback;
+ status_t result = mStream->set_event_callback(mStream, asyncCallback, this);
+ if (result == OK) {
+ mEventCallback = callback;
+ }
+ return result;
+}
+
+// static
+int StreamOutHalLocal::asyncEventCallback(
+ stream_event_callback_type_t event, void *param, void *cookie) {
+ // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
+ // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
+ // already running, because the destructor is invoked after the refcount has been atomically
+ // decremented.
+ wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
+ sp<StreamOutHalLocal> self = weakSelf.promote();
+ if (self == nullptr) return 0;
+ sp<StreamOutHalInterfaceEventCallback> callback = self->mEventCallback.promote();
+ if (callback.get() == nullptr) return 0;
+ switch (event) {
+ case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED:
+ callback->onCodecFormatChanged(std::basic_string<uint8_t>((uint8_t*)param));
+ break;
+ default:
+ ALOGW("%s unknown event %d", __func__, event);
+ break;
+ }
+ return 0;
+}
+
StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
: StreamHalLocal(&stream->common, device), mStream(stream) {
}
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
index 34f2bd8..d17f9f3 100644
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -156,9 +156,12 @@
// Called when the metadata of the stream's source has been changed.
status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
+ status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
private:
audio_stream_out_t *mStream;
wp<StreamOutHalInterfaceCallback> mCallback;
+ wp<StreamOutHalInterfaceEventCallback> mEventCallback;
friend class DeviceHalLocal;
@@ -168,6 +171,8 @@
virtual ~StreamOutHalLocal();
static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
+
+ static int asyncEventCallback(stream_event_callback_type_t event, void *param, void *cookie);
};
class StreamInHalLocal : public StreamInHalInterface, public StreamHalLocal {
diff --git a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
index e9ac1ce..5091558 100644
--- a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -24,6 +24,12 @@
namespace android {
+class DevicesFactoryHalCallback : public RefBase
+{
+ public:
+ virtual void onNewDevicesAvailable() = 0;
+};
+
class DevicesFactoryHalInterface : public RefBase
{
public:
@@ -33,6 +39,10 @@
virtual status_t getHalPids(std::vector<pid_t> *pids) = 0;
+ // Sets a DevicesFactoryHalCallback to notify the client.
+ // The callback can be only set once.
+ virtual status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) = 0;
+
static sp<DevicesFactoryHalInterface> create();
protected:
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index 6c3b21c..e30cb72 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -101,6 +101,15 @@
virtual ~StreamOutHalInterfaceCallback() {}
};
+class StreamOutHalInterfaceEventCallback : public virtual RefBase {
+public:
+ virtual void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) = 0;
+
+protected:
+ StreamOutHalInterfaceEventCallback() {}
+ virtual ~StreamOutHalInterfaceEventCallback() {}
+};
+
class StreamOutHalInterface : public virtual StreamHalInterface {
public:
// Return the audio hardware driver estimated latency in milliseconds.
@@ -157,6 +166,8 @@
*/
virtual status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) = 0;
+ virtual status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) = 0;
+
protected:
virtual ~StreamOutHalInterface() {}
};
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index c10e6e0..cf7f423 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -2009,6 +2009,9 @@
(*meta)->setInt32(kKeyRotation, mRotationDegrees);
}
}
+ if (mOutputFormat == OUTPUT_FORMAT_MPEG_4 || mOutputFormat == OUTPUT_FORMAT_THREE_GPP) {
+ (*meta)->setInt32(kKeyEmptyTrackMalFormed, true);
+ }
}
status_t StagefrightRecorder::pause() {
diff --git a/media/libstagefright/FrameCaptureLayer.cpp b/media/libstagefright/FrameCaptureLayer.cpp
index 815057d..d2cfd41 100644
--- a/media/libstagefright/FrameCaptureLayer.cpp
+++ b/media/libstagefright/FrameCaptureLayer.cpp
@@ -67,7 +67,8 @@
bool isHdrY410(const BufferItem &bi) {
ui::Dataspace dataspace = translateDataspace(static_cast<ui::Dataspace>(bi.mDataSpace));
// pixel format is HDR Y410 masquerading as RGBA_1010102
- return (dataspace == ui::Dataspace::BT2020_ITU_PQ &&
+ return ((dataspace == ui::Dataspace::BT2020_ITU_PQ ||
+ dataspace == ui::Dataspace::BT2020_ITU_HLG) &&
bi.mGraphicBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 3c4524b..734f5bb 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -248,7 +248,8 @@
transfer = 0;
}
return standard == ColorUtils::kColorStandardBT2020 &&
- transfer == ColorUtils::kColorTransferST2084;
+ (transfer == ColorUtils::kColorTransferST2084 ||
+ transfer == ColorUtils::kColorTransferHLG);
}
status_t FrameDecoder::init(
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index dbbdd1b..af8096d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1131,8 +1131,8 @@
err = writerErr;
}
- // Do not write out movie header on error.
- if (err != OK) {
+ // Do not write out movie header on error except malformed track.
+ if (err != OK && err != ERROR_MALFORMED) {
release();
return err;
}
@@ -2687,7 +2687,7 @@
status_t MPEG4Writer::Track::stop(bool stopSource) {
ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
if (!mStarted) {
- ALOGE("Stop() called but track is not started");
+ ALOGE("Stop() called but track is not started or stopped");
return ERROR_END_OF_STREAM;
}
@@ -2711,6 +2711,7 @@
err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
WARN_UNLESS(err == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err,
stopSource ? "Stop" : "Not Stop");
+ mStarted = false;
return err;
}
@@ -3108,6 +3109,7 @@
int32_t nActualFrames = 0; // frames containing non-CSD data (non-0 length)
int32_t nZeroLengthFrames = 0;
int64_t lastTimestampUs = 0; // Previous sample time stamp
+ int64_t previousSampleTimestampWithoutFudgeUs = 0; // Timestamp received/without fudge for STTS
int64_t lastDurationUs = 0; // Between the previous two samples
int64_t currDurationTicks = 0; // Timescale based ticks
int64_t lastDurationTicks = 0; // Timescale based ticks
@@ -3120,6 +3122,8 @@
int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks
int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry
uint32_t lastSamplesPerChunk = 0;
+ int64_t lastSampleDurationUs = -1; // Duration calculated from EOS buffer and its timestamp
+ int64_t lastSampleDurationTicks = -1; // Timescale based ticks
if (mIsAudio) {
prctl(PR_SET_NAME, (unsigned long)"AudioTrackWriterThread", 0, 0, 0);
@@ -3139,14 +3143,34 @@
MediaBufferBase *buffer;
const char *trackName = getTrackType();
while (!mDone && (err = mSource->read(&buffer)) == OK) {
+ int32_t isEOS = false;
if (buffer->range_length() == 0) {
- buffer->release();
- buffer = NULL;
- ++nZeroLengthFrames;
- continue;
+ if (buffer->meta_data().findInt32(kKeyIsEndOfStream, &isEOS) && isEOS) {
+ int64_t eosSampleTimestampUs = -1;
+ CHECK(buffer->meta_data().findInt64(kKeyTime, &eosSampleTimestampUs));
+ if (eosSampleTimestampUs > 0) {
+ lastSampleDurationUs = eosSampleTimestampUs -
+ previousSampleTimestampWithoutFudgeUs -
+ previousPausedDurationUs;
+ if (lastSampleDurationUs >= 0) {
+ lastSampleDurationTicks = (lastSampleDurationUs * mTimeScale + 500000LL) /
+ 1000000LL;
+ } else {
+ ALOGW("lastSampleDurationUs %" PRId64 " is negative", lastSampleDurationUs);
+ }
+ }
+ buffer->release();
+ buffer = nullptr;
+ mSource->stop();
+ break;
+ } else {
+ buffer->release();
+ buffer = nullptr;
+ ++nZeroLengthFrames;
+ continue;
+ }
}
-
// If the codec specific data has not been received yet, delay pause.
// After the codec specific data is received, discard what we received
// when the track is to be paused.
@@ -3470,6 +3494,8 @@
break;
}
+ previousSampleTimestampWithoutFudgeUs = timestampUs;
+
// if the duration is different for this sample, see if it is close enough to the previous
// duration that we can fudge it and use the same value, to avoid filling the stts table
// with lots of near-identical entries.
@@ -3567,47 +3593,61 @@
}
}
if (isTrackMalFormed()) {
+ mIsMalformed = true;
dumpTimeStamps();
err = ERROR_MALFORMED;
}
mOwner->trackProgressStatus(mTrackId, -1, err);
- if (mIsHeic) {
- if (!mChunkSamples.empty()) {
- bufferChunk(0);
- ++nChunks;
- }
- } else {
- // Last chunk
- if (!hasMultipleTracks) {
- addOneStscTableEntry(1, mStszTableEntries->count());
- } else if (!mChunkSamples.empty()) {
- addOneStscTableEntry(++nChunks, mChunkSamples.size());
- bufferChunk(timestampUs);
- }
-
- // We don't really know how long the last frame lasts, since
- // there is no frame time after it, just repeat the previous
- // frame's duration.
- if (mStszTableEntries->count() == 1) {
- lastDurationUs = 0; // A single sample's duration
- lastDurationTicks = 0;
+ // Add final entries only for non-empty tracks.
+ if (mStszTableEntries->count() > 0) {
+ if (mIsHeic) {
+ if (!mChunkSamples.empty()) {
+ bufferChunk(0);
+ ++nChunks;
+ }
} else {
- ++sampleCount; // Count for the last sample
- }
+ // Last chunk
+ if (!hasMultipleTracks) {
+ addOneStscTableEntry(1, mStszTableEntries->count());
+ } else if (!mChunkSamples.empty()) {
+ addOneStscTableEntry(++nChunks, mChunkSamples.size());
+ bufferChunk(timestampUs);
+ }
- addOneSttsTableEntry(sampleCount, lastDurationTicks);
+ // We don't really know how long the last frame lasts, since
+ // there is no frame time after it, just repeat the previous
+ // frame's duration.
+ if (mStszTableEntries->count() == 1) {
+ if (lastSampleDurationUs >= 0) {
+ addOneSttsTableEntry(sampleCount, lastSampleDurationTicks);
+ } else {
+ lastDurationUs = 0; // A single sample's duration
+ lastDurationTicks = 0;
+ addOneSttsTableEntry(sampleCount, lastDurationTicks);
+ }
+ } else if (lastSampleDurationUs >= 0) {
+ addOneSttsTableEntry(sampleCount, lastDurationTicks);
+ addOneSttsTableEntry(1, lastSampleDurationTicks);
+ } else {
+ ++sampleCount; // Count for the last sample
+ addOneSttsTableEntry(sampleCount, lastDurationTicks);
+ }
- // The last ctts box entry may not have been written yet, and this
- // is to make sure that we write out the last ctts box entry.
- if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
- if (cttsSampleCount > 0) {
- addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ // The last ctts box entry may not have been written yet, and this
+ // is to make sure that we write out the last ctts box entry.
+ if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
+ if (cttsSampleCount > 0) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ }
+ }
+ if (lastSampleDurationUs >= 0) {
+ mTrackDurationUs += lastSampleDurationUs;
+ } else {
+ mTrackDurationUs += lastDurationUs;
}
}
-
- mTrackDurationUs += lastDurationUs;
}
mReachedEOS = true;
@@ -3630,14 +3670,24 @@
return true;
}
- if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written
- ALOGE("The number of recorded samples is 0");
- return true;
- }
-
- if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video
- ALOGE("There are no sync frames for video track");
- return true;
+ int32_t emptyTrackMalformed = false;
+ if (mOwner->mStartMeta &&
+ mOwner->mStartMeta->findInt32(kKeyEmptyTrackMalFormed, &emptyTrackMalformed) &&
+ emptyTrackMalformed) {
+ if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written
+ ALOGE("The number of recorded samples is 0");
+ return true;
+ }
+ if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video
+ ALOGE("There are no sync frames for video track");
+ return true;
+ }
+ } else {
+ // No sync frames for video.
+ if (mIsVideo && mStszTableEntries->count() > 0 && mStssTableEntries->count() == 0) {
+ ALOGE("There are no sync frames for video track");
+ return true;
+ }
}
if (OK != checkCodecSpecificData()) { // no codec specific data
@@ -3886,25 +3936,28 @@
void MPEG4Writer::Track::writeStblBox() {
mOwner->beginBox("stbl");
- mOwner->beginBox("stsd");
- mOwner->writeInt32(0); // version=0, flags=0
- mOwner->writeInt32(1); // entry count
- if (mIsAudio) {
- writeAudioFourCCBox();
- } else if (mIsVideo) {
- writeVideoFourCCBox();
- } else {
- writeMetadataFourCCBox();
+ // Add subboxes only for non-empty tracks.
+ if (mStszTableEntries->count() > 0) {
+ mOwner->beginBox("stsd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(1); // entry count
+ if (mIsAudio) {
+ writeAudioFourCCBox();
+ } else if (mIsVideo) {
+ writeVideoFourCCBox();
+ } else {
+ writeMetadataFourCCBox();
+ }
+ mOwner->endBox(); // stsd
+ writeSttsBox();
+ if (mIsVideo) {
+ writeCttsBox();
+ writeStssBox();
+ }
+ writeStszBox();
+ writeStscBox();
+ writeCo64Box();
}
- mOwner->endBox(); // stsd
- writeSttsBox();
- if (mIsVideo) {
- writeCttsBox();
- writeStssBox();
- }
- writeStszBox();
- writeStscBox();
- writeCo64Box();
mOwner->endBox(); // stbl
}
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 3808d7e..1cb45ac 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -157,7 +157,6 @@
status_t MediaMuxer::stop() {
Mutex::Autolock autoLock(mMuxerLock);
-
if (mState == STARTED || mState == ERROR) {
mState = STOPPED;
for (size_t i = 0; i < mTrackList.size(); i++) {
@@ -165,7 +164,10 @@
return INVALID_OPERATION;
}
}
+ // Unlock this mutex to allow notify to be called during stop process.
+ mMuxerLock.unlock();
status_t err = mWriter->stop();
+ mMuxerLock.lock();
if (err != OK || mError != OK) {
ALOGE("stop err: %d, mError:%d", err, mError);
}
@@ -217,6 +219,11 @@
sampleMetaData.setInt32(kKeyIsMuxerData, 1);
}
+ if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+ sampleMetaData.setInt32(kKeyIsEndOfStream, 1);
+ ALOGV("BUFFER_FLAG_EOS");
+ }
+
sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
// This pushBuffer will wait until the mediaBuffer is consumed.
return currentTrack->pushBuffer(mediaBuffer);
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 9fe09fa..050d7c2 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -94,11 +94,16 @@
return ERROR_UNSUPPORTED;
}
+ status_t err = OK;
if (!mCasToken.empty()) {
- mImpl->setMediaCas(mCasToken);
+ err = mImpl->setMediaCas(mCasToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
}
- status_t err = updateDurationAndBitrate();
+ err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = dataSource;
}
@@ -131,7 +136,11 @@
}
if (!mCasToken.empty()) {
- mImpl->setMediaCas(mCasToken);
+ err = mImpl->setMediaCas(mCasToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
}
err = updateDurationAndBitrate();
@@ -161,7 +170,11 @@
}
if (!mCasToken.empty()) {
- mImpl->setMediaCas(mCasToken);
+ err = mImpl->setMediaCas(mCasToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
}
err = updateDurationAndBitrate();
@@ -195,8 +208,12 @@
mCasToken = casToken;
if (mImpl != NULL) {
- mImpl->setMediaCas(casToken);
- status_t err = updateDurationAndBitrate();
+ status_t err = mImpl->setMediaCas(casToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
+ err = updateDurationAndBitrate();
if (err != OK) {
return err;
}
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
index ea8b073..bcf63d5 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.bp
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -1,6 +1,7 @@
cc_library {
name: "libstagefright_amrnb_common",
vendor_available: true,
+ host_supported: true,
srcs: [
"src/add.cpp",
@@ -73,6 +74,12 @@
"-Werror",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+
//addressing b/25409744
//sanitize: {
// misc_undefined: [
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index e18117e..3381d2e 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -1,6 +1,7 @@
cc_library_static {
name: "libstagefright_amrnbdec",
vendor_available: true,
+ host_supported: true,
srcs: [
"src/a_refl.cpp",
@@ -61,6 +62,12 @@
"libstagefright_amrnb_common",
"liblog",
],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
//###############################################################################
@@ -100,6 +107,7 @@
cc_test {
name: "libstagefright_amrnbdec_test",
gtest: false,
+ host_supported: true,
srcs: ["test/amrnbdec_test.cpp"],
@@ -118,6 +126,12 @@
"liblog",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+
//sanitize: {
// misc_undefined: [
// "signed-integer-overflow",
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/Android.bp b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
new file mode 100644
index 0000000..54de1cc
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+ name: "amrnb_dec_fuzzer",
+ host_supported: true,
+ srcs: [
+ "amrnb_dec_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libstagefright_amrnbdec",
+ "libstagefright_amrnb_common",
+ "liblog",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/README.md b/media/libstagefright/codecs/amrnb/fuzzer/README.md
new file mode 100644
index 0000000..7791b83
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/README.md
@@ -0,0 +1,62 @@
+# Fuzzer for libstagefright_amrnbdec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-NB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-NB supports the following parameters:
+1. Stream format (parameter name: `input_format`)
+2. 3GPP frame type (parameter name: `frame_type`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `input_format` | 0. `MIME_IETF` 1. `IF2` | Bit 0 (LSB) of 1st byte of data. |
+| `frame_type` | 0. `AMR_475` 1. `AMR_515` 2. `AMR_59` 3. `AMR_67` 4. `AMR_74` 5. `AMR_795` 6. `AMR_102` 7. `AMR_122` | Bits 3, 4 and 5 of 1st byte of data. |
+
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the decode operation was successful, the input is advanced by the frame size
+which is based on `input_format` and `frame_type` selected.
+If the decode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrnb_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) amrnb_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some amrnb files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
new file mode 100644
index 0000000..d4e7e5c
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <string.h>
+#include <algorithm>
+#include "gsmamr_dec.h"
+
+// Constants for AMR-NB
+constexpr int32_t kSamplesPerFrame = L_FRAME;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const bitstream_format kBitStreamFormats[2] = {MIME_IETF, IF2};
+const int32_t kLocalWmfDecBytesPerFrame[8] = {12, 13, 15, 17, 19, 20, 26, 31};
+const int32_t kLocalIf2DecBytesPerFrame[8] = {13, 14, 16, 18, 19, 21, 26, 31};
+
+class Codec {
+ public:
+ Codec() = default;
+ ~Codec() { deInitDecoder(); }
+ int16_t initDecoder();
+ void deInitDecoder();
+ void decodeFrames(const uint8_t *data, size_t size);
+
+ private:
+ void *mAmrHandle = nullptr;
+};
+
+int16_t Codec::initDecoder() { return GSMInitDecode(&mAmrHandle, (Word8 *)"AMRNBDecoder"); }
+
+void Codec::deInitDecoder() { GSMDecodeFrameExit(&mAmrHandle); }
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+ while (size > 0) {
+ uint8_t mode = *data;
+ bool bit = mode & 0x01;
+ bitstream_format bitsreamFormat = kBitStreamFormats[bit];
+ int32_t frameSize = 0;
+ /* Find frame type */
+ Frame_Type_3GPP frameType = static_cast<Frame_Type_3GPP>((mode >> 3) & 0x07);
+ ++data;
+ --size;
+ if (bit) {
+ frameSize = kLocalIf2DecBytesPerFrame[frameType];
+ } else {
+ frameSize = kLocalWmfDecBytesPerFrame[frameType];
+ }
+ int16_t outputBuf[kOutputBufferSize];
+ uint8_t *inputBuf = new uint8_t[frameSize];
+ if (!inputBuf) {
+ return;
+ }
+ int32_t minSize = std::min((int32_t)size, frameSize);
+ memcpy(inputBuf, data, minSize);
+ AMRDecode(mAmrHandle, frameType, inputBuf, outputBuf, bitsreamFormat);
+ /* AMRDecode() decodes minSize number of bytes if decode is successful.
+ * AMRDecode() returns -1 if decode fails.
+ * Even if no bytes are decoded, increment by minSize to ensure fuzzer proceeds
+ * to feed next data */
+ data += minSize;
+ size -= minSize;
+ delete[] inputBuf;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 2) {
+ return 0;
+ }
+ Codec *codec = new Codec();
+ if (!codec) {
+ return 0;
+ }
+ if (codec->initDecoder() == 0) {
+ codec->decodeFrames(data, size);
+ }
+ delete codec;
+ return 0;
+}
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 67d3f1a..dd2eed3 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -48,13 +48,13 @@
</MediaCodec>
<MediaCodec name="c2.android.g711.alaw.decoder" type="audio/g711-alaw">
<Alias name="OMX.google.g711.alaw.decoder" />
- <Limit name="channel-count" max="1" />
+ <Limit name="channel-count" max="6" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
<MediaCodec name="c2.android.g711.mlaw.decoder" type="audio/g711-mlaw">
<Alias name="OMX.google.g711.mlaw.decoder" />
- <Limit name="channel-count" max="1" />
+ <Limit name="channel-count" max="6" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
@@ -67,7 +67,7 @@
<MediaCodec name="c2.android.opus.decoder" type="audio/opus">
<Alias name="OMX.google.opus.decoder" />
<Limit name="channel-count" max="8" />
- <Limit name="sample-rate" ranges="48000" />
+ <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
<Limit name="bitrate" range="6000-510000" />
</MediaCodec>
<MediaCodec name="c2.android.raw.decoder" type="audio/raw">
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index b9cd18a..3b701f6 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -70,6 +70,7 @@
kKeyIsSyncFrame = 'sync', // int32_t (bool)
kKeyIsCodecConfig = 'conf', // int32_t (bool)
kKeyIsMuxerData = 'muxd', // int32_t (bool)
+ kKeyIsEndOfStream = 'feos', // int32_t (bool)
kKeyTime = 'time', // int64_t (usecs)
kKeyDecodingTime = 'decT', // int64_t (decoding timestamp in usecs)
kKeyNTPTime = 'ntpT', // uint64_t (ntp-timestamp)
@@ -237,6 +238,9 @@
kKeyOpaqueCSD2 = 'csd2',
kKeyHapticChannelCount = 'hapC',
+
+ // Treat empty track as malformed for MediaRecorder.
+ kKeyEmptyTrackMalFormed = 'nemt', // bool (int32_t)
};
enum {
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 1aa8a20..574bd7a 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -112,7 +112,9 @@
sp<ABuffer> profileLevelID = NULL;
if (GetAttribute(params, "profile-level-id", &val)) {
profileLevelID = decodeHex(val);
- CHECK_EQ(profileLevelID->size(), 3u);
+ if (profileLevelID != NULL && profileLevelID->size() != 3u) {
+ profileLevelID = NULL;
+ }
}
Vector<sp<ABuffer> > paramSets;
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index 409f141..ff063e3 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -243,6 +243,10 @@
sp<MetaData> trackMeta = new MetaData;
convertMessageToMetaData(format, trackMeta);
mCurrentTrack = new MediaAdapter(trackMeta);
+ if (mCurrentTrack == nullptr) {
+ ALOGE("MediaAdapter returned nullptr");
+ return -1;
+ }
status_t result = mWriter->addSource(mCurrentTrack);
return result;
}
@@ -301,7 +305,7 @@
getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
- getInputBufferInfo(inputFile, inputInfo);
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
status = addWriterSource(isAudio, param);
ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
@@ -338,7 +342,7 @@
getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
- getInputBufferInfo(inputFile, inputInfo);
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
status = addWriterSource(isAudio, param);
ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
@@ -397,7 +401,7 @@
getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
- getInputBufferInfo(inputFile, inputInfo);
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
status = addWriterSource(isAudio, param);
ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 631a2ab..59ce8db 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -321,6 +321,7 @@
status_t WebmFrameMediaSourceThread::pause() {
if (mStarted) {
mPaused = true;
+ mResumed = false;
}
return OK;
}
diff --git a/media/libwatchdog/Android.bp b/media/libwatchdog/Android.bp
index 849623a..2aefa7d 100644
--- a/media/libwatchdog/Android.bp
+++ b/media/libwatchdog/Android.bp
@@ -19,10 +19,8 @@
],
export_include_dirs: ["include"],
shared_libs: [
- "liblog",
- ],
- static_libs: [
"libbase",
+ "liblog",
],
target: {
windows: {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e5a6e27..74a09d1 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -29,6 +29,7 @@
#include <string>
#include <sys/time.h>
#include <sys/resource.h>
+#include <thread>
#include <android/os/IExternalVibratorService.h>
#include <binder/IPCThreadState.h>
@@ -144,6 +145,19 @@
return sExternalVibratorService;
}
+class DevicesFactoryHalCallbackImpl : public DevicesFactoryHalCallback {
+ public:
+ void onNewDevicesAvailable() override {
+ // Start a detached thread to execute notification in parallel.
+ // This is done to prevent mutual blocking of audio_flinger and
+ // audio_policy services during system initialization.
+ std::thread notifier([]() {
+ AudioSystem::onNewAudioModulesAvailable();
+ });
+ notifier.detach();
+ }
+};
+
// ----------------------------------------------------------------------------
std::string formatToString(audio_format_t format) {
@@ -227,6 +241,9 @@
mMode = AUDIO_MODE_NORMAL;
gAudioFlinger = this;
+
+ mDevicesFactoryHalCallback = new DevicesFactoryHalCallbackImpl;
+ mDevicesFactoryHal->setCallbackOnce(mDevicesFactoryHalCallback);
}
status_t AudioFlinger::setAudioHalPids(const std::vector<pid_t>& pids) {
@@ -833,7 +850,7 @@
input.notificationsPerBuffer, input.speed,
input.sharedBuffer, sessionId, &output.flags,
callingPid, input.clientInfo.clientTid, clientUid,
- &lStatus, portId);
+ &lStatus, portId, input.audioTrackCallback);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
// we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index a16fa94..6d7bf3c 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <limits.h>
+#include <android/media/IAudioTrackCallback.h>
#include <android/os/BnExternalVibrationController.h>
#include <android-base/macros.h>
@@ -104,6 +105,7 @@
class AudioBuffer;
class AudioResampler;
class DeviceHalInterface;
+class DevicesFactoryHalCallback;
class DevicesFactoryHalInterface;
class EffectsFactoryHalInterface;
class FastMixer;
@@ -836,6 +838,7 @@
DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*> mAudioHwDevs;
sp<DevicesFactoryHalInterface> mDevicesFactoryHal;
+ sp<DevicesFactoryHalCallback> mDevicesFactoryHalCallback;
// for dump, indicates which hardware operation is currently in progress (but not stream ops)
enum hardware_call_state {
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 2f3724f..82b9c96 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1395,7 +1395,11 @@
void AudioFlinger::EffectChain::setVolumeForOutput_l(uint32_t left, uint32_t right)
{
- if (mEffectCallback->isOffloadOrDirect() && !isNonOffloadableEnabled_l()) {
+ // for offload or direct thread, if the effect chain has non-offloadable
+ // effect and any effect module within the chain has volume control, then
+ // volume control is delegated to effect, otherwise, set volume to hal.
+ if (mEffectCallback->isOffloadOrDirect() &&
+ !(isNonOffloadableEnabled_l() && hasVolumeControlEnabled_l())) {
float vol_l = (float)left / (1 << 24);
float vol_r = (float)right / (1 << 24);
mEffectCallback->setVolumeForOutput(vol_l, vol_r);
@@ -2296,6 +2300,13 @@
}
}
+bool AudioFlinger::EffectChain::hasVolumeControlEnabled_l() const {
+ for (const auto &effect : mEffects) {
+ if (effect->isVolumeControlEnabled()) return true;
+ }
+ return false;
+}
+
// setVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
{
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 4901451..2826297 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -596,6 +596,9 @@
void setThread(const sp<ThreadBase>& thread);
+ // true if any effect module within the chain has volume control
+ bool hasVolumeControlEnabled_l() const;
+
void setVolumeForOutput_l(uint32_t left, uint32_t right);
mutable Mutex mLock; // mutex protecting effect list
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2833525..f24dcd7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -42,6 +42,7 @@
#include <private/media/AudioTrackShared.h>
#include <private/android_filesystem_config.h>
#include <audio_utils/Balance.h>
+#include <audio_utils/Metadata.h>
#include <audio_utils/channels.h>
#include <audio_utils/mono_blend.h>
#include <audio_utils/primitives.h>
@@ -1921,6 +1922,16 @@
void AudioFlinger::PlaybackThread::onFirstRef()
{
+ if (mOutput == nullptr || mOutput->stream == nullptr) {
+ ALOGE("The stream is not open yet"); // This should not happen.
+ } else {
+ // setEventCallback will need a strong pointer as a parameter. Calling it
+ // here instead of constructor of PlaybackThread so that the onFirstRef
+ // callback would not be made on an incompletely constructed object.
+ if (mOutput->stream->setEventCallback(this) != OK) {
+ ALOGE("Failed to add event callback");
+ }
+ }
run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
}
@@ -2050,7 +2061,8 @@
pid_t tid,
uid_t uid,
status_t *status,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ const sp<media::IAudioTrackCallback>& callback)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2340,6 +2352,12 @@
goto Exit;
}
mTracks.add(track);
+ {
+ Mutex::Autolock _atCbL(mAudioTrackCbLock);
+ if (callback.get() != nullptr) {
+ mAudioTrackCallbacks.emplace(callback);
+ }
+ }
sp<EffectChain> chain = getEffectChain_l(sessionId);
if (chain != 0) {
@@ -2642,6 +2660,29 @@
mCallbackThread->setAsyncError();
}
+void AudioFlinger::PlaybackThread::onCodecFormatChanged(
+ const std::basic_string<uint8_t>& metadataBs)
+{
+ std::thread([this, metadataBs]() {
+ audio_utils::metadata::Data metadata =
+ audio_utils::metadata::dataFromByteString(metadataBs);
+ if (metadata.empty()) {
+ ALOGW("Can not transform the buffer to audio metadata, %s, %d",
+ reinterpret_cast<char*>(const_cast<uint8_t*>(metadataBs.data())),
+ (int)metadataBs.size());
+ return;
+ }
+
+ audio_utils::metadata::ByteString metaDataStr =
+ audio_utils::metadata::byteStringFromData(metadata);
+ std::vector metadataVec(metaDataStr.begin(), metaDataStr.end());
+ Mutex::Autolock _l(mAudioTrackCbLock);
+ for (const auto& callback : mAudioTrackCallbacks) {
+ callback->onCodecFormatChanged(metadataVec);
+ }
+ }).detach();
+}
+
void AudioFlinger::PlaybackThread::resetWriteBlocked(uint32_t sequence)
{
Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index b0eb75d..153cf7c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -720,7 +720,7 @@
// --- PlaybackThread ---
class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback,
- public VolumeInterface {
+ public VolumeInterface, public StreamOutHalInterfaceEventCallback {
public:
#include "PlaybackTracks.h"
@@ -796,6 +796,10 @@
virtual void onAddNewTrack_l();
void onAsyncError(); // error reported by AsyncCallbackThread
+ // StreamHalInterfaceCodecFormatCallback implementation
+ void onCodecFormatChanged(
+ const std::basic_string<uint8_t>& metadataBs) override;
+
// ThreadBase virtuals
virtual void preExit();
@@ -845,7 +849,8 @@
pid_t tid,
uid_t uid,
status_t *status /*non-NULL*/,
- audio_port_handle_t portId);
+ audio_port_handle_t portId,
+ const sp<media::IAudioTrackCallback>& callback);
AudioStreamOut* getOutput() const;
AudioStreamOut* clearOutput();
@@ -1168,6 +1173,10 @@
uint32_t mDrainSequence;
sp<AsyncCallbackThread> mCallbackThread;
+ Mutex mAudioTrackCbLock;
+ // Record of IAudioTrackCallback
+ std::set<sp<media::IAudioTrackCallback>> mAudioTrackCallbacks;
+
private:
// The HAL output sink is treated as non-blocking, but current implementation is blocking
sp<NBAIO_Sink> mOutputSink;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 4d53be4..8d0e5db 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -83,6 +83,10 @@
// configuration functions
//
+ // Informs APM that new HAL modules are available. This typically happens
+ // due to registration of an audio HAL service.
+ virtual void onNewAudioModulesAvailable() = 0;
+
// indicate a change in device connection status
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index e59386f..395bc70 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -37,13 +37,13 @@
{
public:
AudioPolicyConfig(HwModuleCollection &hwModules,
- DeviceVector &availableOutputDevices,
- DeviceVector &availableInputDevices,
+ DeviceVector &outputDevices,
+ DeviceVector &inputDevices,
sp<DeviceDescriptor> &defaultOutputDevice)
: mEngineLibraryNameSuffix(kDefaultEngineLibraryNameSuffix),
mHwModules(hwModules),
- mAvailableOutputDevices(availableOutputDevices),
- mAvailableInputDevices(availableInputDevices),
+ mOutputDevices(outputDevices),
+ mInputDevices(inputDevices),
mDefaultOutputDevice(defaultOutputDevice),
mIsSpeakerDrcEnabled(false),
mIsCallScreenModeSupported(false)
@@ -70,23 +70,23 @@
mHwModules = hwModules;
}
- void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
+ void addDevice(const sp<DeviceDescriptor> &device)
{
- if (audio_is_output_device(availableDevice->type())) {
- mAvailableOutputDevices.add(availableDevice);
- } else if (audio_is_input_device(availableDevice->type())) {
- mAvailableInputDevices.add(availableDevice);
+ if (audio_is_output_device(device->type())) {
+ mOutputDevices.add(device);
+ } else if (audio_is_input_device(device->type())) {
+ mInputDevices.add(device);
}
}
- void addAvailableInputDevices(const DeviceVector &availableInputDevices)
+ void addInputDevices(const DeviceVector &inputDevices)
{
- mAvailableInputDevices.add(availableInputDevices);
+ mInputDevices.add(inputDevices);
}
- void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
+ void addOutputDevices(const DeviceVector &outputDevices)
{
- mAvailableOutputDevices.add(availableOutputDevices);
+ mOutputDevices.add(outputDevices);
}
bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
@@ -106,14 +106,14 @@
const HwModuleCollection getHwModules() const { return mHwModules; }
- const DeviceVector &getAvailableInputDevices() const
+ const DeviceVector &getInputDevices() const
{
- return mAvailableInputDevices;
+ return mInputDevices;
}
- const DeviceVector &getAvailableOutputDevices() const
+ const DeviceVector &getOutputDevices() const
{
- return mAvailableOutputDevices;
+ return mOutputDevices;
}
void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
@@ -134,13 +134,11 @@
sp<AudioProfile> micProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
defaultInputDevice->addAudioProfile(micProfile);
- mAvailableOutputDevices.add(mDefaultOutputDevice);
- mAvailableInputDevices.add(defaultInputDevice);
+ mOutputDevices.add(mDefaultOutputDevice);
+ mInputDevices.add(defaultInputDevice);
sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
mHwModules.add(module);
- mDefaultOutputDevice->attach(module);
- defaultInputDevice->attach(module);
sp<OutputProfile> outProfile = new OutputProfile("primary");
outProfile->addAudioProfile(
@@ -191,8 +189,8 @@
std::string mSource;
std::string mEngineLibraryNameSuffix;
HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
- DeviceVector &mAvailableOutputDevices;
- DeviceVector &mAvailableInputDevices;
+ DeviceVector &mOutputDevices;
+ DeviceVector &mInputDevices;
sp<DeviceDescriptor> &mDefaultOutputDevice;
// TODO: remove when legacy conf file is removed. true on devices that use DRC on the
// DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index dd51658..aaa28bc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -33,7 +33,10 @@
namespace android {
-DeviceTypeSet APM_AUDIO_OUT_DEVICE_REMOTE_ALL = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+static const DeviceTypeSet& getAllOutRemoteDevices() {
+ static const DeviceTypeSet allOutRemoteDevices = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+ return allOutRemoteDevices;
+}
AudioOutputDescriptor::AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
AudioPolicyClientInterface *clientInterface)
@@ -681,7 +684,7 @@
const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
if (outputDesc->isActive(volumeSource, inPastMs, sysTime)
&& (!(outputDesc->devices()
- .containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL)))) {
+ .containsDeviceAmongTypes(getAllOutRemoteDevices())))) {
return true;
}
}
@@ -693,7 +696,7 @@
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
- if (outputDesc->devices().containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL) &&
+ if (outputDesc->devices().containsDeviceAmongTypes(getAllOutRemoteDevices()) &&
outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
// do not consider re routing (when the output is going to a dynamic policy)
// as "remote playback"
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 1b2f7c7..883e713 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -653,7 +653,7 @@
sp<DeviceDescriptor> device = module->getDeclaredDevices().
getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
attachedDevice.get())));
- ctx->addAvailableDevice(device);
+ ctx->addDevice(device);
}
}
}
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index a7d7cf6..b14d2bb 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -41,20 +41,23 @@
{
struct legacy_strategy_map { const char *name; legacy_strategy id; };
-static const std::vector<legacy_strategy_map> gLegacyStrategy = {
- { "STRATEGY_NONE", STRATEGY_NONE },
- { "STRATEGY_MEDIA", STRATEGY_MEDIA },
- { "STRATEGY_PHONE", STRATEGY_PHONE },
- { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
- { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
- { "STRATEGY_DTMF", STRATEGY_DTMF },
- { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
- { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
- { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
- { "STRATEGY_REROUTING", STRATEGY_REROUTING },
- { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
- { "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
-};
+static const std::vector<legacy_strategy_map>& getLegacyStrategy() {
+ static const std::vector<legacy_strategy_map> legacyStrategy = {
+ { "STRATEGY_NONE", STRATEGY_NONE },
+ { "STRATEGY_MEDIA", STRATEGY_MEDIA },
+ { "STRATEGY_PHONE", STRATEGY_PHONE },
+ { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
+ { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
+ { "STRATEGY_DTMF", STRATEGY_DTMF },
+ { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
+ { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
+ { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
+ { "STRATEGY_REROUTING", STRATEGY_REROUTING },
+ { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
+ { "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
+ };
+ return legacyStrategy;
+}
Engine::Engine()
{
@@ -63,7 +66,8 @@
"Policy Engine configuration is partially invalid, skipped %zu elements",
result.nbSkippedElement);
- for (const auto &strategy : gLegacyStrategy) {
+ auto legacyStrategy = getLegacyStrategy();
+ for (const auto &strategy : legacyStrategy) {
mLegacyStrategyMap[getProductStrategyByName(strategy.name)] = strategy.id;
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0aa087a..5a012bf 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4397,7 +4397,7 @@
mpClientInterface(clientInterface),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
- mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice),
+ mConfig(mHwModulesAll, mOutputDevicesAll, mInputDevicesAll, mDefaultOutputDevice),
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
@@ -4442,141 +4442,9 @@
return status;
}
- // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
+ // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
// open all output streams needed to access attached devices
- for (const auto& hwModule : mHwModulesAll) {
- hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
- if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
- ALOGW("could not open HW module %s", hwModule->getName());
- continue;
- }
- mHwModules.push_back(hwModule);
- // open all output streams needed to access attached devices
- // except for direct output streams that are only opened when they are actually
- // required by an app.
- // This also validates mAvailableOutputDevices list
- for (const auto& outProfile : hwModule->getOutputProfiles()) {
- if (!outProfile->canOpenNewIo()) {
- ALOGE("Invalid Output profile max open count %u for profile %s",
- outProfile->maxOpenCount, outProfile->getTagName().c_str());
- continue;
- }
- if (!outProfile->hasSupportedDevices()) {
- ALOGW("Output profile contains no device on module %s", hwModule->getName());
- continue;
- }
- if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
- mTtsOutputAvailable = true;
- }
-
- if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
- continue;
- }
- const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
- DeviceVector availProfileDevices = supportedDevices.filter(mAvailableOutputDevices);
- sp<DeviceDescriptor> supportedDevice = 0;
- if (supportedDevices.contains(mDefaultOutputDevice)) {
- supportedDevice = mDefaultOutputDevice;
- } else {
- // choose first device present in profile's SupportedDevices also part of
- // mAvailableOutputDevices.
- if (availProfileDevices.isEmpty()) {
- continue;
- }
- supportedDevice = availProfileDevices.itemAt(0);
- }
- if (!mAvailableOutputDevices.contains(supportedDevice)) {
- continue;
- }
- sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
- mpClientInterface);
- audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
- AUDIO_STREAM_DEFAULT,
- AUDIO_OUTPUT_FLAG_NONE, &output);
- if (status != NO_ERROR) {
- ALOGW("Cannot open output stream for devices %s on hw module %s",
- supportedDevice->toString().c_str(), hwModule->getName());
- continue;
- }
- for (const auto &device : availProfileDevices) {
- // give a valid ID to an attached device once confirmed it is reachable
- if (!device->isAttached()) {
- device->attach(hwModule);
- }
- }
- if (mPrimaryOutput == 0 &&
- outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
- mPrimaryOutput = outputDesc;
- }
- addOutput(output, outputDesc);
- setOutputDevices(outputDesc,
- DeviceVector(supportedDevice),
- true,
- 0,
- NULL);
- }
- // open input streams needed to access attached devices to validate
- // mAvailableInputDevices list
- for (const auto& inProfile : hwModule->getInputProfiles()) {
- if (!inProfile->canOpenNewIo()) {
- ALOGE("Invalid Input profile max open count %u for profile %s",
- inProfile->maxOpenCount, inProfile->getTagName().c_str());
- continue;
- }
- if (!inProfile->hasSupportedDevices()) {
- ALOGW("Input profile contains no device on module %s", hwModule->getName());
- continue;
- }
- // chose first device present in profile's SupportedDevices also part of
- // available input devices
- const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
- DeviceVector availProfileDevices = supportedDevices.filter(mAvailableInputDevices);
- if (availProfileDevices.isEmpty()) {
- ALOGE("%s: Input device list is empty!", __FUNCTION__);
- continue;
- }
- sp<AudioInputDescriptor> inputDesc =
- new AudioInputDescriptor(inProfile, mpClientInterface);
-
- audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
- status_t status = inputDesc->open(nullptr,
- availProfileDevices.itemAt(0),
- AUDIO_SOURCE_MIC,
- AUDIO_INPUT_FLAG_NONE,
- &input);
- if (status != NO_ERROR) {
- ALOGW("Cannot open input stream for device %s on hw module %s",
- availProfileDevices.toString().c_str(),
- hwModule->getName());
- continue;
- }
- for (const auto &device : availProfileDevices) {
- // give a valid ID to an attached device once confirmed it is reachable
- if (!device->isAttached()) {
- device->attach(hwModule);
- device->importAudioPortAndPickAudioProfile(inProfile, true);
- }
- }
- inputDesc->close();
- }
- }
- // make sure all attached devices have been allocated a unique ID
- auto checkAndSetAvailable = [this](auto& devices) {
- for (size_t i = 0; i < devices.size();) {
- const auto &device = devices[i];
- if (!device->isAttached()) {
- ALOGW("device %s is unreachable", device->toString().c_str());
- devices.remove(device);
- continue;
- }
- // Device is now validated and can be appended to the available devices of the engine
- setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
- i++;
- }
- };
- checkAndSetAvailable(mAvailableOutputDevices);
- checkAndSetAvailable(mAvailableInputDevices);
+ onNewAudioModulesAvailable();
// make sure default device is reachable
if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
@@ -4631,6 +4499,134 @@
// ---
+void AudioPolicyManager::onNewAudioModulesAvailable()
+{
+ for (const auto& hwModule : mHwModulesAll) {
+ if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
+ continue;
+ }
+ hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
+ if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
+ ALOGW("could not open HW module %s", hwModule->getName());
+ continue;
+ }
+ mHwModules.push_back(hwModule);
+ // open all output streams needed to access attached devices
+ // except for direct output streams that are only opened when they are actually
+ // required by an app.
+ // This also validates mAvailableOutputDevices list
+ for (const auto& outProfile : hwModule->getOutputProfiles()) {
+ if (!outProfile->canOpenNewIo()) {
+ ALOGE("Invalid Output profile max open count %u for profile %s",
+ outProfile->maxOpenCount, outProfile->getTagName().c_str());
+ continue;
+ }
+ if (!outProfile->hasSupportedDevices()) {
+ ALOGW("Output profile contains no device on module %s", hwModule->getName());
+ continue;
+ }
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+ mTtsOutputAvailable = true;
+ }
+
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+ continue;
+ }
+ const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+ DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
+ sp<DeviceDescriptor> supportedDevice = 0;
+ if (supportedDevices.contains(mDefaultOutputDevice)) {
+ supportedDevice = mDefaultOutputDevice;
+ } else {
+ // choose first device present in profile's SupportedDevices also part of
+ // mAvailableOutputDevices.
+ if (availProfileDevices.isEmpty()) {
+ continue;
+ }
+ supportedDevice = availProfileDevices.itemAt(0);
+ }
+ if (!mOutputDevicesAll.contains(supportedDevice)) {
+ continue;
+ }
+ sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
+ mpClientInterface);
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
+ AUDIO_STREAM_DEFAULT,
+ AUDIO_OUTPUT_FLAG_NONE, &output);
+ if (status != NO_ERROR) {
+ ALOGW("Cannot open output stream for devices %s on hw module %s",
+ supportedDevice->toString().c_str(), hwModule->getName());
+ continue;
+ }
+ for (const auto &device : availProfileDevices) {
+ // give a valid ID to an attached device once confirmed it is reachable
+ if (!device->isAttached()) {
+ device->attach(hwModule);
+ mAvailableOutputDevices.add(device);
+ setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+ }
+ }
+ if (mPrimaryOutput == 0 &&
+ outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ mPrimaryOutput = outputDesc;
+ }
+ addOutput(output, outputDesc);
+ setOutputDevices(outputDesc,
+ DeviceVector(supportedDevice),
+ true,
+ 0,
+ NULL);
+ }
+ // open input streams needed to access attached devices to validate
+ // mAvailableInputDevices list
+ for (const auto& inProfile : hwModule->getInputProfiles()) {
+ if (!inProfile->canOpenNewIo()) {
+ ALOGE("Invalid Input profile max open count %u for profile %s",
+ inProfile->maxOpenCount, inProfile->getTagName().c_str());
+ continue;
+ }
+ if (!inProfile->hasSupportedDevices()) {
+ ALOGW("Input profile contains no device on module %s", hwModule->getName());
+ continue;
+ }
+ // chose first device present in profile's SupportedDevices also part of
+ // available input devices
+ const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+ DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
+ if (availProfileDevices.isEmpty()) {
+ ALOGE("%s: Input device list is empty!", __FUNCTION__);
+ continue;
+ }
+ sp<AudioInputDescriptor> inputDesc =
+ new AudioInputDescriptor(inProfile, mpClientInterface);
+
+ audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+ status_t status = inputDesc->open(nullptr,
+ availProfileDevices.itemAt(0),
+ AUDIO_SOURCE_MIC,
+ AUDIO_INPUT_FLAG_NONE,
+ &input);
+ if (status != NO_ERROR) {
+ ALOGW("Cannot open input stream for device %s on hw module %s",
+ availProfileDevices.toString().c_str(),
+ hwModule->getName());
+ continue;
+ }
+ for (const auto &device : availProfileDevices) {
+ // give a valid ID to an attached device once confirmed it is reachable
+ if (!device->isAttached()) {
+ device->attach(hwModule);
+ device->importAudioPortAndPickAudioProfile(inProfile, true);
+ mAvailableInputDevices.add(device);
+ setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+ }
+ }
+ inputDesc->close();
+ }
+ }
+}
+
void AudioPolicyManager::addOutput(audio_io_handle_t output,
const sp<SwAudioOutputDescriptor>& outputDesc)
{
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index b0adbc7..8121f86 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -325,6 +325,8 @@
bool isCallScreenModeSupported() override;
+ void onNewAudioModulesAvailable() override;
+
status_t initialize();
protected:
@@ -729,6 +731,8 @@
SwAudioOutputCollection mPreviousOutputs;
AudioInputCollection mInputs; // list of input descriptors
+ DeviceVector mOutputDevicesAll; // all output devices from the config
+ DeviceVector mInputDevicesAll; // all input devices from the config
DeviceVector mAvailableOutputDevices; // all available output devices
DeviceVector mAvailableInputDevices; // all available input devices
@@ -739,9 +743,8 @@
EffectDescriptorCollection mEffects; // list of registered audio effects
sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
- HwModuleCollection mHwModules; // contains only modules that have been loaded successfully
- HwModuleCollection mHwModulesAll; // normally not needed, used during construction and for
- // dumps
+ HwModuleCollection mHwModules; // contains modules that have been loaded successfully
+ HwModuleCollection mHwModulesAll; // contains all modules declared in the config
AudioPolicyConfig mConfig;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 38801ec..0da3b9c 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -66,6 +66,14 @@
// ----------------------------------------------------------------------------
+void AudioPolicyService::doOnNewAudioModulesAvailable()
+{
+ if (mAudioPolicyManager == NULL) return;
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ mAudioPolicyManager->onNewAudioModulesAvailable();
+}
+
status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 99cec5a..bf38477 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -446,17 +446,19 @@
sp<AudioRecordClient> topActive;
sp<AudioRecordClient> latestActive;
+ sp<AudioRecordClient> topSensitiveActive;
sp<AudioRecordClient> latestSensitiveActive;
nsecs_t topStartNs = 0;
nsecs_t latestStartNs = 0;
+ nsecs_t topSensitiveStartNs = 0;
nsecs_t latestSensitiveStartNs = 0;
bool isA11yOnTop = mUidPolicy->isA11yOnTop();
bool isAssistantOnTop = false;
bool isSensitiveActive = false;
bool isInCall = mPhoneState == AUDIO_MODE_IN_CALL;
- bool rttCallActive =
- (mPhoneState == AUDIO_MODE_IN_CALL || mPhoneState == AUDIO_MODE_IN_COMMUNICATION)
+ bool isInCommunication = mPhoneState == AUDIO_MODE_IN_COMMUNICATION;
+ bool rttCallActive = (isInCall || isInCommunication)
&& mUidPolicy->isRttEnabled();
bool onlyHotwordActive = true;
@@ -479,33 +481,47 @@
continue;
}
- bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
bool isAccessibility = mUidPolicy->isA11yUid(current->uid);
- if (appState == APP_STATE_TOP && !isAccessibility) {
- if (current->startTimeNs > topStartNs) {
- topActive = current;
- topStartNs = current->startTimeNs;
+ // Clients capturing for Accessibility services are not considered
+ // for top or latest active to avoid masking regular clients started before
+ if (!isAccessibility) {
+ bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
+ bool isPrivacySensitive =
+ (current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0;
+ if (appState == APP_STATE_TOP) {
+ if (isPrivacySensitive) {
+ if (current->startTimeNs > topSensitiveStartNs) {
+ topSensitiveActive = current;
+ topSensitiveStartNs = current->startTimeNs;
+ }
+ } else {
+ if (current->startTimeNs > topStartNs) {
+ topActive = current;
+ topStartNs = current->startTimeNs;
+ }
+ }
+ if (isAssistant) {
+ isAssistantOnTop = true;
+ }
}
- if (isAssistant) {
- isAssistantOnTop = true;
+ // Clients capturing for HOTWORD are not considered
+ // for latest active to avoid masking regular clients started before
+ if (!(current->attributes.source == AUDIO_SOURCE_HOTWORD
+ || ((isA11yOnTop || rttCallActive) && isAssistant))) {
+ if (isPrivacySensitive) {
+ if (current->startTimeNs > latestSensitiveStartNs) {
+ latestSensitiveActive = current;
+ latestSensitiveStartNs = current->startTimeNs;
+ }
+ isSensitiveActive = true;
+ } else {
+ if (current->startTimeNs > latestStartNs) {
+ latestActive = current;
+ latestStartNs = current->startTimeNs;
+ }
+ }
}
}
- // Client capturing for HOTWORD or Accessibility services not considered
- // for latest active to avoid masking regular clients started before
- if (current->startTimeNs > latestStartNs
- && !(current->attributes.source == AUDIO_SOURCE_HOTWORD
- || ((isA11yOnTop || rttCallActive) && isAssistant))
- && !isAccessibility) {
- latestActive = current;
- latestStartNs = current->startTimeNs;
- }
- if ((current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0) {
- if (current->startTimeNs > latestSensitiveStartNs) {
- latestSensitiveActive = current;
- latestSensitiveStartNs = current->startTimeNs;
- }
- isSensitiveActive = true;
- }
if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
onlyHotwordActive = false;
}
@@ -514,6 +530,21 @@
// if no active client with UI on Top, consider latest active as top
if (topActive == nullptr) {
topActive = latestActive;
+ topStartNs = latestStartNs;
+ }
+ if (topSensitiveActive == nullptr) {
+ topSensitiveActive = latestSensitiveActive;
+ topSensitiveStartNs = latestSensitiveStartNs;
+ }
+
+ // If both privacy sensitive and regular capture are active:
+ // if the regular capture is privileged
+ // allow concurrency
+ // else
+ // favor the privacy sensitive case
+ if (topActive != nullptr && topSensitiveActive != nullptr
+ && !topActive->canCaptureCallOrOutput) {
+ topActive = nullptr;
}
for (size_t i =0; i < mAudioRecordClients.size(); i++) {
@@ -524,8 +555,17 @@
audio_source_t source = current->attributes.source;
bool isTopOrLatestActive = topActive == nullptr ? false : current->uid == topActive->uid;
- bool isLatestSensitive = latestSensitiveActive == nullptr ?
- false : current->uid == latestSensitiveActive->uid;
+ bool isTopOrLatestSensitive = topSensitiveActive == nullptr ?
+ false : current->uid == topSensitiveActive->uid;
+
+ auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) {
+ bool canCaptureCall = recordClient->canCaptureCallOrOutput;
+ bool canCaptureCommunication = recordClient->canCaptureCallOrOutput
+ || recordClient->uid == mPhoneStateOwnerUid
+ || isServiceUid(mPhoneStateOwnerUid);
+ return !(isInCall && !canCaptureCall)
+ && !(isInCommunication && !canCaptureCommunication);
+ };
// By default allow capture if:
// The assistant is not on TOP
@@ -533,9 +573,10 @@
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
bool allowCapture = !isAssistantOnTop
- && ((isTopOrLatestActive && !isLatestSensitive) || isLatestSensitive)
- && !(isSensitiveActive && !(isLatestSensitive || current->canCaptureCallOrOutput))
- && !(isInCall && !current->canCaptureCallOrOutput);
+ && (isTopOrLatestActive || isTopOrLatestSensitive)
+ && !(isSensitiveActive
+ && !(isTopOrLatestSensitive || current->canCaptureCallOrOutput))
+ && canCaptureIfInCallOrCommunication(current);
if (isVirtualSource(source)) {
// Allow capture for virtual (remote submix, call audio TX or RX...) sources
@@ -554,8 +595,9 @@
}
} else {
if (((isAssistantOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
- source == AUDIO_SOURCE_HOTWORD) &&
- (!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) {
+ source == AUDIO_SOURCE_HOTWORD)
+ && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+ && canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
}
@@ -567,7 +609,8 @@
// OR
// Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
if (!isAssistantOnTop
- && (!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) {
+ && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+ && canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
if (isA11yOnTop) {
@@ -580,7 +623,8 @@
// All active clients are using HOTWORD source
// AND no call is active
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
- if (onlyHotwordActive && !(isInCall && !current->canCaptureCallOrOutput)) {
+ if (onlyHotwordActive
+ && canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
}
@@ -1277,6 +1321,16 @@
mLock.lock();
}
} break;
+ case AUDIO_MODULES_UPDATE: {
+ ALOGV("AudioCommandThread() processing audio modules update");
+ svc = mService.promote();
+ if (svc == 0) {
+ break;
+ }
+ mLock.unlock();
+ svc->doOnNewAudioModulesAvailable();
+ mLock.lock();
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
@@ -1566,6 +1620,13 @@
sendCommand(command);
}
+void AudioPolicyService::AudioCommandThread::audioModulesUpdateCommand()
+{
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = AUDIO_MODULES_UPDATE;
+ sendCommand(command);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -1813,6 +1874,11 @@
mAudioCommandThread->setEffectSuspendedCommand(effectId, sessionId, suspended);
}
+void AudioPolicyService::onNewAudioModulesAvailable()
+{
+ mAudioCommandThread->audioModulesUpdateCommand();
+}
+
extern "C" {
audio_module_handle_t aps_load_hw_module(void *service __unused,
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index c3c87f1..ff99124 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -60,6 +60,7 @@
// BnAudioPolicyService (see AudioPolicyInterface for method descriptions)
//
+ void onNewAudioModulesAvailable() override;
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
@@ -277,6 +278,7 @@
bool isCallScreenModeSupported() override;
+ void doOnNewAudioModulesAvailable();
status_t doStopOutput(audio_port_handle_t portId);
void doReleaseOutput(audio_port_handle_t portId);
@@ -463,6 +465,7 @@
DYN_POLICY_MIX_STATE_UPDATE,
RECORDING_CONFIGURATION_UPDATE,
SET_EFFECT_SUSPENDED,
+ AUDIO_MODULES_UPDATE,
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -508,6 +511,7 @@
void setEffectSuspendedCommand(int effectId,
audio_session_t sessionId,
bool suspended);
+ void audioModulesUpdateCommand();
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
class AudioCommandData;
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index c2a92d7..af69466 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -15,6 +15,7 @@
*/
#include <map>
+#include <set>
#include <system/audio.h>
#include <utils/Log.h>
@@ -27,7 +28,10 @@
class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
public:
// AudioPolicyClientInterface implementation
- audio_module_handle_t loadHwModule(const char * /*name*/) override {
+ audio_module_handle_t loadHwModule(const char* name) override {
+ if (!mAllowedModuleNames.empty() && !mAllowedModuleNames.count(name)) {
+ return AUDIO_MODULE_HANDLE_NONE;
+ }
return mNextModuleHandle++;
}
@@ -101,11 +105,18 @@
return &it->second;
};
+ audio_module_handle_t peekNextModuleHandle() const { return mNextModuleHandle; }
+
+ void swapAllowedModuleNames(std::set<std::string>&& names = {}) {
+ mAllowedModuleNames.swap(names);
+ }
+
private:
audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
+ std::set<std::string> mAllowedModuleNames;
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index bafcc63..922a538 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -27,6 +27,8 @@
using AudioPolicyManager::loadConfig;
using AudioPolicyManager::initialize;
using AudioPolicyManager::getOutputs;
+ using AudioPolicyManager::getAvailableOutputDevices;
+ using AudioPolicyManager::getAvailableInputDevices;
};
} // namespace android
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index 8736cf1..b5c67a1 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -67,10 +67,10 @@
manager.loadConfig();
ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
- for (auto desc : manager.getConfig().getAvailableInputDevices()) {
+ for (auto desc : manager.getConfig().getInputDevices()) {
ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
}
- for (auto desc : manager.getConfig().getAvailableOutputDevices()) {
+ for (auto desc : manager.getConfig().getOutputDevices()) {
ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
}
}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 2a8349c..7d92f34 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -298,9 +298,9 @@
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
uid_t uid = 42;
const PatchCountCheck patchCount = snapshotPatchCount();
- ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
+ ASSERT_FALSE(mManager->getAvailableInputDevices().isEmpty());
PatchBuilder patchBuilder;
- patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
+ patchBuilder.addSource(mManager->getAvailableInputDevices()[0]).
addSink(mManager->getConfig().getDefaultOutputDevice());
ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
@@ -334,15 +334,13 @@
sp<AudioProfile> pcmInputProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
mMsdInputDevice->addAudioProfile(pcmInputProfile);
- config.addAvailableDevice(mMsdOutputDevice);
- config.addAvailableDevice(mMsdInputDevice);
+ config.addDevice(mMsdOutputDevice);
+ config.addDevice(mMsdInputDevice);
sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
HwModuleCollection modules = config.getHwModules();
modules.add(msdModule);
config.setHwModules(modules);
- mMsdOutputDevice->attach(msdModule);
- mMsdInputDevice->attach(msdModule);
sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
msdOutputProfile->addAudioProfile(pcmOutputProfile);
@@ -1127,3 +1125,40 @@
AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
"low latency");
}
+
+class AudioPolicyManagerDynamicHwModulesTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+ void SetUpManagerConfig() override;
+};
+
+void AudioPolicyManagerDynamicHwModulesTest::SetUpManagerConfig() {
+ AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig();
+ // Only allow successful opening of "primary" hw module during APM initialization.
+ mClient->swapAllowedModuleNames({"primary"});
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, DynamicAddition) {
+ const auto handleBefore = mClient->peekNextModuleHandle();
+ mManager->onNewAudioModulesAvailable();
+ ASSERT_EQ(handleBefore, mClient->peekNextModuleHandle());
+ // Reset module loading restrictions.
+ mClient->swapAllowedModuleNames();
+ mManager->onNewAudioModulesAvailable();
+ const auto handleAfter = mClient->peekNextModuleHandle();
+ ASSERT_GT(handleAfter, handleBefore);
+ mManager->onNewAudioModulesAvailable();
+ ASSERT_EQ(handleAfter, mClient->peekNextModuleHandle());
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, AddedDeviceAvailable) {
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, mManager->getDeviceConnectionState(
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+ mClient->swapAllowedModuleNames({"primary", "r_submix"});
+ mManager->onNewAudioModulesAvailable();
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, mManager->getDeviceConnectionState(
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 2de5c80..9bc79e0 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -126,6 +126,8 @@
static const String16 sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
static const String16
sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
+static const String16 sCameraOpenCloseListenerPermission(
+ "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
// Matches with PERCEPTIBLE_APP_ADJ in ProcessList.java
static constexpr int32_t kVendorClientScore = 200;
@@ -2146,6 +2148,8 @@
auto clientUid = CameraThreadState::getCallingUid();
auto clientPid = CameraThreadState::getCallingPid();
+ bool openCloseCallbackAllowed = checkPermission(sCameraOpenCloseListenerPermission,
+ clientPid, clientUid);
Mutex::Autolock lock(mServiceLock);
@@ -2160,7 +2164,8 @@
}
sp<ServiceListener> serviceListener =
- new ServiceListener(this, listener, clientUid, clientPid, isVendorListener);
+ new ServiceListener(this, listener, clientUid, clientPid, isVendorListener,
+ openCloseCallbackAllowed);
auto ret = serviceListener->initialize();
if (ret != NO_ERROR) {
String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
@@ -2923,6 +2928,9 @@
sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
+ // Notify listeners of camera open/close status
+ sCameraService->updateOpenCloseStatus(mCameraIdStr, true/*open*/, mClientPackageName);
+
return OK;
}
@@ -2963,6 +2971,9 @@
sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
+ // Notify listeners of camera open/close status
+ sCameraService->updateOpenCloseStatus(mCameraIdStr, false/*open*/, mClientPackageName);
+
return OK;
}
@@ -3759,6 +3770,29 @@
});
}
+void CameraService::updateOpenCloseStatus(const String8& cameraId, bool open,
+ const String16& clientPackageName) {
+ Mutex::Autolock lock(mStatusListenerLock);
+
+ for (const auto& it : mListenerList) {
+ if (!it->isOpenCloseCallbackAllowed()) {
+ continue;
+ }
+
+ binder::Status ret;
+ String16 cameraId64(cameraId);
+ if (open) {
+ ret = it->getListener()->onCameraOpened(cameraId64, clientPackageName);
+ } else {
+ ret = it->getListener()->onCameraClosed(cameraId64);
+ }
+ if (!ret.isOk()) {
+ ALOGE("%s: Failed to trigger onCameraOpened/onCameraClosed callback: %d", __FUNCTION__,
+ ret.exceptionCode());
+ }
+ }
+}
+
template<class Func>
void CameraService::CameraState::updateStatus(StatusInternal status,
const String8& cameraId,
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 751833e..1adf15a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -912,9 +912,10 @@
class ServiceListener : public virtual IBinder::DeathRecipient {
public:
ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
- int uid, int pid, bool isVendorClient)
+ int uid, int pid, bool isVendorClient, bool openCloseCallbackAllowed)
: mParent(parent), mListener(listener), mListenerUid(uid), mListenerPid(pid),
- mIsVendorListener(isVendorClient) { }
+ mIsVendorListener(isVendorClient),
+ mOpenCloseCallbackAllowed(openCloseCallbackAllowed) { }
status_t initialize() {
return IInterface::asBinder(mListener)->linkToDeath(this);
@@ -931,6 +932,7 @@
int getListenerPid() { return mListenerPid; }
sp<hardware::ICameraServiceListener> getListener() { return mListener; }
bool isVendorListener() { return mIsVendorListener; }
+ bool isOpenCloseCallbackAllowed() { return mOpenCloseCallbackAllowed; }
private:
wp<CameraService> mParent;
@@ -938,6 +940,7 @@
int mListenerUid = -1;
int mListenerPid = -1;
bool mIsVendorListener = false;
+ bool mOpenCloseCallbackAllowed = false;
};
// Guarded by mStatusListenerMutex
@@ -960,6 +963,13 @@
void updateStatus(StatusInternal status,
const String8& cameraId);
+ /**
+ * Update the opened/closed status of the given camera id.
+ *
+ * This method acqiures mStatusListenerLock.
+ */
+ void updateOpenCloseStatus(const String8& cameraId, bool open, const String16& packageName);
+
// flashlight control
sp<CameraFlashlight> mFlashlight;
// guard mTorchStatusMap
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
index d7cc2bf..d36ca3b 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
@@ -91,6 +91,8 @@
// The "measured-frame-rate-WIDTHxHEIGHT-range" key is optional.
// Hardcode to some default value (3.33ms * tile count) based on resolution.
*stall = 3333333LL * width * height / (kGridWidth * kGridHeight);
+ *useHeic = chooseHeic;
+ *useGrid = enableGrid;
return true;
}
@@ -275,9 +277,13 @@
ALOGE("%s: Failed to get codec info for %s", __FUNCTION__, mime);
break;
}
+ ALOGV("%s: [%s] codec found", __FUNCTION__,
+ info->getCodecName());
// Filter out software ones as they may be too slow
if (!(info->getAttributes() & MediaCodecInfo::kFlagIsHardwareAccelerated)) {
+ ALOGV("%s: [%s] Filter out software ones as they may be too slow", __FUNCTION__,
+ info->getCodecName());
continue;
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index aac49ef..cc369fa 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -326,8 +326,11 @@
// Pass the camera ID to start interface so that it will save it to the map of ICameraProviders
// that are currently in use.
- const sp<provider::V2_4::ICameraProvider> interface =
- deviceInfo->mParentProvider->startProviderInterface();
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ const sp<provider::V2_4::ICameraProvider> interface = parentProvider->startProviderInterface();
if (interface == nullptr) {
return DEAD_OBJECT;
}
@@ -380,8 +383,11 @@
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
- const sp<provider::V2_4::ICameraProvider> provider =
- deviceInfo->mParentProvider->startProviderInterface();
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
if (provider == nullptr) {
return DEAD_OBJECT;
}
@@ -423,8 +429,11 @@
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
auto *deviceInfo1 = static_cast<ProviderInfo::DeviceInfo1*>(deviceInfo);
- const sp<provider::V2_4::ICameraProvider> provider =
- deviceInfo->mParentProvider->startProviderInterface();
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
if (provider == nullptr) {
return DEAD_OBJECT;
}
@@ -999,7 +1008,8 @@
if (sizeAvail) continue;
int64_t stall = 0;
- bool useHeic, useGrid;
+ bool useHeic = false;
+ bool useGrid = false;
if (camera3::HeicCompositeStream::isSizeSupportedByHeifEncoder(
halStreamConfigs.data.i32[i+1], halStreamConfigs.data.i32[i+2],
&useHeic, &useGrid, &stall)) {
@@ -2044,7 +2054,10 @@
sp<InterfaceT> device;
ATRACE_CALL();
if (mSavedInterface == nullptr) {
- device = mParentProvider->startDeviceInterface<InterfaceT>(mName);
+ sp<ProviderInfo> parentProvider = mParentProvider.promote();
+ if (parentProvider != nullptr) {
+ device = parentProvider->startDeviceInterface<InterfaceT>(mName);
+ }
} else {
device = (InterfaceT *) mSavedInterface.get();
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 9a715b7..50044d8 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -447,7 +447,7 @@
std::map<std::string, hardware::camera::common::V1_0::CameraDeviceStatus>
mPhysicalStatus;
- sp<ProviderInfo> mParentProvider;
+ wp<ProviderInfo> mParentProvider;
bool hasFlashUnit() const { return mHasFlashUnit; }
bool supportNativeZoomRatio() const { return mSupportNativeZoomRatio; }
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
index 95493a1..7148035 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -58,6 +58,15 @@
// TODO: no implementation yet.
return binder::Status::ok();
}
+ virtual binder::Status onCameraOpened(const ::android::String16& /*cameraId*/,
+ const ::android::String16& /*clientPackageId*/) {
+ // empty implementation
+ return binder::Status::ok();
+ }
+ virtual binder::Status onCameraClosed(const ::android::String16& /*cameraId*/) {
+ // empty implementation
+ return binder::Status::ok();
+ }
};
} // implementation
diff --git a/services/camera/libcameraservice/utils/ExifUtils.cpp b/services/camera/libcameraservice/utils/ExifUtils.cpp
index c0afdc1..8a0303a 100644
--- a/services/camera/libcameraservice/utils/ExifUtils.cpp
+++ b/services/camera/libcameraservice/utils/ExifUtils.cpp
@@ -603,13 +603,13 @@
}
bool ExifUtilsImpl::setImageHeight(uint32_t length) {
- SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+ SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
return true;
}
bool ExifUtilsImpl::setImageWidth(uint32_t width) {
- SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+ SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
return true;
}
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index e2e1429..4bf103c 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -89,6 +89,31 @@
"android.hidl.memory@1.0",
],
+ runtime_libs: [
+ "libstagefright_soft_aacdec",
+ "libstagefright_soft_aacenc",
+ "libstagefright_soft_amrdec",
+ "libstagefright_soft_amrnbenc",
+ "libstagefright_soft_amrwbenc",
+ "libstagefright_soft_avcdec",
+ "libstagefright_soft_avcenc",
+ "libstagefright_soft_flacdec",
+ "libstagefright_soft_flacenc",
+ "libstagefright_soft_g711dec",
+ "libstagefright_soft_gsmdec",
+ "libstagefright_soft_hevcdec",
+ "libstagefright_soft_mp3dec",
+ "libstagefright_soft_mpeg2dec",
+ "libstagefright_soft_mpeg4dec",
+ "libstagefright_soft_mpeg4enc",
+ "libstagefright_soft_opusdec",
+ "libstagefright_soft_rawdec",
+ "libstagefright_soft_vorbisdec",
+ "libstagefright_soft_vpxdec",
+ "libstagefright_soft_vpxenc",
+ "libstagefright_softomx_plugin",
+ ],
+
// OMX interfaces force this to stay in 32-bit mode;
compile_multilib: "32",
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 835f8bb..b4a9ff6 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -23,7 +23,7 @@
# on ARM is statically loaded at 0xffff 0000. See
# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
# for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
munmap: 1
mprotect: 1
madvise: 1
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm64.policy b/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
index 835f8bb..b4a9ff6 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
@@ -23,7 +23,7 @@
# on ARM is statically loaded at 0xffff 0000. See
# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
# for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
munmap: 1
mprotect: 1
madvise: 1
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 512e675..9058f10 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -31,7 +31,7 @@
# on ARM is statically loaded at 0xffff 0000. See
# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
# for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
munmap: 1
prctl: 1
getuid32: 1
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index d9603ef..4c51a9c 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
@@ -35,7 +35,7 @@
# on ARM is statically loaded at 0xffff 0000. See
# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
# for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
munmap: 1
prctl: 1
writev: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 07536fc..e1f7fe7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -48,6 +48,14 @@
# for dynamically loading extractors
pread64: 1
+# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
+# parser support for '<' is in this needs to be modified to also prevent
+# |old_address| and |new_address| from touching the exception vector page, which
+# on ARM is statically loaded at 0xffff 0000. See
+# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
+# for more details.
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
+
# for FileSource
readlinkat: 1
_llseek: 1
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 811e135..a6fefd2 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -113,6 +113,7 @@
case AID_MEDIA_CODEC:
case AID_MEDIA_EX:
case AID_MEDIA_DRM:
+ // case AID_SHELL: // DEBUG ONLY - used for mediametrics_tests to add new keys
case AID_SYSTEM:
// trusted source, only override default values
isTrusted = true;
@@ -145,9 +146,10 @@
}
}
- ALOGV("%s: given uid %d; sanitized uid: %d sanitized pkg: %s "
+ ALOGV("%s: isTrusted:%d given uid %d; sanitized uid: %d sanitized pkg: %s "
"sanitized pkg version: %lld",
__func__,
+ (int)isTrusted,
uid_given, item->getUid(),
item->getPkgName().c_str(),
(long long)item->getPkgVersionCode());
@@ -384,7 +386,7 @@
break;
}
if (now > when && (now - when) <= mMaxRecordAgeNs) {
- break; // TODO: if we use BOOTTIME, should be monotonic.
+ break; // Note SYSTEM_TIME_REALTIME may not be monotonic.
}
if (i >= mMaxRecordsExpiredAtOnce) {
// this represents "one too many"; tell caller there are
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
index e048d0e..a4c3693 100644
--- a/services/mediametrics/TimeMachine.h
+++ b/services/mediametrics/TimeMachine.h
@@ -93,7 +93,7 @@
template <typename T>
status_t getValue(const std::string &property, T* value, int64_t time = 0) const {
- if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+ if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
const auto tsptr = mPropertyMap.find(property);
if (tsptr == mPropertyMap.end()) return BAD_VALUE;
const auto& timeSequence = tsptr->second;
@@ -122,14 +122,25 @@
template <typename T>
void putValue(const std::string &property,
T&& e, int64_t time = 0) {
- if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+ if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
mLastModificationTime = time;
+ if (mPropertyMap.size() >= kKeyMaxProperties &&
+ !mPropertyMap.count(property)) {
+ ALOGV("%s: too many properties, rejecting %s", __func__, property.c_str());
+ return;
+ }
auto& timeSequence = mPropertyMap[property];
Elem el{std::forward<T>(e)};
if (timeSequence.empty() // no elements
|| property.back() == AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED
|| timeSequence.rbegin()->second != el) { // value changed
timeSequence.emplace(time, std::move(el));
+
+ if (timeSequence.size() > kTimeSequenceMaxElements) {
+ ALOGV("%s: restricting maximum elements (discarding oldest) for %s",
+ __func__, property.c_str());
+ timeSequence.erase(timeSequence.begin());
+ }
}
}
@@ -188,6 +199,8 @@
using History = std::map<std::string /* key */, std::shared_ptr<KeyHistory>>;
+ static inline constexpr size_t kTimeSequenceMaxElements = 100;
+ static inline constexpr size_t kKeyMaxProperties = 100;
static inline constexpr size_t kKeyLowWaterMark = 500;
static inline constexpr size_t kKeyHighWaterMark = 1000;
@@ -239,6 +252,9 @@
const int64_t time = item->getTimestamp();
const std::string &key = item->getKey();
+ ALOGV("%s(%zu, %zu): key: %s isTrusted:%d size:%zu",
+ __func__, mKeyLowWaterMark, mKeyHighWaterMark,
+ key.c_str(), (int)isTrusted, item->count());
std::shared_ptr<KeyHistory> keyHistory;
{
std::vector<std::any> garbage;
@@ -324,7 +340,7 @@
/**
* Individual property put.
*
- * Put takes in a time (if none is provided then BOOTTIME is used).
+ * Put takes in a time (if none is provided then SYSTEM_TIME_REALTIME is used).
*/
template <typename T>
status_t put(const std::string &url, T &&e, int64_t time = 0) {
@@ -333,7 +349,7 @@
std::shared_ptr<KeyHistory> keyHistory =
getKeyHistoryFromUrl(url, &key, &prop);
if (keyHistory == nullptr) return BAD_VALUE;
- if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+ if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
std::lock_guard lock(getLockForKey(key));
keyHistory->putValue(prop, std::forward<T>(e), time);
return NO_ERROR;
@@ -446,6 +462,9 @@
/**
* Garbage collects if the TimeMachine size exceeds the high water mark.
*
+ * This GC operation limits the number of keys stored (not the size of properties
+ * stored in each key).
+ *
* \param garbage a type-erased vector of elements to be destroyed
* outside of lock. Move large items to be destroyed here.
*
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/TransactionLog.h
index 27e2c14..190a99e 100644
--- a/services/mediametrics/TransactionLog.h
+++ b/services/mediametrics/TransactionLog.h
@@ -264,7 +264,7 @@
return ret;
}
- const size_t mLowWaterMark = kLogItemsHighWater;
+ const size_t mLowWaterMark = kLogItemsLowWater;
const size_t mHighWaterMark = kLogItemsHighWater;
mutable std::mutex mLock;
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 27b72eb..b8e566e 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -846,3 +846,21 @@
ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
}
}
+
+#if 0
+// Stress test code for garbage collection, you need to enable AID_SHELL as trusted to run
+// in MediaMetricsService.cpp.
+//
+// TODO: Make a dedicated stress test.
+//
+TEST(mediametrics_tests, gc_same_key) {
+ // random keys ignored when empty
+ for (int i = 0; i < 10000000; ++i) {
+ std::unique_ptr<mediametrics::Item> test_key(mediametrics::Item::create("audio.zzz.123"));
+ test_key->set("event#", "hello");
+ test_key->set("value", (int)10);
+ test_key->selfrecord();
+ }
+ //mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+#endif