Merge "CSD: Add csd start/stop of BT categorized devices" into main
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 866dc72..921aab2 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -165,11 +165,6 @@
include_dirs: [
"system/media/private/camera/include",
],
- product_variables: {
- pdk: {
- enabled: false,
- },
- },
}
cc_test {
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index bd679e5..af00e55 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -5384,7 +5384,7 @@
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_DEFAULT">CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT</a> mode.
* They can be queried through
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#get">CameraCharacteristics#get</a> with
- * <a href="https://developer.android.com/reference/CameraCharacteristics.html#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION)">CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION)</a>.
+ * <a href="https://developer.android.com/reference/CameraCharacteristics.html#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION">CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION</a>.
* Unless reported by both
* <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html">StreamConfigurationMap</a>s, the outputs from
* <code>android.scaler.streamConfigurationMapMaximumResolution</code> and
@@ -5399,13 +5399,12 @@
* <ul>
* <li>
* <p>The mandatory stream combinations listed in
- * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics/mandatoryMaximumResolutionStreamCombinations.html">mandatoryMaximumResolutionStreamCombinations</a>
- * would not apply.</p>
+ * android.scaler.mandatoryMaximumResolutionStreamCombinations would not apply.</p>
* </li>
* <li>
* <p>The bayer pattern of {@code RAW} streams when
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>
- * is selected will be the one listed in <a href="https://developer.android.com/reference/android/sensor/info/binningFactor.html">binningFactor</a>.</p>
+ * is selected will be the one listed in ACAMERA_SENSOR_INFO_BINNING_FACTOR.</p>
* </li>
* <li>
* <p>The following keys will always be present:</p>
@@ -5419,6 +5418,7 @@
* </ul>
*
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see ACAMERA_SENSOR_INFO_BINNING_FACTOR
* @see ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
*/
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index 17d7046..a19ef8e 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -90,9 +90,12 @@
status_t Overlay::stop() {
ALOGV("Overlay::stop");
- Mutex::Autolock _l(mMutex);
- mState = STOPPING;
- mEventCond.signal();
+ {
+ Mutex::Autolock _l(mMutex);
+ mState = STOPPING;
+ mEventCond.signal();
+ }
+ join();
return NO_ERROR;
}
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
new file mode 100644
index 0000000..01cd354
--- /dev/null
+++ b/media/codec2/hal/aidl/Android.bp
@@ -0,0 +1,149 @@
+package {
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-aidl-client-defaults instead
+cc_library {
+ name: "libcodec2_aidl_client",
+
+ srcs: [
+ "ParamTypes.cpp",
+ ],
+
+ header_libs: [
+ "libcodec2_hal_common",
+ "libcodec2_internal", // private
+ "libgui_headers",
+ ],
+
+ shared_libs: [
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.c2-V1-ndk",
+ "libbinder_ndk",
+ "libbase",
+ "libcodec2",
+ "libcodec2_vndk",
+ "libcutils",
+ "liblog",
+ "libnativewindow",
+ "libutils",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "android.hardware.media.c2-V1-ndk",
+ "libcodec2",
+ ],
+}
+
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-defaults instead
+//cc_library {
+// name: "libcodec2_hidl@1.0",
+// vendor_available: true,
+// min_sdk_version: "29",
+// apex_available: [
+// "//apex_available:platform",
+// "com.android.media.swcodec",
+// ],
+//
+// defaults: ["hidl_defaults"],
+//
+// srcs: [
+// "Component.cpp",
+// "ComponentInterface.cpp",
+// "ComponentStore.cpp",
+// "Configurable.cpp",
+// "InputBufferManager.cpp",
+// "InputSurface.cpp",
+// "InputSurfaceConnection.cpp",
+// "types.cpp",
+// ],
+//
+// header_libs: [
+// "libbinder_headers",
+// "libcodec2_hal_common",
+// "libcodec2_internal", // private
+// "libsystem_headers",
+// ],
+//
+// shared_libs: [
+// "android.hardware.graphics.bufferqueue@1.0",
+// "android.hardware.graphics.bufferqueue@2.0",
+// "android.hardware.graphics.common@1.0",
+// "android.hardware.media@1.0",
+// "android.hardware.media.bufferpool@2.0",
+// "android.hardware.media.c2@1.0",
+// "android.hardware.media.omx@1.0",
+// "libbase",
+// "libcodec2",
+// "libcodec2_vndk",
+// "libcodec2_hidl_plugin_stub",
+// "libcutils",
+// "libhidlbase",
+// "liblog",
+// "libstagefright_bufferpool@2.0.1",
+// "libstagefright_bufferqueue_helper_novndk",
+// "libui",
+// "libutils",
+// ],
+//
+// target: {
+// vendor: {
+// exclude_shared_libs: [
+// "libstagefright_bufferqueue_helper_novndk",
+// "libcodec2_hidl_plugin_stub",
+// ],
+// shared_libs: [
+// "libstagefright_bufferqueue_helper",
+// "libcodec2_hidl_plugin",
+// ],
+// },
+// apex: {
+// exclude_shared_libs: [
+// "libcodec2_hidl_plugin",
+// "libcodec2_hidl_plugin_stub",
+// ],
+// },
+// },
+//
+// export_include_dirs: [
+// "include",
+// ],
+//
+// export_shared_lib_headers: [
+// "android.hardware.media.c2@1.0",
+// "libcodec2",
+// "libcodec2_vndk",
+// "libhidlbase",
+// "libstagefright_bufferpool@2.0.1",
+// "libui",
+// ],
+//}
+//
+//// public dependency for Codec 2.0 HAL service implementations
+//cc_defaults {
+// name: "libcodec2-hidl-defaults@1.0",
+// defaults: ["libcodec2-impl-defaults"],
+//
+// shared_libs: [
+// "android.hardware.media.c2@1.0",
+// "libcodec2_hidl@1.0",
+// ],
+//}
+
+// public dependency for Codec 2.0 HAL client
+cc_defaults {
+ name: "libcodec2-aidl-client-defaults",
+ min_sdk_version: "34",
+ defaults: ["libcodec2-impl-defaults"],
+
+ shared_libs: [
+ "android.hardware.media.c2-V1-ndk",
+ "libcodec2_aidl_client",
+ ],
+}
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
new file mode 100644
index 0000000..319ba62
--- /dev/null
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -0,0 +1,1928 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-types"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/types.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2Component.h>
+#include <C2FenceFactory.h>
+#include <C2Param.h>
+#include <C2ParamInternal.h>
+#include <C2PlatformSupport.h>
+#include <C2Work.h>
+#include <util/C2ParamUtils.h>
+
+#include <algorithm>
+#include <functional>
+#include <iomanip>
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::media::bufferpool::BufferPoolData;
+using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
+using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ ClientManager;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ TransactionId;
+
+const char* asString(Status status, const char* def) {
+ return asString(static_cast<c2_status_t>(status), def);
+}
+
+namespace /* unnamed */ {
+
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(
+ EnumClass x) {
+ return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
+template <typename Common, typename DstVector, typename SrcVector>
+void copyVector(DstVector* d, const SrcVector& s) {
+ static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
+ "DstVector's component size does not match Common");
+ static_assert(sizeof(Common) == sizeof(decltype(s[0])),
+ "SrcVector's component size does not match Common");
+ d->resize(s.size());
+ std::copy(
+ reinterpret_cast<const Common*>(&s[0]),
+ reinterpret_cast<const Common*>(&s[0] + s.size()),
+ reinterpret_cast<Common*>(&(*d)[0]));
+}
+
+// C2ParamField -> ParamField
+bool objcpy(ParamField *d, const C2ParamField &s) {
+ d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
+ d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
+ d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+ return true;
+}
+
+struct C2ParamFieldBuilder : public C2ParamField {
+ C2ParamFieldBuilder() : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
+ }
+ // ParamField -> C2ParamField
+ C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
+ static_cast<uint32_t>(s.fieldId.offset),
+ static_cast<uint32_t>(s.fieldId.size)) {
+ }
+};
+
+// C2WorkOrdinalStruct -> WorkOrdinal
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+ d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
+ d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
+ d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+ return true;
+}
+
+// WorkOrdinal -> C2WorkOrdinalStruct
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+ d->frameIndex = c2_cntr64_t(s.frameIndex);
+ d->timestamp = c2_cntr64_t(s.timestampUs);
+ d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+ return true;
+}
+
+// C2FieldSupportedValues::range's type -> ValueRange
+bool objcpy(
+ ValueRange* d,
+ const decltype(C2FieldSupportedValues::range)& s) {
+ d->min = static_cast<PrimitiveValue>(s.min.u64);
+ d->max = static_cast<PrimitiveValue>(s.max.u64);
+ d->step = static_cast<PrimitiveValue>(s.step.u64);
+ d->num = static_cast<PrimitiveValue>(s.num.u64);
+ d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+ return true;
+}
+
+// C2FieldSupportedValues -> FieldSupportedValues
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+ switch (s.type) {
+ case C2FieldSupportedValues::EMPTY: {
+ d->empty(::android::hidl::safe_union::V1_0::Monostate{});
+ break;
+ }
+ case C2FieldSupportedValues::RANGE: {
+ ValueRange range{};
+ if (!objcpy(&range, s.range)) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+ d->range(range);
+ return false;
+ }
+ d->range(range);
+ break;
+ }
+ case C2FieldSupportedValues::VALUES: {
+ hidl_vec<PrimitiveValue> values;
+ copyVector<uint64_t>(&values, s.values);
+ d->values(values);
+ break;
+ }
+ case C2FieldSupportedValues::FLAGS: {
+ hidl_vec<PrimitiveValue> flags;
+ copyVector<uint64_t>(&flags, s.values);
+ d->flags(flags);
+ break;
+ }
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ return false;
+ }
+ return true;
+}
+
+// ValueRange -> C2FieldSupportedValues::range's type
+bool objcpy(
+ decltype(C2FieldSupportedValues::range)* d,
+ const ValueRange& s) {
+ d->min.u64 = static_cast<uint64_t>(s.min);
+ d->max.u64 = static_cast<uint64_t>(s.max);
+ d->step.u64 = static_cast<uint64_t>(s.step);
+ d->num.u64 = static_cast<uint64_t>(s.num);
+ d->denom.u64 = static_cast<uint64_t>(s.denom);
+ return true;
+}
+
+// FieldSupportedValues -> C2FieldSupportedValues
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+ switch (s.getDiscriminator()) {
+ case FieldSupportedValues::hidl_discriminator::empty: {
+ d->type = C2FieldSupportedValues::EMPTY;
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::range: {
+ d->type = C2FieldSupportedValues::RANGE;
+ if (!objcpy(&d->range, s.range())) {
+ LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+ return false;
+ }
+ d->values.resize(0);
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::values: {
+ d->type = C2FieldSupportedValues::VALUES;
+ copyVector<uint64_t>(&d->values, s.values());
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::flags: {
+ d->type = C2FieldSupportedValues::FLAGS;
+ copyVector<uint64_t>(&d->values, s.flags());
+ break;
+ }
+ default:
+ LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
+ return false;
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool objcpy(
+ FieldSupportedValuesQuery* d,
+ const C2FieldSupportedValuesQuery& s) {
+ if (!objcpy(&d->field, s.field())) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+ return false;
+ }
+ switch (s.type()) {
+ case C2FieldSupportedValuesQuery::POSSIBLE:
+ d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
+ break;
+ case C2FieldSupportedValuesQuery::CURRENT:
+ d->type = FieldSupportedValuesQuery::Type::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+ << "with underlying value " << underlying_value(s.type())
+ << ".";
+ d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
+ }
+ return true;
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s) {
+ C2FieldSupportedValuesQuery::type_t dType;
+ switch (s.type) {
+ case FieldSupportedValuesQuery::Type::POSSIBLE:
+ dType = C2FieldSupportedValuesQuery::POSSIBLE;
+ break;
+ case FieldSupportedValuesQuery::Type::CURRENT:
+ dType = C2FieldSupportedValuesQuery::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
+ }
+ *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
+ return true;
+}
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool objcpy(
+ FieldSupportedValuesQueryResult* d,
+ const C2FieldSupportedValuesQuery& s) {
+ d->status = static_cast<Status>(s.status);
+ return objcpy(&d->values, s.values);
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr) {
+ if (!objcpy(d, sq)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+ return false;
+ }
+ d->status = static_cast<c2_status_t>(sr.status);
+ if (!objcpy(&d->values, sr.values)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+ return false;
+ }
+ return true;
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+bool objcpy(
+ IComponentStore::ComponentTraits *d,
+ const C2Component::Traits &s) {
+ d->name = s.name;
+
+ switch (s.domain) {
+ case C2Component::DOMAIN_VIDEO:
+ d->domain = IComponentStore::ComponentTraits::Domain::VIDEO;
+ break;
+ case C2Component::DOMAIN_AUDIO:
+ d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
+ break;
+ case C2Component::DOMAIN_IMAGE:
+ d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
+ break;
+ case C2Component::DOMAIN_OTHER:
+ d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
+ s.domain);
+ }
+
+ switch (s.kind) {
+ case C2Component::KIND_DECODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::DECODER;
+ break;
+ case C2Component::KIND_ENCODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
+ break;
+ case C2Component::KIND_OTHER:
+ d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
+ s.kind);
+ }
+
+ d->rank = static_cast<uint32_t>(s.rank);
+
+ d->mediaType = s.mediaType;
+
+ d->aliases.resize(s.aliases.size());
+ for (size_t ix = s.aliases.size(); ix > 0; ) {
+ --ix;
+ d->aliases[ix] = s.aliases[ix];
+ }
+ return true;
+}
+
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+bool objcpy(
+ C2Component::Traits* d,
+ const IComponentStore::ComponentTraits& s) {
+ d->name = s.name.c_str();
+
+ switch (s.domain) {
+ case IComponentStore::ComponentTraits::Domain::VIDEO:
+ d->domain = C2Component::DOMAIN_VIDEO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::AUDIO:
+ d->domain = C2Component::DOMAIN_AUDIO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::IMAGE:
+ d->domain = C2Component::DOMAIN_IMAGE;
+ break;
+ case IComponentStore::ComponentTraits::Domain::OTHER:
+ d->domain = C2Component::DOMAIN_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<C2Component::domain_t>(s.domain);
+ }
+
+ switch (s.kind) {
+ case IComponentStore::ComponentTraits::Kind::DECODER:
+ d->kind = C2Component::KIND_DECODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::ENCODER:
+ d->kind = C2Component::KIND_ENCODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::OTHER:
+ d->kind = C2Component::KIND_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<C2Component::kind_t>(s.kind);
+ }
+
+ d->rank = static_cast<C2Component::rank_t>(s.rank);
+ d->mediaType = s.mediaType.c_str();
+ d->aliases.resize(s.aliases.size());
+ for (size_t i = 0; i < s.aliases.size(); ++i) {
+ d->aliases[i] = s.aliases[i];
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// C2ParamFieldValues -> ParamFieldValues
+bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+ if (!objcpy(&d->paramOrField, s.paramOrField)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+ return false;
+ }
+ if (s.values) {
+ d->values.resize(1);
+ if (!objcpy(&d->values[0], *s.values)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ }
+ d->values.resize(0);
+ return true;
+}
+
+// ParamFieldValues -> C2ParamFieldValues
+bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+ d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
+ if (s.values.size() == 1) {
+ d->values = std::make_unique<C2FieldSupportedValues>();
+ if (!objcpy(d->values.get(), s.values[0])) {
+ LOG(ERROR) << "Invalid ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ } else if (s.values.size() == 0) {
+ d->values.reset();
+ return true;
+ }
+ LOG(ERROR) << "Invalid ParamFieldValues: "
+ "Two or more FieldSupportedValues objects exist in "
+ "ParamFieldValues. "
+ "Only zero or one is allowed.";
+ return false;
+}
+
+} // unnamed namespace
+
+// C2SettingResult -> SettingResult
+bool objcpy(SettingResult *d, const C2SettingResult &s) {
+ switch (s.failure) {
+ case C2SettingResult::BAD_TYPE:
+ d->failure = SettingResult::Failure::BAD_TYPE;
+ break;
+ case C2SettingResult::BAD_PORT:
+ d->failure = SettingResult::Failure::BAD_PORT;
+ break;
+ case C2SettingResult::BAD_INDEX:
+ d->failure = SettingResult::Failure::BAD_INDEX;
+ break;
+ case C2SettingResult::READ_ONLY:
+ d->failure = SettingResult::Failure::READ_ONLY;
+ break;
+ case C2SettingResult::MISMATCH:
+ d->failure = SettingResult::Failure::MISMATCH;
+ break;
+ case C2SettingResult::BAD_VALUE:
+ d->failure = SettingResult::Failure::BAD_VALUE;
+ break;
+ case C2SettingResult::CONFLICT:
+ d->failure = SettingResult::Failure::CONFLICT;
+ break;
+ case C2SettingResult::UNSUPPORTED:
+ d->failure = SettingResult::Failure::UNSUPPORTED;
+ break;
+ case C2SettingResult::INFO_BAD_VALUE:
+ d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+ break;
+ case C2SettingResult::INFO_CONFLICT:
+ d->failure = SettingResult::Failure::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ d->failure = static_cast<SettingResult::Failure>(s.failure);
+ }
+ if (!objcpy(&d->field, s.field)) {
+ LOG(ERROR) << "Invalid C2SettingResult::field.";
+ return false;
+ }
+ d->conflicts.resize(s.conflicts.size());
+ size_t i = 0;
+ for (const C2ParamFieldValues& sConflict : s.conflicts) {
+ ParamFieldValues &dConflict = d->conflicts[i++];
+ if (!objcpy(&dConflict, sConflict)) {
+ LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+ return true;
+}
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+ *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
+ .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
+ if (!*d) {
+ LOG(ERROR) << "No memory for C2SettingResult.";
+ return false;
+ }
+
+ // failure
+ switch (s.failure) {
+ case SettingResult::Failure::BAD_TYPE:
+ (*d)->failure = C2SettingResult::BAD_TYPE;
+ break;
+ case SettingResult::Failure::BAD_PORT:
+ (*d)->failure = C2SettingResult::BAD_PORT;
+ break;
+ case SettingResult::Failure::BAD_INDEX:
+ (*d)->failure = C2SettingResult::BAD_INDEX;
+ break;
+ case SettingResult::Failure::READ_ONLY:
+ (*d)->failure = C2SettingResult::READ_ONLY;
+ break;
+ case SettingResult::Failure::MISMATCH:
+ (*d)->failure = C2SettingResult::MISMATCH;
+ break;
+ case SettingResult::Failure::BAD_VALUE:
+ (*d)->failure = C2SettingResult::BAD_VALUE;
+ break;
+ case SettingResult::Failure::CONFLICT:
+ (*d)->failure = C2SettingResult::CONFLICT;
+ break;
+ case SettingResult::Failure::UNSUPPORTED:
+ (*d)->failure = C2SettingResult::UNSUPPORTED;
+ break;
+ case SettingResult::Failure::INFO_BAD_VALUE:
+ (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+ break;
+ case SettingResult::Failure::INFO_CONFLICT:
+ (*d)->failure = C2SettingResult::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
+ }
+
+ // field
+ if (!objcpy(&(*d)->field, s.field)) {
+ LOG(ERROR) << "Invalid SettingResult::field.";
+ return false;
+ }
+
+ // conflicts
+ (*d)->conflicts.clear();
+ (*d)->conflicts.reserve(s.conflicts.size());
+ for (const ParamFieldValues& sConflict : s.conflicts) {
+ (*d)->conflicts.emplace_back(
+ C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
+ if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+ LOG(ERROR) << "Invalid SettingResult::conflicts.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+ d->index = static_cast<ParamIndex>(s.index());
+ d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
+ _C2ParamInspector::GetAttrib(s));
+ d->name = s.name();
+ copyVector<uint32_t>(&d->dependencies, s.dependencies());
+ return true;
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+ std::vector<C2Param::Index> dDependencies;
+ dDependencies.reserve(s.dependencies.size());
+ for (const ParamIndex& sDependency : s.dependencies) {
+ dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
+ }
+ *d = std::make_shared<C2ParamDescriptor>(
+ C2Param::Index(static_cast<uint32_t>(s.index)),
+ static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
+ C2String(s.name.c_str()),
+ std::move(dDependencies));
+ return true;
+}
+
+// C2StructDescriptor -> StructDescriptor
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+ d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
+ d->fields.resize(s.numFields());
+ size_t i = 0;
+ for (const auto& sField : s) {
+ FieldDescriptor& dField = d->fields[i++];
+ dField.fieldId.offset = static_cast<uint32_t>(
+ _C2ParamInspector::GetOffset(sField));
+ dField.fieldId.size = static_cast<uint32_t>(
+ _C2ParamInspector::GetSize(sField));
+ dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
+ sField.type());
+ dField.extent = static_cast<uint32_t>(sField.extent());
+ dField.name = static_cast<hidl_string>(sField.name());
+ const auto& sNamedValues = sField.namedValues();
+ dField.namedValues.resize(sNamedValues.size());
+ size_t j = 0;
+ for (const auto& sNamedValue : sNamedValues) {
+ FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
+ dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
+ dNamedValue.value = static_cast<PrimitiveValue>(
+ sNamedValue.second.u64);
+ }
+ }
+ return true;
+}
+
+// StructDescriptor -> C2StructDescriptor
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+ C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
+ std::vector<C2FieldDescriptor> dFields;
+ dFields.reserve(s.fields.size());
+ for (const auto &sField : s.fields) {
+ C2FieldDescriptor dField = {
+ static_cast<uint32_t>(sField.type),
+ sField.extent,
+ sField.name,
+ sField.fieldId.offset,
+ sField.fieldId.size };
+ C2FieldDescriptor::NamedValuesType namedValues;
+ namedValues.reserve(sField.namedValues.size());
+ for (const auto& sNamedValue : sField.namedValues) {
+ namedValues.emplace_back(
+ sNamedValue.name,
+ C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
+ }
+ _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
+ dFields.emplace_back(dField);
+ }
+ *d = std::make_unique<C2StructDescriptor>(
+ _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
+// associated map.
+// Note: The handle is not cloned.
+bool _addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!handle) {
+ LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(handle);
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(handle, *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+ // This does not clone the handle.
+ dBaseBlock.nativeBlock(
+ reinterpret_cast<const native_handle_t*>(handle));
+
+ }
+ return true;
+}
+
+// Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
+// an associated map.
+bool _addBaseBlock(
+ uint32_t* index,
+ const std::shared_ptr<BufferPoolData> bpData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!bpData) {
+ LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(bpData.get());
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(bpData.get(), *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+
+ if (bufferPoolSender) {
+ BufferStatusMessage pooledBlock;
+ ResultStatus bpStatus = bufferPoolSender->send(
+ bpData,
+ &pooledBlock);
+
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
+ << static_cast<int32_t>(bpStatus)
+ << ".";
+ return false;
+ }
+ dBaseBlock.pooledBlock(pooledBlock);
+ }
+ }
+ return true;
+}
+
+bool addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!blockPoolData) {
+ // No BufferPoolData ==> NATIVE block.
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ }
+ switch (blockPoolData->getType()) {
+ case _C2BlockPoolData::TYPE_BUFFERPOOL: {
+ // BufferPoolData
+ std::shared_ptr<BufferPoolData> bpData;
+ if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
+ || !bpData) {
+ LOG(ERROR) << "BufferPoolData unavailable in a block.";
+ return false;
+ }
+ return _addBaseBlock(
+ index, bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices);
+ }
+ case _C2BlockPoolData::TYPE_BUFFERQUEUE:
+ uint32_t gen;
+ uint64_t bqId;
+ int32_t bqSlot;
+ // Update handle if migration happened.
+ if (_C2BlockFactory::GetBufferQueueData(
+ blockPoolData, &gen, &bqId, &bqSlot)) {
+ android::MigrateNativeCodec2GrallocHandle(
+ const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
+ }
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ default:
+ LOG(ERROR) << "Unknown C2BlockPoolData type.";
+ return false;
+ }
+}
+
+// C2Fence -> hidl_handle
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(hidl_handle* d, const C2Fence& s) {
+ d->setTo(nullptr);
+ native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
+ if (handle) {
+ d->setTo(handle, true /* owns */);
+// } else if (!s.ready()) {
+// // TODO: we should wait for unmarshallable fences but this may not be
+// // the best place for it. We can safely ignore here as at this time
+// // all fences used here are marshallable.
+ }
+ return true;
+}
+
+// C2ConstLinearBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstLinearBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetLinearBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RangeInfo dRangeInfo;
+ dRangeInfo.offset = static_cast<uint32_t>(s.offset());
+ dRangeInfo.length = static_cast<uint32_t>(s.size());
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
+ LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2ConstGraphicBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstGraphicBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetGraphicBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RectInfo dRectInfo;
+ C2Rect sRect = s.crop();
+ dRectInfo.left = static_cast<uint32_t>(sRect.left);
+ dRectInfo.top = static_cast<uint32_t>(sRect.top);
+ dRectInfo.width = static_cast<uint32_t>(sRect.width);
+ dRectInfo.height = static_cast<uint32_t>(sRect.height);
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
+ LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2BufferData -> Buffer
+// This function only fills in d->blocks.
+bool objcpy(Buffer* d, const C2BufferData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->blocks.resize(
+ s.linearBlocks().size() +
+ s.graphicBlocks().size());
+ size_t i = 0;
+ for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, linearBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, graphicBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2Buffer -> Buffer
+bool objcpy(Buffer* d, const C2Buffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!createParamsBlob(&d->info, s.info())) {
+ LOG(ERROR) << "Invalid C2Buffer::info.";
+ return false;
+ }
+ if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Buffer::data.";
+ return false;
+ }
+ return true;
+}
+
+// C2InfoBuffer -> InfoBuffer
+bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->index = static_cast<ParamIndex>(s.index());
+ Buffer& dBuffer = d->buffer;
+ if (!objcpy(&dBuffer, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2InfoBuffer::data";
+ return false;
+ }
+ return true;
+}
+
+// C2FrameData -> FrameData
+bool objcpy(FrameData* d, const C2FrameData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid C2FrameData::ordinal.";
+ return false;
+ }
+
+ d->buffers.resize(s.buffers.size());
+ size_t i = 0;
+ for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
+ Buffer& dBuffer = d->buffers[i++];
+ if (!sBuffer) {
+ // A null (pointer to) C2Buffer corresponds to a Buffer with empty
+ // info and blocks.
+ dBuffer.info.resize(0);
+ dBuffer.blocks.resize(0);
+ continue;
+ }
+ if (!objcpy(
+ &dBuffer, *sBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::buffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
+ LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
+ return false;
+ }
+
+ d->infoBuffers.resize(s.infoBuffers.size());
+ i = 0;
+ for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
+ InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
+ if (!objcpy(&dInfoBuffer, sInfoBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // unnamed namespace
+
+// DefaultBufferPoolSender's implementation
+
+DefaultBufferPoolSender::DefaultBufferPoolSender(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval)
+ : mReceiverManager(receiverManager),
+ mRefreshInterval(refreshInterval) {
+}
+
+void DefaultBufferPoolSender::setReceiver(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mReceiverManager != receiverManager) {
+ mReceiverManager = receiverManager;
+ mConnections.clear();
+ }
+ mRefreshInterval = refreshInterval;
+}
+
+ResultStatus DefaultBufferPoolSender::send(
+ const std::shared_ptr<BufferPoolData>& bpData,
+ BufferStatusMessage* bpMessage) {
+ int64_t connectionId = bpData->mConnectionId;
+ if (connectionId == 0) {
+ LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mReceiverManager) {
+ LOG(ERROR) << "No access to receiver's BufferPool.";
+ return ResultStatus::NOT_FOUND;
+ }
+ if (!mSenderManager) {
+ mSenderManager = ClientManager::getInstance();
+ if (!mSenderManager) {
+ LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ }
+
+ int64_t receiverConnectionId{0};
+ auto foundConnection = mConnections.find(connectionId);
+ bool isNewConnection = foundConnection == mConnections.end();
+ std::chrono::steady_clock::time_point now =
+ std::chrono::steady_clock::now();
+ if (isNewConnection ||
+ (now - foundConnection->second.lastSent > mRefreshInterval)) {
+ // Initialize the bufferpool connection.
+ ResultStatus rs =
+ mSenderManager->registerSender(mReceiverManager,
+ connectionId,
+ &receiverConnectionId);
+ if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
+ LOG(WARNING) << "registerSender -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ return rs;
+ } else if (receiverConnectionId == 0) {
+ LOG(WARNING) << "registerSender -- "
+ "invalid receiver connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ } else {
+ if (isNewConnection) {
+ foundConnection = mConnections.try_emplace(
+ connectionId, receiverConnectionId, now).first;
+ } else {
+ foundConnection->second.receiverConnectionId = receiverConnectionId;
+ }
+ }
+ } else {
+ receiverConnectionId = foundConnection->second.receiverConnectionId;
+ }
+
+ uint64_t transactionId;
+ int64_t timestampUs;
+ ResultStatus rs = mSenderManager->postSend(
+ receiverConnectionId, bpData, &transactionId, ×tampUs);
+ if (rs != ResultStatus::OK) {
+ LOG(ERROR) << "ClientManager::postSend -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ mConnections.erase(foundConnection);
+ return rs;
+ }
+ if (!bpMessage) {
+ LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
+ mConnections.erase(foundConnection);
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ bpMessage->connectionId = receiverConnectionId;
+ bpMessage->bufferId = bpData->mId;
+ bpMessage->transactionId = transactionId;
+ bpMessage->timestampUs = timestampUs;
+ foundConnection->second.lastSent = now;
+ return rs;
+}
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+bool objcpy(
+ WorkBundle* d,
+ const std::list<std::unique_ptr<C2Work>>& s,
+ BufferPoolSender* bufferPoolSender) {
+ // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
+ std::list<BaseBlock> baseBlocks;
+
+ // baseBlockIndices maps a raw pointer to native_handle_t or BufferPoolData
+ // inside baseBlocks to the corresponding index into baseBlocks. The keys
+ // (pointers) are used to identify blocks that have the same "base block" in
+ // s, a list of C2Work objects. Because baseBlocks will be copied into a
+ // hidl_vec eventually, the values of baseBlockIndices are zero-based
+ // integer indices instead of list iterators.
+ //
+ // Note that the pointers can be raw because baseBlockIndices has a shorter
+ // lifespan than all of base blocks.
+ std::map<const void*, uint32_t> baseBlockIndices;
+
+ d->works.resize(s.size());
+ size_t i = 0;
+ for (const std::unique_ptr<C2Work>& sWork : s) {
+ Work &dWork = d->works[i++];
+ if (!sWork) {
+ LOG(WARNING) << "Null C2Work encountered.";
+ continue;
+ }
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork->input,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::input.";
+ return false;
+ }
+
+ // worklets
+ if (sWork->worklets.size() == 0) {
+ LOG(DEBUG) << "Work with no worklets.";
+ } else {
+ // Parcel the worklets.
+ hidl_vec<Worklet> &dWorklets = dWork.worklets;
+ dWorklets.resize(sWork->worklets.size());
+ size_t j = 0;
+ for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
+ {
+ if (!sWorklet) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j << "].";
+ continue;
+ }
+ Worklet &dWorklet = dWorklets[j++];
+
+ // component id
+ dWorklet.componentId = static_cast<uint32_t>(
+ sWorklet->component);
+
+ // tunings
+ if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->tunings.";
+ return false;
+ }
+
+ // failures
+ dWorklet.failures.resize(sWorklet->failures.size());
+ size_t k = 0;
+ for (const std::unique_ptr<C2SettingResult>& sFailure :
+ sWorklet->failures) {
+ if (!sFailure) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k << "].";
+ continue;
+ }
+ if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k - 1 << "].";
+ return false;
+ }
+ }
+
+ // output
+ if (!objcpy(&dWorklet.output, sWorklet->output,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->output.";
+ return false;
+ }
+ }
+ }
+
+ // worklets processed
+ dWork.workletsProcessed = sWork->workletsProcessed;
+
+ // result
+ dWork.result = static_cast<Status>(sWork->result);
+ }
+
+ // Copy std::list<BaseBlock> to hidl_vec<BaseBlock>.
+ {
+ d->baseBlocks.resize(baseBlocks.size());
+ size_t i = 0;
+ for (const BaseBlock& baseBlock : baseBlocks) {
+ d->baseBlocks[i++] = baseBlock;
+ }
+ }
+
+ return true;
+}
+
+namespace /* unnamed */ {
+
+struct C2BaseBlock {
+ enum type_t {
+ LINEAR,
+ GRAPHIC,
+ };
+ type_t type;
+ std::shared_ptr<C2LinearBlock> linear;
+ std::shared_ptr<C2GraphicBlock> graphic;
+};
+
+// hidl_handle -> C2Fence
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(C2Fence* d, const hidl_handle& s) {
+ const native_handle_t* handle = s.getNativeHandle();
+ *d = _C2FenceFactory::CreateFromNativeHandle(handle);
+ return true;
+}
+
+// C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createLinearBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2LinearBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RangeInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2LinearBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
+ LOG(ERROR) << "Invalid range info in C2LinearBlock.";
+ return false;
+ }
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
+
+ // Create C2Buffer from C2LinearBlock.
+ *buffer = C2Buffer::CreateLinearBuffer(block->share(
+ rangeInfo->offset, rangeInfo->length,
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateLinearBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createGraphicBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2GraphicBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RectInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
+ LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
+ return false;
+ }
+ C2Hidl_RectInfo *rectInfo =
+ reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
+
+ // Create C2Buffer from C2GraphicBlock.
+ *buffer = C2Buffer::CreateGraphicBuffer(block->share(
+ C2Rect(rectInfo->width, rectInfo->height).
+ at(rectInfo->left, rectInfo->top),
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateGraphicBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// Buffer -> C2Buffer
+// Note: The native handles will be cloned.
+bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ *d = nullptr;
+
+ // Currently, a non-null C2Buffer must contain exactly 1 block.
+ if (s.blocks.size() == 0) {
+ return true;
+ } else if (s.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid Buffer: "
+ "Currently, a C2Buffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::linear.";
+ return false;
+ }
+ break;
+ case C2BaseBlock::GRAPHIC:
+ if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
+ return false;
+ }
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type.";
+ return false;
+ }
+
+ // Parse info
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.info)) {
+ LOG(ERROR) << "Invalid Buffer::info.";
+ return false;
+ }
+ for (C2Param* param : params) {
+ if (param == nullptr) {
+ LOG(ERROR) << "Null param in Buffer::info.";
+ return false;
+ }
+ std::shared_ptr<C2Param> c2param{
+ C2Param::Copy(*param).release()};
+ if (!c2param) {
+ LOG(ERROR) << "Invalid param in Buffer::info.";
+ return false;
+ }
+ c2_status_t status =
+ (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+ if (status != C2_OK) {
+ LOG(ERROR) << "C2Buffer::setInfo failed.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// InfoBuffer -> C2InfoBuffer
+bool objcpy(std::vector<C2InfoBuffer> *d, const InfoBuffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+
+ // Currently, a non-null C2InfoBufer must contain exactly 1 block.
+ if (s.buffer.blocks.size() == 0) {
+ return true;
+ } else if (s.buffer.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer "
+ "Currently, a C2InfoBuffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.buffer.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (sBlockMeta.size() == 1 && sBlockMeta[0] != nullptr &&
+ sBlockMeta[0]->size() == sizeof(C2Hidl_RangeInfo)) {
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(sBlockMeta[0]);
+ d->emplace_back(C2InfoBuffer::CreateLinearBuffer(
+ s.index,
+ baseBlock.linear->share(
+ rangeInfo->offset, rangeInfo->length, dFence)));
+ return true;
+ }
+ LOG(ERROR) << "Invalid Meta for C2BaseBlock::Linear InfoBuffer.";
+ break;
+ case C2BaseBlock::GRAPHIC:
+ // It's not used now
+ LOG(ERROR) << "Non-Used C2BaseBlock::type for InfoBuffer.";
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type for InfoBuffer.";
+ break;
+ }
+
+ return false;
+}
+
+// FrameData -> C2FrameData
+bool objcpy(C2FrameData* d, const FrameData& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ d->flags = static_cast<C2FrameData::flags_t>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid FrameData::ordinal.";
+ return false;
+ }
+ d->buffers.clear();
+ d->buffers.reserve(s.buffers.size());
+ for (const Buffer& sBuffer : s.buffers) {
+ std::shared_ptr<C2Buffer> dBuffer;
+ if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid FrameData::buffers.";
+ return false;
+ }
+ d->buffers.emplace_back(dBuffer);
+ }
+
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.configUpdate)) {
+ LOG(ERROR) << "Invalid FrameData::configUpdate.";
+ return false;
+ }
+ d->configUpdate.clear();
+ for (C2Param* param : params) {
+ d->configUpdate.emplace_back(C2Param::Copy(*param));
+ if (!d->configUpdate.back()) {
+ LOG(ERROR) << "Unexpected error while parsing "
+ "FrameData::configUpdate.";
+ return false;
+ }
+ }
+
+ d->infoBuffers.clear();
+ if (s.infoBuffers.size() == 0) {
+ // InfoBuffer is optional
+ return true;
+ }
+ d->infoBuffers.reserve(s.infoBuffers.size());
+ for (const InfoBuffer &sInfoBuffer: s.infoBuffers) {
+ if (!objcpy(&(d->infoBuffers), sInfoBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid Framedata::infoBuffers.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// BaseBlock -> C2BaseBlock
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+ switch (s.getDiscriminator()) {
+ case BaseBlock::hidl_discriminator::nativeBlock: {
+ if (s.nativeBlock() == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
+ return false;
+ }
+ native_handle_t* sHandle =
+ native_handle_clone(s.nativeBlock());
+ if (sHandle == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+ return false;
+ }
+ const C2Handle *sC2Handle =
+ reinterpret_cast<const C2Handle*>(sHandle);
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
+ if (sHandle) {
+ native_handle_close(sHandle);
+ native_handle_delete(sHandle);
+ }
+ return false;
+ }
+ case BaseBlock::hidl_discriminator::pooledBlock: {
+ const BufferStatusMessage &bpMessage =
+ s.pooledBlock();
+ sp<ClientManager> bp = ClientManager::getInstance();
+ std::shared_ptr<BufferPoolData> bpData;
+ native_handle_t *cHandle;
+ ResultStatus bpStatus = bp->receive(
+ bpMessage.connectionId,
+ bpMessage.transactionId,
+ bpMessage.bufferId,
+ bpMessage.timestampUs,
+ &cHandle,
+ &bpData);
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+ << "resultStatus = " << underlying_value(bpStatus)
+ << ".";
+ return false;
+ } else if (!bpData) {
+ LOG(ERROR) << "No data in bufferpool transaction.";
+ return false;
+ }
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+ if (cHandle) {
+ // Though we got cloned handle, creating block failed.
+ native_handle_close(cHandle);
+ native_handle_delete(cHandle);
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+ return false;
+ }
+ default:
+ LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+ << "underlying value "
+ << underlying_value(s.getDiscriminator()) << ".";
+ return false;
+ }
+}
+
+} // unnamed namespace
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
+ // Convert BaseBlocks to C2BaseBlocks.
+ std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
+ for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
+ if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
+ LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
+ << i << "].";
+ return false;
+ }
+ }
+
+ d->clear();
+ for (const Work& sWork : s.works) {
+ d->emplace_back(std::make_unique<C2Work>());
+ C2Work& dWork = *d->back();
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Work::input.";
+ return false;
+ }
+
+ // worklet(s)
+ dWork.worklets.clear();
+ for (const Worklet& sWorklet : sWork.worklets) {
+ std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
+
+ // component id
+ dWorklet->component = static_cast<c2_node_id_t>(
+ sWorklet.componentId);
+
+ // tunings
+ if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
+ LOG(ERROR) << "Invalid Worklet::tunings";
+ return false;
+ }
+
+ // failures
+ dWorklet->failures.clear();
+ dWorklet->failures.reserve(sWorklet.failures.size());
+ for (const SettingResult& sFailure : sWorklet.failures) {
+ std::unique_ptr<C2SettingResult> dFailure;
+ if (!objcpy(&dFailure, sFailure)) {
+ LOG(ERROR) << "Invalid Worklet::failures.";
+ return false;
+ }
+ dWorklet->failures.emplace_back(std::move(dFailure));
+ }
+
+ // output
+ if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Worklet::output.";
+ return false;
+ }
+
+ dWork.worklets.emplace_back(std::move(dWorklet));
+ }
+
+ // workletsProcessed
+ dWork.workletsProcessed = sWork.workletsProcessed;
+
+ // result
+ dWork.result = static_cast<c2_status_t>(sWork.result);
+ }
+
+ return true;
+}
+
+constexpr size_t PARAMS_ALIGNMENT = 8; // 64-bit alignment
+static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
+
+// Params -> std::vector<C2Param*>
+bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+ // assuming blob is const here
+ size_t size = blob.size();
+ size_t ix = 0;
+ size_t old_ix = 0;
+ const uint8_t *data = blob.data();
+ C2Param *p = nullptr;
+
+ do {
+ p = C2ParamUtils::ParseFirst(data + ix, size - ix);
+ if (p) {
+ params->emplace_back(p);
+ old_ix = ix;
+ ix += p->size();
+ ix = align(ix, PARAMS_ALIGNMENT);
+ if (ix <= old_ix || ix > size) {
+ android_errorWriteLog(0x534e4554, "238083570");
+ break;
+ }
+ }
+ } while (p);
+
+ if (ix != size) {
+ LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+/**
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval C2_OK if the blob was successfully created
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ * happens if the parameters were not const)
+ */
+template <typename T>
+bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
+ // assuming the parameter values are const
+ size_t size = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ size += p->size();
+ size = align(size, PARAMS_ALIGNMENT);
+ }
+ blob->resize(size);
+ size_t ix = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ // NEVER overwrite even if param values (e.g. size) changed
+ size_t paramSize = std::min(p->size(), size - ix);
+ std::copy(
+ reinterpret_cast<const uint8_t*>(&*p),
+ reinterpret_cast<const uint8_t*>(&*p) + paramSize,
+ &(*blob)[ix]);
+ ix += paramSize;
+ ix = align(ix, PARAMS_ALIGNMENT);
+ }
+ blob->resize(ix);
+ if (ix != size) {
+ LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename T>
+bool _copyParamsFromBlob(
+ std::vector<std::unique_ptr<T>>* params,
+ Params blob) {
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ params->resize(paramPointers.size());
+ size_t i = 0;
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+ return false;
+ }
+ (*params)[i++].reset(reinterpret_cast<T*>(
+ C2Param::Copy(*paramPointer).release()));
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// std::vector<const C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<const C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Param>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Param>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Tuning>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::shared_ptr<const C2Info>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Param>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Param>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+bool updateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& blob) {
+ std::unordered_map<uint32_t, C2Param*> index2param;
+ for (C2Param* const& param : params) {
+ if (!param) {
+ LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+ return false;
+ }
+ if (index2param.find(param->index()) == index2param.end()) {
+ index2param.emplace(param->index(), param);
+ }
+ }
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+ return false;
+ }
+ decltype(index2param)::iterator i = index2param.find(
+ paramPointer->index());
+ if (i == index2param.end()) {
+ LOG(DEBUG) << "updateParamsFromBlob -- index "
+ << paramPointer->index() << " not found. Skipping...";
+ continue;
+ }
+ if (!i->second->updateFrom(*paramPointer)) {
+ LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+ << params.size() << " vs " << paramPointer->size()
+ << " (index = " << i->first << ").";
+ return false;
+ }
+ }
+ return true;
+}
+
+// Convert BufferPool ResultStatus to c2_status_t.
+c2_status_t toC2Status(ResultStatus rs) {
+ switch (rs) {
+ case ResultStatus::OK:
+ return C2_OK;
+ case ResultStatus::NO_MEMORY:
+ return C2_NO_MEMORY;
+ case ResultStatus::ALREADY_EXISTS:
+ return C2_DUPLICATE;
+ case ResultStatus::NOT_FOUND:
+ return C2_NOT_FOUND;
+ case ResultStatus::CRITICAL_ERROR:
+ return C2_CORRUPTED;
+ default:
+ LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
+ << static_cast<int32_t>(rs) << ".";
+ return C2_CORRUPTED;
+ }
+}
+
+namespace /* unnamed */ {
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+ BlockProcessor process) {
+ for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+ if (buffer) {
+ for (const C2ConstGraphicBlock& block :
+ buffer->data().graphicBlocks()) {
+ process(block);
+ }
+ }
+ }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+ BlockProcessor process,
+ bool processInput, bool processOutput) {
+ for (const std::unique_ptr<C2Work>& work : workList) {
+ if (!work) {
+ continue;
+ }
+ if (processInput) {
+ forEachBlock(work->input, process);
+ }
+ if (processOutput) {
+ for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+ if (worklet) {
+ forEachBlock(worklet->output,
+ process);
+ }
+ }
+ }
+ }
+}
+
+} // unnamed namespace
+
+bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::BeginTransferBlockToClient(data);
+ return true;
+ }
+ return false;
+}
+
+void beginTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList, beginTransferBufferQueueBlock,
+ processInput, processOutput);
+}
+
+bool endTransferBufferQueueBlock(
+ const C2ConstGraphicBlock& block,
+ bool transfer) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::EndTransferBlockToClient(data, transfer);
+ return true;
+ }
+ return false;
+}
+
+void endTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool transfer,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList,
+ std::bind(endTransferBufferQueueBlock,
+ std::placeholders::_1, transfer),
+ processInput, processOutput);
+}
+
+bool displayBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::DisplayBlockToBufferQueue(data);
+ return true;
+ }
+ return false;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hal/aidl/ParamTypes-specialization.h b/media/codec2/hal/aidl/ParamTypes-specialization.h
new file mode 100644
index 0000000..e409b34
--- /dev/null
+++ b/media/codec2/hal/aidl/ParamTypes-specialization.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_AIDL_UTILS_PARAM_TYPES_SPECIALIZATIONS_H
+#define CODEC2_AIDL_UTILS_PARAM_TYPES_SPECIALIZATIONS_H
+
+#include <aidl/android/hardware/media/c2/FieldId.h>
+#include <aidl/android/hardware/media/c2/FieldSupportedValues.h>
+#include <aidl/android/hardware/media/c2/Params.h>
+#include <aidl/android/hardware/media/c2/Status.h>
+#include <codec2/common/ParamTypes.h>
+
+namespace android {
+
+using ::aidl::android::hardware::media::c2::FieldId;
+using ::aidl::android::hardware::media::c2::FieldSupportedValues;
+using ::aidl::android::hardware::media::c2::Params;
+using ::aidl::android::hardware::media::c2::Status;
+
+// {offset, size} -> FieldId
+template<>
+void SetFieldId(FieldId *d, uint32_t offset, uint32_t size);
+
+// FieldId -> offset
+template<>
+uint32_t GetOffsetFromFieldId(const FieldId &s);
+
+// FieldId -> size
+template<>
+uint32_t GetSizeFromFieldId(const FieldId &s);
+
+template<>
+void SetStatus(Status *dst, c2_status_t src);
+
+template<>
+c2_status_t GetStatus(const Status &status);
+
+// C2FieldSupportedValues -> FieldSupportedValues
+template<>
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s);
+
+// FieldSupportedValues -> C2FieldSupportedValues
+template<>
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s);
+
+template<>
+struct _ParamsBlobHelper<Params> { typedef std::vector<uint8_t> BlobType; };
+
+template<>
+const std::vector<uint8_t> &GetBlob<Params>(const Params ¶ms);
+
+template<>
+std::vector<uint8_t> *GetBlob<Params>(Params *params);
+
+} // namespace android
+
+
+
+#endif // CODEC2_AIDL_UTILS_PARAM_TYPES_SPECIALIZATIONS_H
diff --git a/media/codec2/hal/aidl/ParamTypes.cpp b/media/codec2/hal/aidl/ParamTypes.cpp
new file mode 100644
index 0000000..0a430f9
--- /dev/null
+++ b/media/codec2/hal/aidl/ParamTypes.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-AIDL-ParamTypes"
+#include <android-base/logging.h>
+
+#include <codec2/aidl/ParamTypes.h>
+#include <codec2/common/ParamTypes.h>
+
+#include "ParamTypes-specialization.h"
+
+namespace android {
+
+using ::aidl::android::hardware::media::c2::FieldId;
+using ::aidl::android::hardware::media::c2::FieldSupportedValues;
+using ::aidl::android::hardware::media::c2::Params;
+using ::aidl::android::hardware::media::c2::Status;
+using ::aidl::android::hardware::media::c2::ValueRange;
+
+// {offset, size} -> FieldId
+template<>
+void SetFieldId(FieldId *d, uint32_t offset, uint32_t size) {
+ d->offset = offset;
+ d->sizeBytes = size;
+}
+
+// FieldId -> offset
+template<>
+uint32_t GetOffsetFromFieldId(const FieldId &s) {
+ return s.offset;
+}
+
+// FieldId -> size
+template<>
+uint32_t GetSizeFromFieldId(const FieldId &s) {
+ return s.sizeBytes;
+}
+
+template<>
+void SetStatus(Status *dst, c2_status_t src) {
+ dst->status = src;
+}
+
+template<>
+c2_status_t GetStatus(const Status &status) {
+ return static_cast<c2_status_t>(status.status);
+}
+
+static constexpr FieldSupportedValues::Tag EMPTY = FieldSupportedValues::empty;
+static constexpr FieldSupportedValues::Tag RANGE = FieldSupportedValues::range;
+static constexpr FieldSupportedValues::Tag VALUES = FieldSupportedValues::values;
+static constexpr FieldSupportedValues::Tag FLAGS = FieldSupportedValues::flags;
+
+// C2FieldSupportedValues -> FieldSupportedValues
+template<>
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+ switch (s.type) {
+ case C2FieldSupportedValues::EMPTY: {
+ d->set<EMPTY>(true);
+ break;
+ }
+ case C2FieldSupportedValues::RANGE: {
+ ValueRange range{};
+ if (!objcpy(&range, s.range)) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+ d->set<RANGE>(range);
+ return false;
+ }
+ d->set<RANGE>(range);
+ break;
+ }
+ case C2FieldSupportedValues::VALUES: {
+ std::vector<int64_t> values;
+ copyVector<int64_t>(&values, s.values);
+ d->set<VALUES>(values);
+ break;
+ }
+ case C2FieldSupportedValues::FLAGS: {
+ std::vector<int64_t> flags;
+ copyVector<int64_t>(&flags, s.values);
+ d->set<FLAGS>(flags);
+ break;
+ }
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ return false;
+ }
+ return true;
+}
+
+// FieldSupportedValues -> C2FieldSupportedValues
+template<>
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+ switch (s.getTag()) {
+ case FieldSupportedValues::empty: {
+ d->type = C2FieldSupportedValues::EMPTY;
+ break;
+ }
+ case FieldSupportedValues::range: {
+ d->type = C2FieldSupportedValues::RANGE;
+ if (!objcpy(&d->range, s.get<RANGE>())) {
+ LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+ return false;
+ }
+ d->values.resize(0);
+ break;
+ }
+ case FieldSupportedValues::values: {
+ d->type = C2FieldSupportedValues::VALUES;
+ copyVector<uint64_t>(&d->values, s.get<VALUES>());
+ break;
+ }
+ case FieldSupportedValues::flags: {
+ d->type = C2FieldSupportedValues::FLAGS;
+ copyVector<uint64_t>(&d->values, s.get<FLAGS>());
+ break;
+ }
+ default:
+ LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
+ return false;
+ }
+ return true;
+}
+
+template<>
+const std::vector<uint8_t> &GetBlob<Params>(const Params ¶ms) {
+ return params.params;
+}
+
+template<>
+std::vector<uint8_t> *GetBlob<Params>(Params *params) {
+ return ¶ms->params;
+}
+
+} // namespace android
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace utils {
+
+const char* asString(Status status, const char* def) {
+ return asString(static_cast<c2_status_t>(status.status), def);
+}
+
+namespace /* unnamed */ {
+
+} // unnamed namespace
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool ToAidl(
+ FieldSupportedValuesQuery* d,
+ const C2FieldSupportedValuesQuery& s) {
+ return ::android::objcpy(d, nullptr, s);
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool FromAidl(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s) {
+ return ::android::objcpy(d, s);
+}
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool ToAidl(
+ FieldSupportedValuesQueryResult* d,
+ const C2FieldSupportedValuesQuery& s) {
+ return ::android::objcpy(nullptr, d, s);
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+bool FromAidl(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr) {
+ return ::android::objcpy(d, sq, sr);
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+bool ToAidl(
+ IComponentStore::ComponentTraits *d,
+ const C2Component::Traits &s) {
+ return ::android::objcpy(d, s);
+}
+
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+bool FromAidl(
+ C2Component::Traits* d,
+ const IComponentStore::ComponentTraits& s) {
+ return ::android::objcpy(d, s);
+}
+
+// C2SettingResult -> SettingResult
+bool ToAidl(SettingResult *d, const C2SettingResult &s) {
+ return ::android::objcpy(d, s);
+}
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool FromAidl(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+ return ::android::objcpy(d, s);
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+bool ToAidl(ParamDescriptor *d, const C2ParamDescriptor &s) {
+ return ::android::objcpy(d, s);
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+bool FromAidl(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+ return ::android::objcpy(d, s);
+}
+
+// C2StructDescriptor -> StructDescriptor
+bool ToAidl(StructDescriptor *d, const C2StructDescriptor &s) {
+ return ::android::objcpy(d, s);
+}
+
+// StructDescriptor -> C2StructDescriptor
+bool FromAidl(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+ return ::android::objcpy(d, s);
+}
+
+// Params -> std::vector<C2Param*>
+bool ParseParamsBlob(std::vector<C2Param*> *params, const Params &blob) {
+ return ::android::parseParamsBlob(params, blob);
+}
+
+// std::vector<const C2Param*> -> Params
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<const C2Param*> ¶ms) {
+ return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<C2Param*> -> Params
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<C2Param*> ¶ms) {
+ return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Param>> -> Params
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<std::unique_ptr<C2Param>> ¶ms) {
+ return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Tuning>> -> Params
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
+ return ::android::_createParamsBlob(blob, params);
+}
+
+// std::vector<std::shared_ptr<const C2Info>> -> Params
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
+ return ::android::_createParamsBlob(blob, params);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Param>>
+bool CopyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Param>>* params,
+ Params blob) {
+ return ::android::_copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool CopyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob) {
+ return ::android::_copyParamsFromBlob(params, blob);
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+bool UpdateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& blob) {
+ return ::android::updateParamsFromBlob(params, blob);
+}
+
+} // namespace utils
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h b/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
new file mode 100644
index 0000000..f111f81
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_TYPES_H
+#define CODEC2_HIDL_V1_0_UTILS_TYPES_H
+
+#include <bufferpool/ClientManager.h>
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/bufferpool/2.0/types.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/types.h>
+#include <android/hidl/safe_union/1.0/types.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2ParamDef.h>
+#include <C2Work.h>
+#include <util/C2Debug-base.h>
+
+#include <chrono>
+
+using namespace std::chrono_literals;
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::status_t;
+using ::android::sp;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ ConnectionId;
+
+// Types of metadata for Blocks.
+struct C2Hidl_Range {
+ uint32_t offset;
+ uint32_t length; // Do not use "size" because the name collides with C2Info::size().
+};
+typedef C2GlobalParam<C2Info, C2Hidl_Range, 0> C2Hidl_RangeInfo;
+
+struct C2Hidl_Rect {
+ uint32_t left;
+ uint32_t top;
+ uint32_t width;
+ uint32_t height;
+};
+typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
+
+// Make asString() and operator<< work with Status as well as c2_status_t.
+C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(Status);
+
+/**
+ * All objcpy() functions will return a boolean value indicating whether the
+ * conversion succeeds or not.
+ */
+
+// C2SettingResult -> SettingResult
+bool objcpy(
+ SettingResult* d,
+ const C2SettingResult& s);
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool objcpy(
+ std::unique_ptr<C2SettingResult>* d,
+ const SettingResult& s);
+
+// C2ParamDescriptor -> ParamDescriptor
+bool objcpy(
+ ParamDescriptor* d,
+ const C2ParamDescriptor& s);
+
+// ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
+bool objcpy(
+ std::shared_ptr<C2ParamDescriptor>* d,
+ const ParamDescriptor& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool objcpy(
+ FieldSupportedValuesQuery* d,
+ const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool objcpy(
+ FieldSupportedValuesQueryResult* d,
+ const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr);
+
+// C2Component::Traits -> ComponentTraits
+bool objcpy(
+ IComponentStore::ComponentTraits* d,
+ const C2Component::Traits& s);
+
+// ComponentTraits -> C2Component::Traits
+bool objcpy(
+ C2Component::Traits* d,
+ const IComponentStore::ComponentTraits& s);
+
+// C2StructDescriptor -> StructDescriptor
+bool objcpy(
+ StructDescriptor* d,
+ const C2StructDescriptor& s);
+
+// StructDescriptor -> C2StructDescriptor
+bool objcpy(
+ std::unique_ptr<C2StructDescriptor>* d,
+ const StructDescriptor& s);
+
+// Abstract class to be used in
+// objcpy(std::list<std::unique_ptr<C2Work>> -> WorkBundle).
+struct BufferPoolSender {
+ typedef ::android::hardware::media::bufferpool::V2_0::
+ ResultStatus ResultStatus;
+ typedef ::android::hardware::media::bufferpool::V2_0::
+ BufferStatusMessage BufferStatusMessage;
+ typedef ::android::hardware::media::bufferpool::
+ BufferPoolData BufferPoolData;
+
+ /**
+ * Send bpData and return BufferStatusMessage that can be supplied to
+ * IClientManager::receive() in the receiving process.
+ *
+ * This function will be called from within the function
+ * objcpy(std::list<std::unique_ptr<C2Work>> -> WorkBundle).
+ *
+ * \param[in] bpData BufferPoolData identifying the buffer to send.
+ * \param[out] bpMessage BufferStatusMessage of the transaction. Information
+ * inside \p bpMessage should be passed to the receiving process by some
+ * other means so it can call receive() properly.
+ * \return ResultStatus value that determines the success of the operation.
+ * (See the possible values of ResultStatus in
+ * hardware/interfaces/media/bufferpool/2.0/types.hal.)
+ */
+ virtual ResultStatus send(
+ const std::shared_ptr<BufferPoolData>& bpData,
+ BufferStatusMessage* bpMessage) = 0;
+
+ virtual ~BufferPoolSender() = default;
+};
+
+// Default implementation of BufferPoolSender.
+//
+// To use DefaultBufferPoolSender, the IClientManager instance of the receiving
+// process must be set before send() can operate. DefaultBufferPoolSender will
+// hold a strong reference to the IClientManager instance and use it to call
+// IClientManager::registerSender() to establish the bufferpool connection when
+// send() is called.
+struct DefaultBufferPoolSender : BufferPoolSender {
+ typedef ::android::hardware::media::bufferpool::V2_0::implementation::
+ ClientManager ClientManager;
+ typedef ::android::hardware::media::bufferpool::V2_0::
+ IClientManager IClientManager;
+
+ // Set the IClientManager instance of the receiving process and the refresh
+ // interval for the connection. The default interval is 4.5 seconds, which
+ // is slightly shorter than the amount of time the bufferpool will keep an
+ // inactive connection for.
+ DefaultBufferPoolSender(
+ const sp<IClientManager>& receiverManager = nullptr,
+ std::chrono::steady_clock::duration refreshInterval = 4500ms);
+
+ // Set the IClientManager instance of the receiving process and the refresh
+ // interval for the connection. The default interval is 4.5 seconds, which
+ // is slightly shorter than the amount of time the bufferpool will keep an
+ // inactive connection for.
+ void setReceiver(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval = 4500ms);
+
+ // Implementation of BufferPoolSender::send(). send() will establish a
+ // bufferpool connection if needed, then send the bufferpool data over to
+ // the receiving process.
+ virtual ResultStatus send(
+ const std::shared_ptr<BufferPoolData>& bpData,
+ BufferStatusMessage* bpMessage) override;
+
+private:
+ std::mutex mMutex;
+ sp<ClientManager> mSenderManager;
+ sp<IClientManager> mReceiverManager;
+ std::chrono::steady_clock::duration mRefreshInterval;
+
+ struct Connection {
+ int64_t receiverConnectionId;
+ std::chrono::steady_clock::time_point lastSent;
+ Connection(int64_t receiverConnectionId,
+ std::chrono::steady_clock::time_point lastSent)
+ : receiverConnectionId(receiverConnectionId),
+ lastSent(lastSent) {
+ }
+ };
+
+ // Map of connections.
+ //
+ // The key is the connection id. One sender-receiver pair may have multiple
+ // connections.
+ std::map<int64_t, Connection> mConnections;
+};
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+// Note: If bufferpool will be used, bpSender must not be null.
+bool objcpy(
+ WorkBundle* d,
+ const std::list<std::unique_ptr<C2Work>>& s,
+ BufferPoolSender* bpSender = nullptr);
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+bool objcpy(
+ std::list<std::unique_ptr<C2Work>>* d,
+ const WorkBundle& s);
+
+/**
+ * Parses a params blob and returns C2Param pointers to its params. The pointers
+ * point to locations inside the underlying buffer of \p blob. If \p blob is
+ * destroyed, the pointers become invalid.
+ *
+ * \param[out] params target vector of C2Param pointers
+ * \param[in] blob parameter blob to parse
+ * \retval true if the full blob was parsed
+ * \retval false otherwise
+ */
+bool parseParamsBlob(
+ std::vector<C2Param*> *params,
+ const hidl_vec<uint8_t> &blob);
+
+/**
+ * Concatenates a list of C2Params into a params blob.
+ *
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval true if the blob was successfully created
+ * \retval false if the blob was not successful (this only happens if the
+ * parameters were not const)
+ */
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<C2Param*> ¶ms);
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Param>> ¶ms);
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::shared_ptr<const C2Info>> ¶ms);
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Tuning>> ¶ms);
+
+/**
+ * Parses a params blob and create a vector of C2Params whose members are copies
+ * of the params in the blob.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval true if the full blob was parsed and params was constructed
+ * \retval false otherwise
+ */
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Param>>* params,
+ Params blob);
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob);
+
+/**
+ * Parses a params blob and applies updates to params.
+ *
+ * \param[in,out] params params to be updated
+ * \param[in] blob parameter blob containing updates
+ * \retval true if the full blob was parsed and params was updated
+ * \retval false otherwise
+ */
+bool updateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& blob);
+
+/**
+ * Converts a BufferPool status value to c2_status_t.
+ * \param BufferPool status
+ * \return Corresponding c2_status_t
+ */
+c2_status_t toC2Status(::android::hardware::media::bufferpool::V2_0::
+ ResultStatus rs);
+
+// BufferQueue-Based Block Operations
+// ==================================
+
+// Call before transferring block to other processes.
+//
+// The given block is ready to transfer to other processes. This will guarantee
+// the given block data is not mutated by bufferqueue migration.
+bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block);
+
+// Call beginTransferBufferQueueBlock() on blocks in the given workList.
+// processInput determines whether input blocks are yielded. processOutput
+// works similarly on output blocks. (The default value of processInput is
+// false while the default value of processOutput is true. This implies that in
+// most cases, only output buffers contain bufferqueue-based blocks.)
+void beginTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool processInput = false,
+ bool processOutput = true);
+
+// Call after transferring block is finished and make sure that
+// beginTransferBufferQueueBlock() is called before.
+//
+// The transfer of given block is finished. If transfer is successful the given
+// block is not owned by process anymore. Since transfer is finished the given
+// block data is OK to mutate by bufferqueue migration after this call.
+bool endTransferBufferQueueBlock(const C2ConstGraphicBlock& block,
+ bool transfer);
+
+// Call endTransferBufferQueueBlock() on blocks in the given workList.
+// processInput determines whether input blocks are yielded. processOutput
+// works similarly on output blocks. (The default value of processInput is
+// false while the default value of processOutput is true. This implies that in
+// most cases, only output buffers contain bufferqueue-based blocks.)
+void endTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool transfer,
+ bool processInput = false,
+ bool processOutput = true);
+
+// The given block is ready to be rendered. the given block is not owned by
+// process anymore. If migration is in progress, this returns false in order
+// not to render.
+bool displayBufferQueueBlock(const C2ConstGraphicBlock& block);
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_TYPES_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
new file mode 100644
index 0000000..ff69039
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_AIDL_UTILS_PARAM_TYPES_H
+#define CODEC2_AIDL_UTILS_PARAM_TYPES_H
+
+#include <aidl/android/hardware/media/c2/FieldSupportedValuesQuery.h>
+#include <aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.h>
+#include <aidl/android/hardware/media/c2/IComponentStore.h>
+#include <aidl/android/hardware/media/c2/ParamDescriptor.h>
+#include <aidl/android/hardware/media/c2/SettingResult.h>
+#include <aidl/android/hardware/media/c2/Status.h>
+#include <aidl/android/hardware/media/c2/StructDescriptor.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2ParamDef.h>
+#include <util/C2Debug-base.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace utils {
+
+// Make asString() and operator<< work with Status as well as c2_status_t.
+C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(Status);
+
+/**
+ * All objcpy() functions will return a boolean value indicating whether the
+ * conversion succeeds or not.
+ */
+
+// C2SettingResult -> SettingResult
+bool ToAidl(
+ SettingResult* d,
+ const C2SettingResult& s);
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool FromAidl(
+ std::unique_ptr<C2SettingResult>* d,
+ const SettingResult& s);
+
+// C2ParamDescriptor -> ParamDescriptor
+bool ToAidl(
+ ParamDescriptor* d,
+ const C2ParamDescriptor& s);
+
+// ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
+bool FromAidl(
+ std::shared_ptr<C2ParamDescriptor>* d,
+ const ParamDescriptor& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool ToAidl(
+ FieldSupportedValuesQuery* d,
+ const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool FromAidl(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool ToAidl(
+ FieldSupportedValuesQueryResult* d,
+ const C2FieldSupportedValuesQuery& s);
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
+bool FromAidl(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr);
+
+// C2Component::Traits -> ComponentTraits
+bool ToAidl(
+ IComponentStore::ComponentTraits* d,
+ const C2Component::Traits& s);
+
+// ComponentTraits -> C2Component::Traits
+bool FromAidl(
+ C2Component::Traits* d,
+ const IComponentStore::ComponentTraits& s);
+
+// C2StructDescriptor -> StructDescriptor
+bool ToAidl(
+ StructDescriptor* d,
+ const C2StructDescriptor& s);
+
+// StructDescriptor -> C2StructDescriptor
+bool FromAidl(
+ std::unique_ptr<C2StructDescriptor>* d,
+ const StructDescriptor& s);
+
+/**
+ * Parses a params blob and returns C2Param pointers to its params. The pointers
+ * point to locations inside the underlying buffer of \p blob. If \p blob is
+ * destroyed, the pointers become invalid.
+ *
+ * \param[out] params target vector of C2Param pointers
+ * \param[in] blob parameter blob to parse
+ * \retval true if the full blob was parsed
+ * \retval false otherwise
+ */
+bool ParseParamsBlob(
+ std::vector<C2Param*> *params,
+ const Params &blob);
+
+/**
+ * Concatenates a list of C2Params into a params blob.
+ *
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval true if the blob was successfully created
+ * \retval false if the blob was not successful (this only happens if the
+ * parameters were not const)
+ */
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<C2Param*> ¶ms);
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<std::unique_ptr<C2Param>> ¶ms);
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<std::shared_ptr<const C2Info>> ¶ms);
+bool CreateParamsBlob(
+ Params *blob,
+ const std::vector<std::unique_ptr<C2Tuning>> ¶ms);
+
+/**
+ * Parses a params blob and create a vector of C2Params whose members are copies
+ * of the params in the blob.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval true if the full blob was parsed and params was constructed
+ * \retval false otherwise
+ */
+bool CopyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Param>>* params,
+ const Params &blob);
+bool CopyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ const Params &blob);
+
+/**
+ * Parses a params blob and applies updates to params.
+ *
+ * \param[in,out] params params to be updated
+ * \param[in] blob parameter blob containing updates
+ * \retval true if the full blob was parsed and params was updated
+ * \retval false otherwise
+ */
+bool UpdateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& blob);
+
+} // namespace utils
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+} // namespace aidl
+
+#endif // CODEC2_AIDL_UTILS_PARAM_TYPES_H
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 31244fe..43dae1d 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -10,12 +10,6 @@
cc_library_headers {
name: "libcodec2_client_headers",
export_include_dirs: ["include"],
- vendor_available: true,
- apex_available: [
- "//apex_available:platform",
- "com.android.media",
- "com.android.media.swcodec",
- ],
min_sdk_version: "29",
host_supported: true,
target: {
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 97c0806..62e7b34 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -16,8 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2Client"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <android-base/logging.h>
-
+#include <utils/Trace.h>
#include <codec2/hidl/client.h>
#include <C2Debug.h>
#include <C2BufferPriv.h>
@@ -1577,6 +1578,7 @@
const C2ConstGraphicBlock& block,
const QueueBufferInput& input,
QueueBufferOutput* output) {
+ ScopedTrace trace(ATRACE_TAG,"Codec2Client::Component::queueToOutputSurface");
return mOutputBufferQueue->outputBuffer(block, input, output);
}
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index 4eebd1c..2f9773e 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -16,7 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2-OutputBufferQueue"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <android-base/logging.h>
+#include <utils/Trace.h>
#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
#include <codec2/hidl/output.h>
@@ -388,6 +390,7 @@
uint32_t generation;
uint64_t bqId;
int32_t bqSlot;
+ ScopedTrace trace(ATRACE_TAG,"Codec2-OutputBufferQueue::outputBuffer");
bool display = V1_0::utils::displayBufferQueueBlock(block);
if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
bqId == 0) {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 86fd8ab..a75ce70 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -46,6 +46,7 @@
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/RenderedFrameInfo.h>
#include <utils/NativeHandle.h>
#include "C2OMXNode.h"
@@ -672,8 +673,7 @@
}
void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override {
- mCodec->mCallback->onOutputFramesRendered(
- {RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
+ mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
}
void onOutputBuffersChanged() override {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 51082d1..14160f7 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -592,6 +592,8 @@
size_t bufferSize = 0;
c2_status_t blockRes = C2_OK;
bool copied = false;
+ ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
+ "CCodecBufferChannel::decrypt(%s)", mName).c_str());
if (mSendEncryptedInfoBuffer) {
static const C2MemoryUsage kDefaultReadWriteUsage{
C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 018e269..a56a216 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -16,7 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2Buffer"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <utils/Log.h>
+#include <utils/Trace.h>
#include <list>
#include <map>
@@ -33,6 +35,7 @@
namespace {
+using android::ScopedTrace;
using android::C2AllocatorBlob;
using android::C2AllocatorGralloc;
using android::C2AllocatorIon;
@@ -1159,6 +1162,7 @@
uint32_t capacity,
C2MemoryUsage usage,
std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+ ScopedTrace trace(ATRACE_TAG,"C2PooledBlockPool::fetchLinearBlock");
if (mBufferPoolVer == VER_HIDL && mImpl) {
return mImpl->fetchLinearBlock(capacity, usage, block);
}
@@ -1174,6 +1178,7 @@
uint32_t format,
C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block) {
+ ScopedTrace trace(ATRACE_TAG,"C2PooledBlockPool::fetchGraphicBlock");
if (mBufferPoolVer == VER_HIDL && mImpl) {
return mImpl->fetchGraphicBlock(width, height, format, usage, block);
}
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index f2cd585..b1838a3 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -16,8 +16,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2BqBuffer"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <android/hardware_buffer.h>
#include <utils/Log.h>
+#include <utils/Trace.h>
#include <ui/BufferQueueDefs.h>
#include <ui/GraphicBuffer.h>
@@ -37,6 +39,7 @@
#include <map>
#include <mutex>
+using ::android::ScopedTrace;
using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
using ::android::C2AllocatorGralloc;
using ::android::C2AndroidMemoryUsage;
@@ -1054,6 +1057,7 @@
uint32_t format,
C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ ScopedTrace trace(ATRACE_TAG,"C2BufferQueueBlockPool::fetchGraphicBlock");
if (mImpl) {
return mImpl->fetchGraphicBlock(width, height, format, usage, block, nullptr);
}
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index d55a3d8..d8c2292 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -114,8 +114,8 @@
}
namespace {
- constexpr int kSpinNumForLock = 100;
- constexpr int kSpinNumForUnlock = 200;
+ constexpr int kSpinNumForLock = 0;
+ constexpr int kSpinNumForUnlock = 0;
enum : uint32_t {
FUTEX_UNLOCKED = 0,
@@ -125,32 +125,65 @@
}
int C2SyncVariables::lock() {
- uint32_t old;
+ uint32_t old = FUTEX_UNLOCKED;
+
+ // see if we can lock uncontended immediately (if previously unlocked)
+ if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) {
+ return 0;
+ }
+
+ // spin to see if we can get it with a short wait without involving kernel
for (int i = 0; i < kSpinNumForLock; i++) {
- old = 0;
+ sched_yield();
+
+ old = FUTEX_UNLOCKED;
if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) {
return 0;
}
- sched_yield();
}
- if (old == FUTEX_LOCKED_UNCONTENDED)
+ // still locked, if other side thinks it was uncontended, now it is contended, so let them
+ // know that they need to wake us up.
+ if (old == FUTEX_LOCKED_UNCONTENDED) {
old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
+ // It is possible that the other holder released the lock at this very moment (and old
+ // becomes UNLOCKED), If so, we will not involve the kernel to wait for the lock to be
+ // released, but are still marking our lock contended (even though we are the only
+ // holders.)
+ }
- while (old) {
- (void) syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0);
+ // while the futex is still locked by someone else
+ while (old != FUTEX_UNLOCKED) {
+ // wait until other side releases the lock (and still contented)
+ (void)syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0);
+ // try to relock
old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
}
return 0;
}
int C2SyncVariables::unlock() {
- if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) return 0;
+ // TRICKY: here we assume that we are holding this lock
+ // unlock the lock immediately (since we were holding it)
+ // If it is (still) locked uncontested, we are done (no need to involve the kernel)
+ if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) {
+ return 0;
+ }
+
+ // We don't need to spin for unlock as here we know already we have a waiter who we need to
+ // wake up. This code was here in case someone just happened to lock this lock (uncontested)
+ // before we would wake up other waiters to avoid a syscall. It is unsure if this ever gets
+ // exercised or if this is the behavior we want. (Note that if this code is removed, the same
+ // situation is still handled in lock() by the woken up waiter that realizes that the lock is
+ // now taken.)
for (int i = 0; i < kSpinNumForUnlock; i++) {
- if (mLock.load()) {
+ // here we seem to check if someone relocked this lock, and if they relocked uncontested,
+ // we up it to contested (since there are other waiters.)
+ if (mLock.load() != FUTEX_UNLOCKED) {
uint32_t old = FUTEX_LOCKED_UNCONTENDED;
mLock.compare_exchange_strong(old, FUTEX_LOCKED_CONTENDED);
+ // this is always true here so we return immediately
if (old) {
return 0;
}
@@ -158,7 +191,8 @@
sched_yield();
}
- (void) syscall(__NR_futex, &mLock, FUTEX_WAKE, 1, NULL, NULL, 0);
+ // wake up one waiter
+ (void)syscall(__NR_futex, &mLock, FUTEX_WAKE, 1, NULL, NULL, 0);
return 0;
}
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 7648c76..74f7e6b 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -623,6 +623,11 @@
* (e.g. a USB audio interface, a DAC connected to headphones) to
* specify allowable configurations of a particular device.
*
+ * Channel masks are for input only, output only, or both input and output.
+ * These channel masks are different than those defined in AudioFormat.java.
+ * If an app gets a channel mask from Java API and wants to use it in AAudio,
+ * conversion should be done by the app.
+ *
* Added in API level 32.
*/
enum {
@@ -630,10 +635,6 @@
* Invalid channel mask
*/
AAUDIO_CHANNEL_INVALID = -1,
-
- /**
- * Output audio channel mask
- */
AAUDIO_CHANNEL_FRONT_LEFT = 1 << 0,
AAUDIO_CHANNEL_FRONT_RIGHT = 1 << 1,
AAUDIO_CHANNEL_FRONT_CENTER = 1 << 2,
@@ -661,62 +662,112 @@
AAUDIO_CHANNEL_FRONT_WIDE_LEFT = 1 << 24,
AAUDIO_CHANNEL_FRONT_WIDE_RIGHT = 1 << 25,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_MONO = AAUDIO_CHANNEL_FRONT_LEFT,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_STEREO = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_2POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_TRI = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_TRI_BACK = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_BACK_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_3POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_2POINT0POINT2 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_2POINT1POINT2 = AAUDIO_CHANNEL_2POINT0POINT2 |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_3POINT0POINT2 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_3POINT1POINT2 = AAUDIO_CHANNEL_3POINT0POINT2 |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_QUAD = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_BACK_LEFT |
AAUDIO_CHANNEL_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_QUAD_SIDE = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_SIDE_LEFT |
AAUDIO_CHANNEL_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_SURROUND = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_BACK_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_PENTA = AAUDIO_CHANNEL_QUAD |
AAUDIO_CHANNEL_FRONT_CENTER,
- // aka 5POINT1_BACK
+ /**
+ * Supported for Input and Output. aka 5POINT1_BACK
+ */
AAUDIO_CHANNEL_5POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_LOW_FREQUENCY |
AAUDIO_CHANNEL_BACK_LEFT |
AAUDIO_CHANNEL_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_5POINT1_SIDE = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_LOW_FREQUENCY |
AAUDIO_CHANNEL_SIDE_LEFT |
AAUDIO_CHANNEL_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_6POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
@@ -724,32 +775,55 @@
AAUDIO_CHANNEL_BACK_LEFT |
AAUDIO_CHANNEL_BACK_RIGHT |
AAUDIO_CHANNEL_BACK_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_7POINT1 = AAUDIO_CHANNEL_5POINT1 |
AAUDIO_CHANNEL_SIDE_LEFT |
AAUDIO_CHANNEL_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_5POINT1POINT2 = AAUDIO_CHANNEL_5POINT1 |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_5POINT1POINT4 = AAUDIO_CHANNEL_5POINT1 |
AAUDIO_CHANNEL_TOP_FRONT_LEFT |
AAUDIO_CHANNEL_TOP_FRONT_RIGHT |
AAUDIO_CHANNEL_TOP_BACK_LEFT |
AAUDIO_CHANNEL_TOP_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_7POINT1POINT2 = AAUDIO_CHANNEL_7POINT1 |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_7POINT1POINT4 = AAUDIO_CHANNEL_7POINT1 |
AAUDIO_CHANNEL_TOP_FRONT_LEFT |
AAUDIO_CHANNEL_TOP_FRONT_RIGHT |
AAUDIO_CHANNEL_TOP_BACK_LEFT |
AAUDIO_CHANNEL_TOP_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_9POINT1POINT4 = AAUDIO_CHANNEL_7POINT1POINT4 |
AAUDIO_CHANNEL_FRONT_WIDE_LEFT |
AAUDIO_CHANNEL_FRONT_WIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_9POINT1POINT6 = AAUDIO_CHANNEL_9POINT1POINT4 |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
-
+ /**
+ * Supported for only Input
+ */
AAUDIO_CHANNEL_FRONT_BACK = AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_BACK_CENTER,
};
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 359c140..4269aa2 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -817,7 +817,7 @@
(void) updateAndGetPosition_l();
// save start timestamp
- if (isOffloadedOrDirect_l()) {
+ if (isAfTrackOffloadedOrDirect_l()) {
if (getTimestamp_l(mStartTs) != OK) {
mStartTs.mPosition = 0;
}
@@ -838,7 +838,7 @@
mTimestampStaleTimeReported = false;
mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
- if (!isOffloadedOrDirect_l()
+ if (!isAfTrackOffloadedOrDirect_l()
&& mStartEts.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] > 0) {
// Server side has consumed something, but is it finished consuming?
// It is possible since flush and stop are asynchronous that the server
@@ -1917,6 +1917,7 @@
mAfChannelCount = audio_channel_count_from_out_mask(output.afChannelMask);
mAfFormat = output.afFormat;
mAfLatency = output.afLatencyMs;
+ mAfTrackFlags = output.afTrackFlags;
mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
@@ -3182,7 +3183,7 @@
// To avoid a race, read the presented frames first. This ensures that presented <= consumed.
status_t status;
- if (isOffloadedOrDirect_l()) {
+ if (isAfTrackOffloadedOrDirect_l()) {
// use Binder to get timestamp
media::AudioTimestampInternal ts;
mAudioTrack->getTimestamp(&ts, &status);
@@ -3294,7 +3295,7 @@
ALOGV_IF(status != WOULD_BLOCK, "%s(%d): getTimestamp error:%#x", __func__, mPortId, status);
return status;
}
- if (isOffloadedOrDirect_l()) {
+ if (isAfTrackOffloadedOrDirect_l()) {
if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) {
// use cached paused position in case another offloaded track is running.
timestamp.mPosition = mPausedPosition;
@@ -3740,7 +3741,7 @@
// This is conservatively figured - if we encounter an unexpected error
// then we will not wait.
bool wait = false;
- if (isOffloadedOrDirect_l()) {
+ if (isAfTrackOffloadedOrDirect_l()) {
AudioTimestamp ts;
status_t status = getTimestamp_l(ts);
if (status == WOULD_BLOCK) {
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 4bd12b8..515e708 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -116,6 +116,8 @@
legacy2aidl_audio_channel_mask_t_AudioChannelLayout(afChannelMask, false /*isInput*/));
aidl.afFormat = VALUE_OR_RETURN(
legacy2aidl_audio_format_t_AudioFormatDescription(afFormat));
+ aidl.afTrackFlags = VALUE_OR_RETURN(
+ legacy2aidl_audio_output_flags_t_int32_t_mask(afTrackFlags));
aidl.outputId = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(outputId));
aidl.portId = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(portId));
aidl.audioTrack = audioTrack;
@@ -144,6 +146,8 @@
false /*isInput*/));
legacy.afFormat = VALUE_OR_RETURN(
aidl2legacy_AudioFormatDescription_audio_format_t(aidl.afFormat));
+ legacy.afTrackFlags = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_output_flags_t_mask(aidl.afTrackFlags));
legacy.outputId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.outputId));
legacy.portId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.portId));
legacy.audioTrack = aidl.audioTrack;
diff --git a/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
index 42e0bb4..ab60461 100644
--- a/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
@@ -43,6 +43,7 @@
AudioChannelLayout afChannelMask;
AudioFormatDescription afFormat;
int afLatencyMs;
+ int afTrackFlags;
/** Interpreted as audio_io_handle_t. */
int outputId;
/** Interpreted as audio_port_handle_t. */
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 8f712db..523383f 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1238,6 +1238,11 @@
bool isDirect_l() const
{ return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
+ bool isAfTrackOffloadedOrDirect_l() const
+ { return isOffloadedOrDirect_l() ||
+ (mAfTrackFlags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|
+ AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }
+
// pure pcm data is mixable (which excludes HW_AV_SYNC, with embedded timing)
bool isPurePcmData_l() const
{ return audio_is_linear_pcm(mFormat)
@@ -1295,6 +1300,7 @@
uint32_t mAfSampleRate; // AudioFlinger sample rate
uint32_t mAfChannelCount; // AudioFlinger channel count
audio_format_t mAfFormat; // AudioFlinger format
+ audio_output_flags_t mAfTrackFlags; // AudioFlinger track flags
// constant after constructor or set()
audio_format_t mFormat; // as requested by client, not forced to 16-bit
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 3c96862..35a3208 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -119,6 +119,7 @@
uint32_t afLatencyMs;
audio_channel_mask_t afChannelMask;
audio_format_t afFormat;
+ audio_output_flags_t afTrackFlags;
audio_io_handle_t outputId;
audio_port_handle_t portId;
sp<media::IAudioTrack> audioTrack;
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index ae4a530..b8e62ae 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -56,6 +56,7 @@
using ::aidl::android::hardware::audio::effect::Descriptor;
using ::aidl::android::hardware::audio::effect::IEffect;
using ::aidl::android::hardware::audio::effect::IFactory;
+using ::aidl::android::hardware::audio::effect::State;
namespace android {
namespace effect {
@@ -165,13 +166,20 @@
// write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
status_t EffectHalAidl::process() {
+ State state = State::INIT;
+ if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
+ state != State::PROCESSING) {
+ ALOGI("%s skipping %s process because it's %s", __func__, mDesc.common.name.c_str(),
+ mConversion->isBypassing()
+ ? "bypassing"
+ : aidl::android::hardware::audio::effect::toString(state).c_str());
+ return OK;
+ }
+
auto statusQ = mConversion->getStatusMQ();
auto inputQ = mConversion->getInputMQ();
auto outputQ = mConversion->getOutputMQ();
auto efGroup = mConversion->getEventFlagGroup();
- if (mConversion->isBypassing()) {
- return OK;
- }
if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
!outputQ->isValid() || !efGroup) {
ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__,
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index fc2da6b..5e465d9 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -92,9 +92,7 @@
"noActiveEffctFound");
}
- const size_t newIndex = std::distance(mSubEffects.begin(), itor);
- mActiveSubIdx = newIndex;
-
+ mActiveSubIdx = std::distance(mSubEffects.begin(), itor);
ALOGI("%s: active %soffload sub-effect %zu descriptor: %s", __func__,
offload->isOffload ? "" : "non-", mActiveSubIdx,
::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid)
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 1551e33..8d408dd 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -165,6 +165,7 @@
pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
+ pContext->mChannelCount = channelCount;
pContext->mConfig = *pConfig;
Visualizer_reset(pContext);
@@ -229,8 +230,6 @@
pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
// measurement initialization
- pContext->mChannelCount =
- audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels);
pContext->mMeasurementMode = MEASUREMENT_MODE_NONE;
pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
pContext->mMeasurementBufferIdx = 0;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a91b24a..1a32e61 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -43,6 +43,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/RenderedFrameInfo.h>
#include <media/stagefright/SurfaceUtils.h>
#include <media/hardware/HardwareAPI.h>
#include <media/MediaBufferHolder.h>
@@ -634,7 +635,8 @@
if (!mBufferChannel) {
mBufferChannel = std::make_shared<ACodecBufferChannel>(
new AMessage(kWhatInputBufferFilled, this),
- new AMessage(kWhatOutputBufferDrained, this));
+ new AMessage(kWhatOutputBufferDrained, this),
+ new AMessage(kWhatPollForRenderedBuffers, this));
}
return mBufferChannel;
}
@@ -744,6 +746,7 @@
// if we have not yet started the codec, we can simply set the native window
if (mBuffers[kPortIndexInput].size() == 0) {
mNativeWindow = surface;
+ initializeFrameTracking();
return OK;
}
@@ -852,6 +855,7 @@
mNativeWindow = nativeWindow;
mNativeWindowUsageBits = usageBits;
+ initializeFrameTracking();
return OK;
}
@@ -962,7 +966,6 @@
BufferInfo info;
info.mStatus = BufferInfo::OWNED_BY_US;
info.mFenceFd = -1;
- info.mRenderInfo = NULL;
info.mGraphicBuffer = NULL;
info.mNewGraphicBuffer = false;
@@ -1230,6 +1233,7 @@
*bufferCount = def.nBufferCountActual;
*bufferSize = def.nBufferSize;
+ initializeFrameTracking();
return err;
}
@@ -1268,7 +1272,6 @@
info.mStatus = BufferInfo::OWNED_BY_US;
info.mFenceFd = fenceFd;
info.mIsReadFence = false;
- info.mRenderInfo = NULL;
info.mGraphicBuffer = graphicBuffer;
info.mNewGraphicBuffer = false;
info.mDequeuedAt = mDequeueCounter;
@@ -1345,7 +1348,6 @@
BufferInfo info;
info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
info.mFenceFd = -1;
- info.mRenderInfo = NULL;
info.mGraphicBuffer = NULL;
info.mNewGraphicBuffer = false;
info.mDequeuedAt = mDequeueCounter;
@@ -1441,42 +1443,6 @@
return err;
}
-void ACodec::updateRenderInfoForDequeuedBuffer(
- ANativeWindowBuffer *buf, int fenceFd, BufferInfo *info) {
-
- info->mRenderInfo =
- mRenderTracker.updateInfoForDequeuedBuffer(
- buf, fenceFd, info - &mBuffers[kPortIndexOutput][0]);
-
- // check for any fences already signaled
- notifyOfRenderedFrames(false /* dropIncomplete */, info->mRenderInfo);
-}
-
-void ACodec::onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
- if (mRenderTracker.onFrameRendered(mediaTimeUs, systemNano) != OK) {
- mRenderTracker.dumpRenderQueue();
- }
-}
-
-void ACodec::notifyOfRenderedFrames(bool dropIncomplete, FrameRenderTracker::Info *until) {
- std::list<FrameRenderTracker::Info> done =
- mRenderTracker.checkFencesAndGetRenderedFrames(until, dropIncomplete);
-
- // unlink untracked frames
- for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin();
- it != done.cend(); ++it) {
- ssize_t index = it->getIndex();
- if (index >= 0 && (size_t)index < mBuffers[kPortIndexOutput].size()) {
- mBuffers[kPortIndexOutput][index].mRenderInfo = NULL;
- } else if (index >= 0) {
- // THIS SHOULD NEVER HAPPEN
- ALOGE("invalid index %zd in %zu", index, mBuffers[kPortIndexOutput].size());
- }
- }
-
- mCallback->onOutputFramesRendered(done);
-}
-
void ACodec::onFirstTunnelFrameReady() {
mCallback->onFirstTunnelFrameReady();
}
@@ -1531,7 +1497,6 @@
info->mStatus = BufferInfo::OWNED_BY_US;
info->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow");
- updateRenderInfoForDequeuedBuffer(buf, fenceFd, info);
return info;
}
}
@@ -1576,18 +1541,96 @@
oldest->mNewGraphicBuffer = true;
oldest->mStatus = BufferInfo::OWNED_BY_US;
oldest->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow for oldest");
- mRenderTracker.untrackFrame(oldest->mRenderInfo);
- oldest->mRenderInfo = NULL;
ALOGV("replaced oldest buffer #%u with age %u, graphicBuffer %p",
(unsigned)(oldest - &mBuffers[kPortIndexOutput][0]),
mDequeueCounter - oldest->mDequeuedAt,
oldest->mGraphicBuffer->handle);
-
- updateRenderInfoForDequeuedBuffer(buf, fenceFd, oldest);
return oldest;
}
+void ACodec::initializeFrameTracking() {
+ mTrackedFrames.clear();
+
+ int isWindowToDisplay = 0;
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+ &isWindowToDisplay);
+ mIsWindowToDisplay = isWindowToDisplay == 1;
+ // No frame tracking is needed if we're not sending frames to the display
+ if (!mIsWindowToDisplay) {
+ // Return early so we don't call into SurfaceFlinger (requiring permissions)
+ return;
+ }
+
+ int hasPresentFenceTimes = 0;
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT,
+ &hasPresentFenceTimes);
+ mHasPresentFenceTimes = hasPresentFenceTimes == 1;
+ if (!mHasPresentFenceTimes) {
+ ALOGI("Using latch times for frame rendered signals - present fences not supported");
+ }
+
+ status_t err = native_window_enable_frame_timestamps(mNativeWindow.get(), true);
+ if (err) {
+ ALOGE("Failed to enable frame timestamps (%d)", err);
+ }
+}
+
+void ACodec::trackReleasedFrame(int64_t frameId, int64_t mediaTimeUs, int64_t desiredRenderTimeNs) {
+ // If the render time is earlier than now, then we're suggesting it should be rendered ASAP,
+ // so track the frame as if the desired render time is now.
+ int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (desiredRenderTimeNs < nowNs) {
+ desiredRenderTimeNs = nowNs;
+ }
+ // We've just queued a frame to the surface, so keep track of it and later check to see if it is
+ // actually rendered.
+ TrackedFrame frame;
+ frame.id = frameId;
+ frame.mediaTimeUs = mediaTimeUs;
+ frame.desiredRenderTimeNs = desiredRenderTimeNs;
+ mTrackedFrames.push_back(frame);
+}
+
+void ACodec::pollForRenderedFrames() {
+ std::list<RenderedFrameInfo> renderedFrameInfos;
+ // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have,
+ // in fact, been rendered.
+ int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+ while (!mTrackedFrames.empty()) {
+ TrackedFrame & frame = mTrackedFrames.front();
+ // Frames that should have been rendered at least 100ms in the past are checked
+ if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) {
+ break;
+ }
+
+ status_t err;
+ nsecs_t latchOrPresentTimeNs = NATIVE_WINDOW_TIMESTAMP_INVALID;
+ err = native_window_get_frame_timestamps(mNativeWindow.get(), frame.id,
+ /* outRequestedPresentTime */ nullptr, /* outAcquireTime */ nullptr,
+ mHasPresentFenceTimes ? nullptr : &latchOrPresentTimeNs, // latch time
+ /* outFirstRefreshStartTime */ nullptr, /* outLastRefreshStartTime */ nullptr,
+ /* outGpuCompositionDoneTime */ nullptr,
+ mHasPresentFenceTimes ? &latchOrPresentTimeNs : nullptr, // display present time,
+ /* outDequeueReadyTime */ nullptr, /* outReleaseTime */ nullptr);
+ if (err) {
+ ALOGE("Failed to get frame timestamps for %lld: %d", (long long) frame.id, err);
+ }
+ // If we don't have a render time by now, then consider the frame as dropped
+ if (latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_PENDING &&
+ latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_INVALID) {
+ renderedFrameInfos.push_back(RenderedFrameInfo(frame.mediaTimeUs,
+ latchOrPresentTimeNs));
+ }
+
+ mTrackedFrames.pop_front();
+ }
+
+ if (!renderedFrameInfos.empty()) {
+ mCallback->onOutputFramesRendered(renderedFrameInfos);
+ }
+}
+
status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
if (portIndex == kPortIndexInput) {
mBufferChannel->setInputBufferArray({});
@@ -1663,11 +1706,6 @@
::close(info->mFenceFd);
}
- if (portIndex == kPortIndexOutput) {
- mRenderTracker.untrackFrame(info->mRenderInfo, i);
- info->mRenderInfo = NULL;
- }
-
// remove buffer even if mOMXNode->freeBuffer fails
mBuffers[portIndex].erase(mBuffers[portIndex].begin() + i);
return err;
@@ -6032,22 +6070,10 @@
sp<RefBase> obj;
CHECK(msg->findObject("messages", &obj));
sp<MessageList> msgList = static_cast<MessageList *>(obj.get());
-
- bool receivedRenderedEvents = false;
for (std::list<sp<AMessage>>::const_iterator it = msgList->getList().cbegin();
it != msgList->getList().cend(); ++it) {
(*it)->setWhat(ACodec::kWhatOMXMessageItem);
mCodec->handleMessage(*it);
- int32_t type;
- CHECK((*it)->findInt32("type", &type));
- if (type == omx_message::FRAME_RENDERED) {
- receivedRenderedEvents = true;
- }
- }
-
- if (receivedRenderedEvents) {
- // NOTE: all buffers are rendered in this case
- mCodec->notifyOfRenderedFrames();
}
return true;
}
@@ -6609,15 +6635,6 @@
info->mDequeuedAt = ++mCodec->mDequeueCounter;
info->mStatus = BufferInfo::OWNED_BY_US;
- if (info->mRenderInfo != NULL) {
- // The fence for an emptied buffer must have signaled, but there still could be queued
- // or out-of-order dequeued buffers in the render queue prior to this buffer. Drop these,
- // as we will soon requeue this buffer to the surface. While in theory we could still keep
- // track of buffers that are requeued to the surface, it is better to add support to the
- // buffer-queue to notify us of released buffers and their fences (in the future).
- mCodec->notifyOfRenderedFrames(true /* dropIncomplete */);
- }
-
// byte buffers cannot take fences, so wait for any fence now
if (mCodec->mNativeWindow == NULL) {
(void)mCodec->waitForFence(fenceFd, "onOMXFillBufferDone");
@@ -6824,14 +6841,6 @@
mCodec->mLastHdr10PlusBuffer = hdr10PlusInfo;
}
- // save buffers sent to the surface so we can get render time when they return
- int64_t mediaTimeUs = -1;
- buffer->meta()->findInt64("timeUs", &mediaTimeUs);
- if (mediaTimeUs >= 0) {
- mCodec->mRenderTracker.onFrameQueued(
- mediaTimeUs, info->mGraphicBuffer, new Fence(::dup(info->mFenceFd)));
- }
-
int64_t timestampNs = 0;
if (!msg->findInt64("timestampNs", ×tampNs)) {
// use media timestamp if client did not request a specific render timestamp
@@ -6845,11 +6854,25 @@
err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs);
ALOGW_IF(err != NO_ERROR, "failed to set buffer timestamp: %d", err);
+ uint64_t frameId;
+ err = native_window_get_next_frame_id(mCodec->mNativeWindow.get(), &frameId);
+
info->checkReadFence("onOutputBufferDrained before queueBuffer");
err = mCodec->mNativeWindow->queueBuffer(
mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd);
- // TODO(b/266211548): Poll the native window for rendered buffers, since when queueing
- // buffers, the frame event history delta is retrieved.
+
+ int64_t mediaTimeUs = -1;
+ buffer->meta()->findInt64("timeUs", &mediaTimeUs);
+ if (mCodec->mIsWindowToDisplay) {
+ mCodec->trackReleasedFrame(frameId, mediaTimeUs, timestampNs);
+ mCodec->pollForRenderedFrames();
+ } else {
+ // When the surface is an intermediate surface, onFrameRendered is triggered immediately
+ // when the frame is queued to the non-display surface
+ mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs,
+ timestampNs)});
+ }
+
info->mFenceFd = -1;
if (err == OK) {
info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
@@ -7076,7 +7099,6 @@
++mCodec->mNodeGeneration;
mCodec->mComponentName = componentName;
- mCodec->mRenderTracker.setComponentName(componentName);
mCodec->mFlags = 0;
if (componentName.endsWith(".secure")) {
@@ -7713,7 +7735,6 @@
void ACodec::ExecutingState::stateEntered() {
ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str());
- mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
mCodec->processDeferredMessages();
}
@@ -7824,7 +7845,15 @@
mCodec->signalSubmitOutputMetadataBufferIfEOS_workaround();
}
}
- return true;
+ handled = true;
+ break;
+ }
+
+ case kWhatPollForRenderedBuffers:
+ {
+ mCodec->pollForRenderedFrames();
+ handled = true;
+ break;
}
default:
@@ -8520,7 +8549,7 @@
}
bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
- mCodec->onFrameRendered(mediaTimeUs, systemNano);
+ mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)});
return true;
}
@@ -8694,7 +8723,7 @@
bool ACodec::OutputPortSettingsChangedState::onOMXFrameRendered(
int64_t mediaTimeUs, nsecs_t systemNano) {
- mCodec->onFrameRendered(mediaTimeUs, systemNano);
+ mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)});
return true;
}
@@ -8725,10 +8754,6 @@
OMX_CommandPortEnable, kPortIndexOutput);
}
- // Clear the RenderQueue in which queued GraphicBuffers hold the
- // actual buffer references in order to free them early.
- mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
-
if (err == OK) {
err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
ALOGE_IF(err != OK, "Failed to allocate output port buffers after port "
@@ -9112,8 +9137,6 @@
// the native window for rendering. Let's get those back as well.
mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs();
- mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
-
mCodec->mCallback->onFlushCompleted();
mCodec->mPortEOS[kPortIndexInput] =
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 8f2bed2..ad42813 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -32,6 +32,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/ACodec.h>
#include <media/stagefright/MediaCodec.h>
#include <media/MediaCodecBuffer.h>
#include <system/window.h>
@@ -87,9 +88,11 @@
}
ACodecBufferChannel::ACodecBufferChannel(
- const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
+ const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained,
+ const sp<AMessage> &pollForRenderedBuffers)
: mInputBufferFilled(inputBufferFilled),
mOutputBufferDrained(outputBufferDrained),
+ mPollForRenderedBuffers(pollForRenderedBuffers),
mHeapSeqNum(-1) {
}
@@ -488,7 +491,7 @@
}
void ACodecBufferChannel::pollForRenderedBuffers() {
- // TODO(b/266211548): Poll the native window for rendered buffers.
+ mPollForRenderedBuffers->post();
}
status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index b5bd975..57937f9 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -16,7 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "FrameDecoder"
-
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include "include/FrameDecoder.h"
#include "include/FrameCaptureLayer.h"
#include "include/HevcUtils.h"
@@ -41,6 +41,7 @@
#include <media/stagefright/Utils.h>
#include <private/media/VideoFrame.h>
#include <utils/Log.h>
+#include <utils/Trace.h>
namespace android {
@@ -340,6 +341,7 @@
}
sp<IMemory> FrameDecoder::extractFrame(FrameRect *rect) {
+ ScopedTrace trace(ATRACE_TAG, "FrameDecoder::ExtractFrame");
status_t err = onExtractRect(rect);
if (err == OK) {
err = extractInternal();
@@ -713,6 +715,7 @@
}
converter.setSrcColorSpace(standard, range, transfer);
if (converter.isValid()) {
+ ScopedTrace trace(ATRACE_TAG, "FrameDecoder::ColorConverter");
converter.convert(
(const uint8_t *)videoFrameBuffer->data(),
width, height, stride,
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a0d56f8..c5475cf 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -77,6 +77,7 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/RenderedFrameInfo.h>
#include <media/stagefright/SurfaceUtils.h>
#include <nativeloader/dlext_namespaces.h>
#include <private/android_filesystem_config.h>
@@ -408,7 +409,7 @@
std::scoped_lock lock{mLock};
// Unregistering from DeathRecipient notification.
if (mService != nullptr) {
- AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+ AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), mCookie);
mService = nullptr;
}
}
@@ -448,13 +449,15 @@
std::shared_ptr<IResourceManagerClient> mClient;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
std::shared_ptr<IResourceManagerService> mService;
+ BinderDiedContext* mCookie;
};
MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
pid_t pid, uid_t uid, const std::shared_ptr<IResourceManagerClient> &client) :
mPid(pid), mUid(uid), mClient(client),
mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
- AIBinder_DeathRecipient_new(BinderDiedCallback))) {
+ AIBinder_DeathRecipient_new(BinderDiedCallback))),
+ mCookie(nullptr) {
if (mUid == MediaCodec::kNoUid) {
mUid = AIBinder_getCallingUid();
}
@@ -512,9 +515,9 @@
// Create the context that is passed as cookie to the binder death notification.
// The context gets deleted at BinderUnlinkedCallback.
- BinderDiedContext* context = new BinderDiedContext{.mRMServiceProxy = weak_from_this()};
+ mCookie = new BinderDiedContext{.mRMServiceProxy = weak_from_this()};
// Register for the callbacks by linking to death notification.
- AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), context);
+ AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), mCookie);
// If the RM was restarted, re-register all the resources.
if (mBinderDied) {
@@ -869,7 +872,7 @@
const sp<AMessage> &outputFormat) override;
virtual void onInputSurfaceDeclined(status_t err) override;
virtual void onSignaledInputEOS(status_t err) override;
- virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
+ virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) override;
virtual void onOutputBuffersChanged() override;
virtual void onFirstTunnelFrameReady() override;
private:
@@ -978,7 +981,7 @@
notify->post();
}
-void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
+void CodecCallback::onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) {
sp<AMessage> notify(mNotify->dup());
notify->setInt32("what", kWhatOutputFramesRendered);
if (MediaCodec::CreateFramesRenderedMessage(done, notify)) {
@@ -6076,12 +6079,10 @@
return onQueueInputBuffer(msg);
}
-//static
-size_t MediaCodec::CreateFramesRenderedMessage(
- const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) {
+template<typename T>
+static size_t CreateFramesRenderedMessageInternal(const std::list<T> &done, sp<AMessage> &msg) {
size_t index = 0;
- for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin();
- it != done.cend(); ++it) {
+ for (typename std::list<T>::const_iterator it = done.cbegin(); it != done.cend(); ++it) {
if (it->getRenderTimeNs() < 0) {
continue; // dropped frame from tracking
}
@@ -6092,6 +6093,18 @@
return index;
}
+//static
+size_t MediaCodec::CreateFramesRenderedMessage(
+ const std::list<RenderedFrameInfo> &done, sp<AMessage> &msg) {
+ return CreateFramesRenderedMessageInternal(done, msg);
+}
+
+//static
+size_t MediaCodec::CreateFramesRenderedMessage(
+ const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) {
+ return CreateFramesRenderedMessageInternal(done, msg);
+}
+
status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
size_t index;
CHECK(msg->findSize("index", &index));
diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp
index f25318d..4383d6f 100644
--- a/media/libstagefright/http/Android.bp
+++ b/media/libstagefright/http/Android.bp
@@ -37,10 +37,4 @@
],
cfi: true,
},
-
- product_variables: {
- pdk: {
- enabled: false,
- },
- },
}
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 903280f..a464504 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -29,6 +29,7 @@
#include <media/IOMX.h>
namespace android {
+ struct ACodec;
namespace hardware {
class HidlMemory;
};
@@ -63,7 +64,8 @@
};
ACodecBufferChannel(
- const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
+ const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained,
+ const sp<AMessage> &pollForRenderedBuffers);
virtual ~ACodecBufferChannel();
// BufferChannelBase interface
@@ -138,6 +140,7 @@
const sp<AMessage> mInputBufferFilled;
const sp<AMessage> mOutputBufferDrained;
+ const sp<AMessage> mPollForRenderedBuffers;
sp<MemoryDealer> mDealer;
sp<IMemory> mDecryptDestination;
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index e535d5d..ec4a04c 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -19,7 +19,7 @@
#include <set>
#include <stdint.h>
-#include <list>
+#include <deque>
#include <vector>
#include <android/native_window.h>
#include <media/hardware/MetadataBufferType.h>
@@ -27,9 +27,9 @@
#include <media/IOMX.h>
#include <media/stagefright/AHierarchicalStateMachine.h>
#include <media/stagefright/CodecBase.h>
-#include <media/stagefright/FrameRenderTracker.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/SkipCutBuffer.h>
+#include <ui/GraphicBuffer.h>
#include <utils/NativeHandle.h>
#include <OMX_Audio.h>
#include <hardware/gralloc.h>
@@ -156,6 +156,7 @@
kWhatForceStateTransition = 'fstt',
kWhatCheckIfStuck = 'Cstk',
kWhatSubmitExtraOutputMetadataBuffer = 'sbxo',
+ kWhatPollForRenderedBuffers = 'pfrb',
};
enum {
@@ -177,6 +178,13 @@
| static_cast<uint64_t>(BufferUsage::VIDEO_DECODER),
};
+ struct TrackedFrame {
+ int64_t id;
+ int64_t mediaTimeUs;
+ int64_t desiredRenderTimeNs;
+ nsecs_t renderTimeNs;
+ };
+
struct BufferInfo {
enum Status {
OWNED_BY_US,
@@ -204,7 +212,6 @@
sp<GraphicBuffer> mGraphicBuffer;
bool mNewGraphicBuffer;
int mFenceFd;
- FrameRenderTracker::Info *mRenderInfo;
// The following field and 4 methods are used for debugging only
bool mIsReadFence;
@@ -253,6 +260,8 @@
bool mUsingNativeWindow;
sp<ANativeWindow> mNativeWindow;
+ bool mIsWindowToDisplay;
+ bool mHasPresentFenceTimes;
int mNativeWindowUsageBits;
android_native_rect_t mLastNativeWindowCrop;
int32_t mLastNativeWindowDataSpace;
@@ -267,7 +276,7 @@
// format updates. This will equal to mOutputFormat until the first actual frame is received.
sp<AMessage> mBaseOutputFormat;
- FrameRenderTracker mRenderTracker; // render information for buffers rendered by ACodec
+ std::deque<TrackedFrame> mTrackedFrames; // render information for buffers sent to a window
std::vector<BufferInfo> mBuffers[2];
bool mPortEOS[2];
status_t mInputEOSResult;
@@ -349,6 +358,10 @@
status_t freeOutputBuffersNotOwnedByComponent();
BufferInfo *dequeueBufferFromNativeWindow();
+ void initializeFrameTracking();
+ void trackReleasedFrame(int64_t frameId, int64_t mediaTimeUs, int64_t desiredRenderTimeNs);
+ void pollForRenderedFrames();
+
inline bool storingMetadataInDecodedBuffers() {
return (mPortMode[kPortIndexOutput] == IOMX::kPortModeDynamicANWBuffer) && !mIsEncoder;
}
@@ -571,21 +584,6 @@
void processDeferredMessages();
void onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano);
- // called when we have dequeued a buffer |buf| from the native window to track render info.
- // |fenceFd| is the dequeue fence, and |info| points to the buffer info where this buffer is
- // stored.
- void updateRenderInfoForDequeuedBuffer(
- ANativeWindowBuffer *buf, int fenceFd, BufferInfo *info);
-
- // Checks to see if any frames have rendered up until |until|, and to notify client
- // (MediaCodec) of rendered frames up-until the frame pointed to by |until| or the first
- // unrendered frame. These frames are removed from the render queue.
- // If |dropIncomplete| is true, unrendered frames up-until |until| will be dropped from the
- // queue, allowing all rendered framed up till then to be notified of.
- // (This will effectively clear the render queue up-until (and including) |until|.)
- // If |until| is NULL, or is not in the rendered queue, this method will check all frames.
- void notifyOfRenderedFrames(
- bool dropIncomplete = false, FrameRenderTracker::Info *until = NULL);
void onFirstTunnelFrameReady();
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 916d41e..90347f9 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -41,7 +41,7 @@
struct BufferProducerWrapper;
class MediaCodecBuffer;
struct PersistentSurface;
-struct RenderedFrameInfo;
+class RenderedFrameInfo;
class Surface;
struct ICrypto;
class IMemory;
diff --git a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
index c14755a..cab7ecc 100644
--- a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
+++ b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
@@ -32,61 +32,59 @@
namespace android {
-// Tracks the render information about a frame. Frames go through several states while
-// the render information is tracked:
-//
-// 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
-// queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
-// Key characteristics: mFence is not NULL and mIndex is negative.
-//
-// 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
-// Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
-// invalid.
-//
-// 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
-// Key characteristics: mFence is NULL.
-//
-struct RenderedFrameInfo {
- // set by client during onFrameQueued or onFrameRendered
- int64_t getMediaTimeUs() const { return mMediaTimeUs; }
-
- // -1 if frame is not yet rendered
- nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
-
- // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
- ssize_t getIndex() const { return mIndex; }
-
- // creates information for a queued frame
- RenderedFrameInfo(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer,
- const sp<Fence> &fence)
- : mMediaTimeUs(mediaTimeUs),
- mRenderTimeNs(-1),
- mIndex(-1),
- mGraphicBuffer(graphicBuffer),
- mFence(fence) {
- }
-
- // creates information for a frame rendered on a tunneled surface
- RenderedFrameInfo(int64_t mediaTimeUs, nsecs_t renderTimeNs)
- : mMediaTimeUs(mediaTimeUs),
- mRenderTimeNs(renderTimeNs),
- mIndex(-1),
- mGraphicBuffer(NULL),
- mFence(NULL) {
- }
-
-private:
- int64_t mMediaTimeUs;
- nsecs_t mRenderTimeNs;
- ssize_t mIndex; // to be used by client
- sp<GraphicBuffer> mGraphicBuffer;
- sp<Fence> mFence;
-
- friend struct FrameRenderTracker;
-};
-
struct FrameRenderTracker {
- typedef RenderedFrameInfo Info;
+ // Tracks the render information about a frame. Frames go through several states while
+ // the render information is tracked:
+ //
+ // 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
+ // queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
+ // Key characteristics: mFence is not NULL and mIndex is negative.
+ //
+ // 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
+ // Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
+ // invalid.
+ //
+ // 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
+ // Key characteristics: mFence is NULL.
+ //
+ struct Info {
+ // set by client during onFrameQueued or onFrameRendered
+ int64_t getMediaTimeUs() const { return mMediaTimeUs; }
+
+ // -1 if frame is not yet rendered
+ nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
+
+ // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
+ ssize_t getIndex() const { return mIndex; }
+
+ // creates information for a queued frame
+ Info(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer,
+ const sp<Fence> &fence)
+ : mMediaTimeUs(mediaTimeUs),
+ mRenderTimeNs(-1),
+ mIndex(-1),
+ mGraphicBuffer(graphicBuffer),
+ mFence(fence) {
+ }
+
+ // creates information for a frame rendered on a tunneled surface
+ Info(int64_t mediaTimeUs, nsecs_t renderTimeNs)
+ : mMediaTimeUs(mediaTimeUs),
+ mRenderTimeNs(renderTimeNs),
+ mIndex(-1),
+ mGraphicBuffer(NULL),
+ mFence(NULL) {
+ }
+
+ private:
+ int64_t mMediaTimeUs;
+ nsecs_t mRenderTimeNs;
+ ssize_t mIndex; // to be used by client
+ sp<GraphicBuffer> mGraphicBuffer;
+ sp<Fence> mFence;
+
+ friend struct FrameRenderTracker;
+ };
FrameRenderTracker();
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 05bc9cc..da15ed4 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -64,6 +64,7 @@
class MediaCodecBuffer;
class IMemory;
struct PersistentSurface;
+class RenderedFrameInfo;
class SoftwareRenderer;
class Surface;
namespace hardware {
@@ -281,6 +282,8 @@
// by adding rendered frame information to a base notification message. Returns the number
// of frames that were rendered.
static size_t CreateFramesRenderedMessage(
+ const std::list<RenderedFrameInfo> &done, sp<AMessage> &msg);
+ static size_t CreateFramesRenderedMessage(
const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg);
static status_t CanFetchLinearBlock(
diff --git a/media/libstagefright/include/media/stagefright/RenderedFrameInfo.h b/media/libstagefright/include/media/stagefright/RenderedFrameInfo.h
new file mode 100644
index 0000000..4b8a58d
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/RenderedFrameInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RENDERED_FRAME_INFO_H
+#define RENDERED_FRAME_INFO_H
+
+namespace android {
+
+class RenderedFrameInfo {
+public:
+ RenderedFrameInfo(int64_t mediaTimeUs, int64_t renderTimeNs)
+ : mMediaTimeUs(mediaTimeUs), mRenderTimeNs(renderTimeNs) {}
+
+ int64_t getMediaTimeUs() const { return mMediaTimeUs; }
+ nsecs_t getRenderTimeNs() const { return mRenderTimeNs;}
+
+private:
+ int64_t mMediaTimeUs;
+ nsecs_t mRenderTimeNs;
+};
+
+} // android
+
+#endif // RENDERED_FRAME_INFO_H
\ No newline at end of file
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 5dbcd08..6068d68 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -73,14 +73,14 @@
}
bool MtpDataPacket::getUInt8(uint8_t& value) {
- if (mPacketSize - mOffset < sizeof(value))
+ if ((mPacketSize - mOffset < sizeof(value)) || (mOffset >= mBufferSize))
return false;
value = mBuffer[mOffset++];
return true;
}
bool MtpDataPacket::getUInt16(uint16_t& value) {
- if (mPacketSize - mOffset < sizeof(value))
+ if ((mPacketSize - mOffset < sizeof(value)) || ((mOffset+1) >= mBufferSize))
return false;
int offset = mOffset;
value = (uint16_t)mBuffer[offset] | ((uint16_t)mBuffer[offset + 1] << 8);
@@ -89,7 +89,7 @@
}
bool MtpDataPacket::getUInt32(uint32_t& value) {
- if (mPacketSize - mOffset < sizeof(value))
+ if ((mPacketSize - mOffset < sizeof(value)) || ((mOffset+3) >= mBufferSize))
return false;
int offset = mOffset;
value = (uint32_t)mBuffer[offset] | ((uint32_t)mBuffer[offset + 1] << 8) |
@@ -99,7 +99,7 @@
}
bool MtpDataPacket::getUInt64(uint64_t& value) {
- if (mPacketSize - mOffset < sizeof(value))
+ if ((mPacketSize - mOffset < sizeof(value)) || ((mOffset+7) >= mBufferSize))
return false;
int offset = mOffset;
value = (uint64_t)mBuffer[offset] | ((uint64_t)mBuffer[offset + 1] << 8) |
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index fded4f5..8b9dde3 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -161,11 +161,6 @@
"libgui",
],
- product_variables: {
- pdk: {
- enabled: false,
- },
- },
version_script: "libmediandk.map.txt",
stubs: {
symbol_file: "libmediandk.map.txt",
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
index 9e0d5e4..be8b2b4 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -322,7 +322,7 @@
ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
BufferInfo bufInfo;
if (mNumInFramesProvided >= mNumInFramesRequired) {
- Log.i(TAG, "Input frame limit reached");
+ Log.i(TAG, "Input frame limit reached provided: " + mNumInFramesProvided);
mIndex = mInputBufferInfo.size() - 1;
bufInfo = mInputBufferInfo.get(mIndex);
if ((bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
index 84554d3..306aeee 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
public class FrameReleaseQueue {
private static final String TAG = "FrameReleaseQueue";
@@ -28,7 +29,7 @@
private MediaCodec mCodec;
private LinkedBlockingQueue<FrameInfo> mFrameInfoQueue;
private ReleaseThread mReleaseThread;
- private boolean doFrameRelease = false;
+ private AtomicBoolean doFrameRelease = new AtomicBoolean(false);
private boolean mRender = false;
private int mWaitTime = 40; // milliseconds per frame
private int mWaitTimeCorrection = 0;
@@ -49,19 +50,19 @@
private class ReleaseThread extends Thread {
public void run() {
- int nextReleaseTime = 0;
+ long nextReleaseTime = 0;
int loopCount = 0;
- while (doFrameRelease || mFrameInfoQueue.size() > 0) {
+ while (doFrameRelease.get() || mFrameInfoQueue.size() > 0) {
FrameInfo curFrameInfo = mFrameInfoQueue.peek();
if (curFrameInfo == null) {
nextReleaseTime += mWaitTime;
} else {
- if (curFrameInfo.displayTime == 0) {
+ if (firstReleaseTime == -1 || curFrameInfo.displayTime <= 0) {
// first frame of loop
firstReleaseTime = getCurSysTime();
nextReleaseTime = firstReleaseTime + mWaitTime;
popAndRelease(curFrameInfo, true);
- } else if (!doFrameRelease && mFrameInfoQueue.size() == 1) {
+ } else if (!doFrameRelease.get() && mFrameInfoQueue.size() == 1) {
// EOS
Log.i(TAG, "EOS");
popAndRelease(curFrameInfo, false);
@@ -83,12 +84,13 @@
}
if (curFrameInfo != null && curFrameInfo.displayTime > curMediaTime) {
if ((curFrameInfo.displayTime - curMediaTime) < THRESHOLD_TIME) {
+ // release the frame now as we are already there
popAndRelease(curFrameInfo, true);
}
}
}
}
- int sleepTime = nextReleaseTime - getCurSysTime();
+ long sleepTime = nextReleaseTime - getCurSysTime();
if (sleepTime > 0) {
try {
mReleaseThread.sleep(sleepTime);
@@ -109,7 +111,7 @@
public FrameReleaseQueue(boolean render, int frameRate) {
this.mFrameInfoQueue = new LinkedBlockingQueue();
this.mReleaseThread = new ReleaseThread();
- this.doFrameRelease = true;
+ this.doFrameRelease.set(true);
this.mRender = render;
this.mWaitTime = 1000 / frameRate; // wait time in milliseconds per frame
int waitTimeRemainder = 1000 % frameRate;
@@ -163,7 +165,7 @@
}
public void stopFrameRelease() {
- doFrameRelease = false;
+ doFrameRelease.set(false);
try {
mReleaseThread.join();
Log.i(TAG, "Joined frame release thread");
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1e59bf8..761270b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1096,7 +1096,7 @@
input.sharedBuffer, sessionId, &output.flags,
callingPid, adjAttributionSource, input.clientInfo.clientTid,
&lStatus, portId, input.audioTrackCallback, isSpatialized,
- isBitPerfect);
+ isBitPerfect, &output.afTrackFlags);
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
@@ -4314,7 +4314,7 @@
response->id = idOut;
response->enabled = enabledOut != 0;
- response->effect = handle->asIEffect();
+ response->effect = handle.get() ? handle->asIEffect() : nullptr;
response->desc = VALUE_OR_RETURN_STATUS(
legacy2aidl_effect_descriptor_t_EffectDescriptor(descOut));
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index be51d51..6ee1ec9 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -398,7 +398,8 @@
audio_port_handle_t portId,
const sp<media::IAudioTrackCallback>& callback,
bool isSpatialized,
- bool isBitPerfect) = 0;
+ bool isBitPerfect,
+ audio_output_flags_t* afTrackFlags) = 0;
virtual status_t addTrack_l(const sp<IAfTrack>& track) = 0;
virtual bool destroyTrack_l(const sp<IAfTrack>& track) = 0;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 978c4aa..5f54e11 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -58,7 +58,7 @@
sp<PlayAudioOpCallback> mOpCallback;
// called by PlayAudioOpCallback when OP_PLAY_AUDIO is updated in AppOp callback
- void checkPlayAudioForUsage();
+ void checkPlayAudioForUsage(bool doBroadcast);
wp<IAfThreadBase> mThread;
std::atomic_bool mHasOpPlayAudio;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 575bcf9..a36494c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2378,7 +2378,8 @@
audio_port_handle_t portId,
const sp<media::IAudioTrackCallback>& callback,
bool isSpatialized,
- bool isBitPerfect)
+ bool isBitPerfect,
+ audio_output_flags_t *afTrackFlags)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2696,6 +2697,7 @@
if (mType == DIRECT) {
trackFlags = static_cast<audio_output_flags_t>(trackFlags | AUDIO_OUTPUT_FLAG_DIRECT);
}
+ *afTrackFlags = trackFlags;
track = IAfTrack::create(this, client, streamType, attr, sampleRate, format,
channelMask, frameCount,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 474da8e..79f75ca 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -935,7 +935,8 @@
audio_port_handle_t portId,
const sp<media::IAudioTrackCallback>& callback,
bool isSpatialized,
- bool isBitPerfect) final;
+ bool isBitPerfect,
+ audio_output_flags_t* afTrackFlags) final;
bool isTrackActive(const sp<IAfTrack>& track) const final {
return mActiveTracks.indexOf(track) >= 0;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 1a00681..ecea9eb 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -611,7 +611,9 @@
void OpPlayAudioMonitor::onFirstRef()
{
- checkPlayAudioForUsage();
+ // make sure not to broadcast the initial state since it is not needed and could
+ // cause a deadlock since this method can be called with the mThread->mLock held
+ checkPlayAudioForUsage(/*doBroadcast=*/false);
if (mAttributionSource.packageName.has_value()) {
mOpCallback = new PlayAudioOpCallback(this);
mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO,
@@ -626,7 +628,7 @@
// Note this method is never called (and never to be) for audio server / patch record track
// - not called from constructor due to check on UID,
// - not called from PlayAudioOpCallback because the callback is not installed in this case
-void OpPlayAudioMonitor::checkPlayAudioForUsage()
+void OpPlayAudioMonitor::checkPlayAudioForUsage(bool doBroadcast)
{
const bool hasAppOps = mAttributionSource.packageName.has_value()
&& mAppOpsManager.checkAudioOpNoThrow(
@@ -636,11 +638,13 @@
bool shouldChange = !hasAppOps; // check if we need to update.
if (mHasOpPlayAudio.compare_exchange_strong(shouldChange, hasAppOps)) {
ALOGD("OpPlayAudio: track:%d usage:%d %smuted", mId, mUsage, hasAppOps ? "not " : "");
- auto thread = mThread.promote();
- if (thread != nullptr && thread->type() == IAfThreadBase::OFFLOAD) {
- // Wake up Thread if offloaded, otherwise it may be several seconds for update.
- Mutex::Autolock _l(thread->mutex());
- thread->broadcast_l();
+ if (doBroadcast) {
+ auto thread = mThread.promote();
+ if (thread != nullptr && thread->type() == IAfThreadBase::OFFLOAD) {
+ // Wake up Thread if offloaded, otherwise it may be several seconds for update.
+ Mutex::Autolock _l(thread->mutex());
+ thread->broadcast_l();
+ }
}
}
}
@@ -658,7 +662,7 @@
}
sp<OpPlayAudioMonitor> monitor = mMonitor.promote();
if (monitor != NULL) {
- monitor->checkPlayAudioForUsage();
+ monitor->checkPlayAudioForUsage(/*doBroadcast=*/true);
}
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 6d3c7a5..cbab6fa 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -5892,6 +5892,8 @@
" clear-stream-use-case-override clear the stream use case override\n"
" set-zoom-override <-1/0/1> enable or disable zoom override\n"
" Valid values -1: do not override, 0: override to OFF, 1: override to ZOOM\n"
+ " set-watchdog <VALUE> enables or disables the camera service watchdog\n"
+ " Valid values 0=disable, 1=enable\n"
" watch <start|stop|dump|print|clear> manages tag monitoring in connected clients\n"
" help print this message\n");
}
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 8144792..68e9ad4 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -452,15 +452,27 @@
newFormat->setString(KEY_MIME, mimeHeic);
newFormat->setInt32(KEY_WIDTH, mOutputWidth);
newFormat->setInt32(KEY_HEIGHT, mOutputHeight);
- if (mUseGrid) {
+ }
+
+ if (mUseGrid || mUseHeic) {
+ int32_t gridRows, gridCols, tileWidth, tileHeight;
+ if (newFormat->findInt32(KEY_GRID_ROWS, &gridRows) &&
+ newFormat->findInt32(KEY_GRID_COLUMNS, &gridCols) &&
+ newFormat->findInt32(KEY_TILE_WIDTH, &tileWidth) &&
+ newFormat->findInt32(KEY_TILE_HEIGHT, &tileHeight)) {
+ mGridWidth = tileWidth;
+ mGridHeight = tileHeight;
+ mGridRows = gridRows;
+ mGridCols = gridCols;
+ } else {
newFormat->setInt32(KEY_TILE_WIDTH, mGridWidth);
newFormat->setInt32(KEY_TILE_HEIGHT, mGridHeight);
newFormat->setInt32(KEY_GRID_ROWS, mGridRows);
newFormat->setInt32(KEY_GRID_COLUMNS, mGridCols);
- int32_t left, top, right, bottom;
- if (newFormat->findRect("crop", &left, &top, &right, &bottom)) {
- newFormat->setRect("crop", 0, 0, mOutputWidth - 1, mOutputHeight - 1);
- }
+ }
+ int32_t left, top, right, bottom;
+ if (newFormat->findRect("crop", &left, &top, &right, &bottom)) {
+ newFormat->setRect("crop", 0, 0, mOutputWidth - 1, mOutputHeight - 1);
}
}
newFormat->setInt32(KEY_IS_DEFAULT, 1 /*isPrimary*/);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 52ba782..a275cfb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4014,8 +4014,11 @@
sp<Camera3Device> parent = mParent.promote();
if (parent != nullptr) {
const std::string& streamCameraId = outputStream->getPhysicalCameraId();
+ // Consider the case where clients are sending a single logical camera request
+ // to physical output/outputs
+ bool singleRequest = captureRequest->mSettingsList.size() == 1;
for (const auto& settings : captureRequest->mSettingsList) {
- if ((streamCameraId.empty() &&
+ if (((streamCameraId.empty() || singleRequest) &&
parent->getId() == settings.cameraId) ||
streamCameraId == settings.cameraId) {
outputStream->fireBufferRequestForFrameNumber(
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
index f8cdb80..e26fd28 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.cpp
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -434,7 +434,7 @@
void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
const std::vector<int>& priorities,
- const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+ const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
const PidUidVector& idList, bool reclaimed) {
// Construct the metrics for codec reclaim as a pushed atom.
// 1. Information about the requester.
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
index 3124aa2..d99c5b1 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.h
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -135,7 +135,7 @@
// To be called when after a reclaim event.
void pushReclaimAtom(const ClientInfoParcel& clientInfo,
const std::vector<int>& priorities,
- const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+ const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
const PidUidVector& idList, bool reclaimed);
// Add this pid/uid set to monitor for the process termination state.
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 23b23cc..dbde27c 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -44,47 +44,82 @@
namespace android {
-//static
-std::mutex ResourceManagerService::sCookieLock;
-//static
-uintptr_t ResourceManagerService::sCookieCounter = 0;
-//static
-std::map<uintptr_t, sp<DeathNotifier> > ResourceManagerService::sCookieToDeathNotifierMap;
+class DeathNotifier : public std::enable_shared_from_this<DeathNotifier> {
-class DeathNotifier : public RefBase {
+ // BinderDiedContext defines the cookie that is passed as DeathRecipient.
+ // Since this can maintain more context than a raw pointer, we can
+ // validate the scope of DeathNotifier, before deferencing it upon the binder death.
+ struct BinderDiedContext {
+ std::weak_ptr<DeathNotifier> mDeathNotifier;
+ };
public:
- DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
- const ClientInfoParcel& clientInfo);
+ DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
+ const std::shared_ptr<ResourceManagerService>& service,
+ const ClientInfoParcel& clientInfo,
+ AIBinder_DeathRecipient* recipient);
- virtual ~DeathNotifier() {}
+ virtual ~DeathNotifier() {
+ unlink();
+ }
+
+ void unlink() {
+ if (mClient != nullptr) {
+ // Register for the callbacks by linking to death notification.
+ AIBinder_unlinkToDeath(mClient->asBinder().get(), mRecipient, mCookie);
+ mClient = nullptr;
+ }
+ }
// Implement death recipient
static void BinderDiedCallback(void* cookie);
+ static void BinderUnlinkedCallback(void* cookie);
virtual void binderDied();
+private:
+ void link() {
+ // Create the context that is passed as cookie to the binder death notification.
+ // The context gets deleted at BinderUnlinkedCallback.
+ mCookie = new BinderDiedContext{.mDeathNotifier = weak_from_this()};
+ // Register for the callbacks by linking to death notification.
+ AIBinder_linkToDeath(mClient->asBinder().get(), mRecipient, mCookie);
+ }
+
protected:
+ std::shared_ptr<IResourceManagerClient> mClient;
std::weak_ptr<ResourceManagerService> mService;
const ClientInfoParcel mClientInfo;
+ AIBinder_DeathRecipient* mRecipient;
+ BinderDiedContext* mCookie;
};
-DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
- const ClientInfoParcel& clientInfo)
- : mService(service), mClientInfo(clientInfo) {}
+DeathNotifier::DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
+ const std::shared_ptr<ResourceManagerService>& service,
+ const ClientInfoParcel& clientInfo,
+ AIBinder_DeathRecipient* recipient)
+ : mClient(client), mService(service), mClientInfo(clientInfo),
+ mRecipient(recipient), mCookie(nullptr) {
+ link();
+}
+
+//static
+void DeathNotifier::BinderUnlinkedCallback(void* cookie) {
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+ // Since we don't need the context anymore, we are deleting it now.
+ delete context;
+}
//static
void DeathNotifier::BinderDiedCallback(void* cookie) {
- sp<DeathNotifier> notifier;
- {
- std::scoped_lock lock{ResourceManagerService::sCookieLock};
- auto it = ResourceManagerService::sCookieToDeathNotifierMap.find(
- reinterpret_cast<uintptr_t>(cookie));
- if (it == ResourceManagerService::sCookieToDeathNotifierMap.end()) {
- return;
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+
+ // Validate the context and check if the DeathNotifier object is still in scope.
+ if (context != nullptr) {
+ std::shared_ptr<DeathNotifier> thiz = context->mDeathNotifier.lock();
+ if (thiz != nullptr) {
+ thiz->binderDied();
+ } else {
+ ALOGI("DeathNotifier is out of scope already");
}
- notifier = it->second;
- }
- if (notifier.get() != nullptr) {
- notifier->binderDied();
}
}
@@ -103,9 +138,11 @@
class OverrideProcessInfoDeathNotifier : public DeathNotifier {
public:
- OverrideProcessInfoDeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
- const ClientInfoParcel& clientInfo)
- : DeathNotifier(service, clientInfo) {}
+ OverrideProcessInfoDeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
+ const std::shared_ptr<ResourceManagerService>& service,
+ const ClientInfoParcel& clientInfo,
+ AIBinder_DeathRecipient* recipient)
+ : DeathNotifier(client, service, clientInfo, recipient) {}
virtual ~OverrideProcessInfoDeathNotifier() {}
@@ -124,7 +161,7 @@
}
template <typename T>
-static String8 getString(const std::vector<T> &items) {
+static String8 getString(const std::vector<T>& items) {
String8 itemsStr;
for (size_t i = 0; i < items.size(); ++i) {
itemsStr.appendFormat("%s ", toString(items[i]).string());
@@ -165,8 +202,8 @@
static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
const ResourceInfos& infos) {
- for (size_t i = 0; i < infos.size(); ++i) {
- if (hasResourceType(type, subType, infos[i].resources)) {
+ for (const auto& [id, info] : infos) {
+ if (hasResourceType(type, subType, info.resources)) {
return true;
}
}
@@ -174,41 +211,37 @@
}
static ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map) {
- ssize_t index = map.indexOfKey(pid);
- if (index < 0) {
+ PidResourceInfosMap::iterator found = map.find(pid);
+ if (found == map.end()) {
// new pid
ResourceInfos infosForPid;
- map.add(pid, infosForPid);
+ auto [it, inserted] = map.emplace(pid, infosForPid);
+ found = it;
}
- return map.editValueFor(pid);
+ return found->second;
}
static ResourceInfo& getResourceInfoForEdit(uid_t uid, int64_t clientId,
const std::string& name,
const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos) {
- ssize_t index = infos.indexOfKey(clientId);
+ ResourceInfos::iterator found = infos.find(clientId);
- if (index < 0) {
- ResourceInfo info;
- info.uid = uid;
- info.clientId = clientId;
- if (name.empty()) {
- info.name = "<unknown client>";
- } else {
- info.name = name;
- }
- info.client = client;
- info.cookie = 0;
- info.pendingRemoval = false;
-
- index = infos.add(clientId, info);
+ if (found == infos.end()) {
+ ResourceInfo info{.uid = uid,
+ .clientId = clientId,
+ .name = name.empty()? "<unknown client>" : name,
+ .client = client,
+ .deathNotifier = nullptr,
+ .pendingRemoval = false};
+ auto [it, inserted] = infos.emplace(clientId, info);
+ found = it;
}
- return infos.editValueAt(index);
+ return found->second;
}
-static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel> &resources) {
+static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
static const char* const kServiceName = "media_resource_monitor";
sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
if (binder != NULL) {
@@ -249,7 +282,7 @@
std::map<int, int> overridePidMapCopy;
String8 serviceLog;
{
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
mapCopy = mMap; // Shadow copy, real copy will happen on write.
supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
@@ -269,8 +302,7 @@
result.append(buffer);
result.append(" Processes:\n");
- for (size_t i = 0; i < mapCopy.size(); ++i) {
- int pid = mapCopy.keyAt(i);
+ for (const auto& [pid, infos] : mapCopy) {
snprintf(buffer, SIZE, " Pid: %d\n", pid);
result.append(buffer);
int priority = 0;
@@ -281,17 +313,16 @@
}
result.append(buffer);
- const ResourceInfos &infos = mapCopy.valueAt(i);
- for (size_t j = 0; j < infos.size(); ++j) {
+ for (const auto& [infoKey, info] : infos) {
result.append(" Client:\n");
- snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
+ snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
result.append(buffer);
- std::string clientName = infos[j].name;
+ std::string clientName = info.name;
snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
result.append(buffer);
- const ResourceList &resources = infos[j].resources;
+ const ResourceList& resources = info.resources;
result.append(" Resources:\n");
for (auto it = resources.begin(); it != resources.end(); it++) {
snprintf(buffer, SIZE, " %s\n", toString(it->second).string());
@@ -347,7 +378,8 @@
mSupportsMultipleSecureCodecs(true),
mSupportsSecureWithNonSecureCodec(true),
mCpuBoostCount(0),
- mDeathRecipient(AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback)) {
+ mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback))) {
mSystemCB->noteResetVideo();
// Create ResourceManagerMetrics that handles all the metrics.
mResourceManagerMetrics = std::make_unique<ResourceManagerMetrics>(mProcessInfo);
@@ -388,7 +420,7 @@
String8 log = String8::format("config(%s)", getString(policies).string());
mServiceLog->add(log);
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
for (size_t i = 0; i < policies.size(); ++i) {
const std::string &type = policies[i].type;
const std::string &value = policies[i].value;
@@ -461,7 +493,7 @@
pid, uid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidUidTrusted(pid, uid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -502,9 +534,9 @@
mergeResources(it->second, res);
}
}
- if (info.cookie == 0 && client != nullptr) {
- info.cookie = addCookieAndLink_l(client,
- new DeathNotifier(ref<ResourceManagerService>(), clientInfo));
+ if (info.deathNotifier == nullptr && client != nullptr) {
+ info.deathNotifier = std::make_shared<DeathNotifier>(
+ client, ref<ResourceManagerService>(), clientInfo, mDeathRecipient.get());
}
if (mObserverService != nullptr && !resourceAdded.empty()) {
mObserverService->onResourceAdded(uid, pid, resourceAdded);
@@ -523,27 +555,27 @@
pid, uid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
pid, callingPid);
pid = callingPid;
}
- ssize_t index = mMap.indexOfKey(pid);
- if (index < 0) {
+ PidResourceInfosMap::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
return Status::ok();
}
- ResourceInfos &infos = mMap.editValueAt(index);
+ ResourceInfos& infos = found->second;
- index = infos.indexOfKey(clientId);
- if (index < 0) {
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
return Status::ok();
}
- ResourceInfo &info = infos.editValueAt(index);
+ ResourceInfo& info = foundClient->second;
ResourceList resourceRemoved;
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
@@ -593,27 +625,27 @@
pid, uid, (long long) clientId);
mServiceLog->add(log);
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
if (checkValid && !mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
pid, callingPid);
pid = callingPid;
}
- ssize_t index = mMap.indexOfKey(pid);
- if (index < 0) {
+ PidResourceInfosMap::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
return Status::ok();
}
- ResourceInfos &infos = mMap.editValueAt(index);
+ ResourceInfos& infos = found->second;
- index = infos.indexOfKey(clientId);
- if (index < 0) {
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
return Status::ok();
}
- const ResourceInfo &info = infos[index];
+ const ResourceInfo& info = foundClient->second;
for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
onLastRemoved(it->second, info);
}
@@ -621,20 +653,18 @@
// Since this client has been removed, update the metrics collector.
mResourceManagerMetrics->notifyClientReleased(clientInfo);
- removeCookieAndUnlink_l(info.client, info.cookie);
-
if (mObserverService != nullptr && !info.resources.empty()) {
mObserverService->onResourceRemoved(info.uid, pid, info.resources);
}
- infos.removeItemsAt(index);
+ infos.erase(foundClient);
return Status::ok();
}
void ResourceManagerService::getClientForResource_l(int callingPid,
const MediaResourceParcel *res,
PidUidVector* idVector,
- Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
+ std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
if (res == NULL) {
return;
}
@@ -653,10 +683,10 @@
mServiceLog->add(log);
*_aidl_return = false;
- Vector<std::shared_ptr<IResourceManagerClient>> clients;
+ std::vector<std::shared_ptr<IResourceManagerClient>> clients;
PidUidVector idVector;
{
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(callingPid)) {
pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
@@ -749,7 +779,7 @@
}
void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo,
- const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+ const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
const PidUidVector& idVector, bool reclaimed) {
int32_t callingPid = clientInfo.pid;
int requesterPriority = -1;
@@ -767,7 +797,7 @@
}
bool ResourceManagerService::reclaimUnconditionallyFrom(
- const Vector<std::shared_ptr<IResourceManagerClient>> &clients) {
+ const std::vector<std::shared_ptr<IResourceManagerClient>>& clients) {
if (clients.size() == 0) {
return false;
}
@@ -790,20 +820,18 @@
int failedClientPid = -1;
{
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
bool found = false;
- for (size_t i = 0; i < mMap.size(); ++i) {
- ResourceInfos &infos = mMap.editValueAt(i);
- for (size_t j = 0; j < infos.size();) {
- if (infos[j].client == failedClient) {
- j = infos.removeItemsAt(j);
+ for (auto& [pid, infos] : mMap) {
+ for (const auto& [id, info] : infos) {
+ if (info.client == failedClient) {
+ infos.erase(id);
found = true;
- } else {
- ++j;
+ break;
}
}
if (found) {
- failedClientPid = mMap.keyAt(i);
+ failedClientPid = pid;
break;
}
}
@@ -835,7 +863,7 @@
}
{
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
mOverridePidMap.erase(originalPid);
if (newPid != -1) {
mOverridePidMap.emplace(originalPid, newPid);
@@ -865,7 +893,7 @@
return Status::fromServiceSpecificError(BAD_VALUE);
}
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
removeProcessInfoOverride_l(pid);
if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
@@ -877,42 +905,16 @@
.uid = 0,
.id = 0,
.name = "<unknown client>"};
- uintptr_t cookie = addCookieAndLink_l(client,
- new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), clientInfo));
+ auto deathNotifier = std::make_shared<OverrideProcessInfoDeathNotifier>(
+ client, ref<ResourceManagerService>(), clientInfo, mDeathRecipient.get());
- mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{cookie, client});
+ mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
return Status::ok();
}
-uintptr_t ResourceManagerService::addCookieAndLink_l(
- const std::shared_ptr<IResourceManagerClient>& client, const sp<DeathNotifier>& notifier) {
- if (client == nullptr) {
- return 0;
- }
- std::scoped_lock lock{sCookieLock};
-
- uintptr_t cookie;
- // Need to skip cookie 0 (if it wraps around). ResourceInfo has cookie initialized to 0
- // indicating the death notifier is not created yet.
- while ((cookie = ++sCookieCounter) == 0);
- AIBinder_linkToDeath(client->asBinder().get(), mDeathRecipient.get(), (void*)cookie);
- sCookieToDeathNotifierMap.emplace(cookie, notifier);
-
- return cookie;
-}
-
-void ResourceManagerService::removeCookieAndUnlink_l(
- const std::shared_ptr<IResourceManagerClient>& client, uintptr_t cookie) {
- std::scoped_lock lock{sCookieLock};
- if (client != nullptr) {
- AIBinder_unlinkToDeath(client->asBinder().get(), mDeathRecipient.get(), (void*)cookie);
- }
- sCookieToDeathNotifierMap.erase(cookie);
-}
-
void ResourceManagerService::removeProcessInfoOverride(int pid) {
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
removeProcessInfoOverride_l(pid);
}
@@ -924,9 +926,6 @@
}
mProcessInfo->removeProcessInfoOverride(pid);
-
- removeCookieAndUnlink_l(it->second.client, it->second.cookie);
-
mProcessInfoOverrideMap.erase(pid);
}
@@ -938,28 +937,28 @@
pid, (long long) clientId);
mServiceLog->add(log);
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
pid, callingPid);
pid = callingPid;
}
- ssize_t index = mMap.indexOfKey(pid);
- if (index < 0) {
+ PidResourceInfosMap::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
ALOGV("markClientForPendingRemoval: didn't find pid %d for clientId %lld",
pid, (long long)clientId);
return Status::ok();
}
- ResourceInfos &infos = mMap.editValueAt(index);
+ ResourceInfos& infos = found->second;
- index = infos.indexOfKey(clientId);
- if (index < 0) {
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
ALOGV("markClientForPendingRemoval: didn't find clientId %lld", (long long) clientId);
return Status::ok();
}
- ResourceInfo &info = infos.editValueAt(index);
+ ResourceInfo& info = foundClient->second;
info.pendingRemoval = true;
return Status::ok();
}
@@ -968,9 +967,9 @@
String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid);
mServiceLog->add(log);
- Vector<std::shared_ptr<IResourceManagerClient>> clients;
+ std::vector<std::shared_ptr<IResourceManagerClient>> clients;
{
- Mutex::Autolock lock(mLock);
+ std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
@@ -992,7 +991,7 @@
std::shared_ptr<IResourceManagerClient> client;
uid_t uid = 0;
if (getBiggestClientPendingRemoval_l(pid, type, subType, uid, &client)) {
- clients.add(client);
+ clients.push_back(client);
continue;
}
}
@@ -1003,7 +1002,7 @@
uid_t uid = 0;
if (getBiggestClientPendingRemoval_l(pid, type,
MediaResource::SubType::kUnspecifiedSubType, uid, &client)) {
- clients.add(client);
+ clients.push_back(client);
}
break;
}
@@ -1031,23 +1030,22 @@
bool ResourceManagerService::getAllClients_l(int callingPid, MediaResource::Type type,
MediaResource::SubType subType,
PidUidVector* idVector,
- Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
- Vector<std::shared_ptr<IResourceManagerClient>> temp;
+ std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
+ std::vector<std::shared_ptr<IResourceManagerClient>> temp;
PidUidVector tempIdList;
- for (size_t i = 0; i < mMap.size(); ++i) {
- ResourceInfos &infos = mMap.editValueAt(i);
- for (size_t j = 0; j < infos.size(); ++j) {
- if (hasResourceType(type, subType, infos[j].resources)) {
- if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
+ for (auto& [pid, infos] : mMap) {
+ for (const auto& [id, info] : infos) {
+ if (hasResourceType(type, subType, info.resources)) {
+ if (!isCallingPriorityHigher_l(callingPid, pid)) {
// some higher/equal priority process owns the resource,
// this request can't be fulfilled.
ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
- asString(type), mMap.keyAt(i));
+ asString(type), pid);
return false;
}
- temp.push_back(infos[j].client);
- tempIdList.emplace_back(mMap.keyAt(i), infos[j].uid);
+ temp.push_back(info.client);
+ tempIdList.emplace_back(pid, info.uid);
}
}
}
@@ -1055,7 +1053,8 @@
ALOGV("getAllClients_l: didn't find any resource %s", asString(type));
return true;
}
- clients->appendVector(temp);
+
+ clients->insert(std::end(*clients), std::begin(temp), std::end(temp));
idVector->insert(std::end(*idVector), std::begin(tempIdList), std::end(tempIdList));
return true;
}
@@ -1102,17 +1101,16 @@
MediaResource::SubType subType, int *lowestPriorityPid, int *lowestPriority) {
int pid = -1;
int priority = -1;
- for (size_t i = 0; i < mMap.size(); ++i) {
- if (mMap.valueAt(i).size() == 0) {
+ for (auto& [tempPid, infos] : mMap) {
+ if (infos.size() == 0) {
// no client on this process.
continue;
}
- if (!hasResourceType(type, subType, mMap.valueAt(i))) {
+ if (!hasResourceType(type, subType, infos)) {
// doesn't have the requested resource type
continue;
}
- int tempPid = mMap.keyAt(i);
- int tempPriority;
+ int tempPriority = -1;
if (!getPriority_l(tempPid, &tempPriority)) {
ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
// TODO: remove this pid from mMap?
@@ -1155,8 +1153,8 @@
MediaResource::SubType subType, uid_t& uid,
std::shared_ptr<IResourceManagerClient> *client,
bool pendingRemovalOnly) {
- ssize_t index = mMap.indexOfKey(pid);
- if (index < 0) {
+ PidResourceInfosMap::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
ALOGE_IF(!pendingRemovalOnly,
"getBiggestClient_l: can't find resource info for pid %d", pid);
return false;
@@ -1164,10 +1162,10 @@
std::shared_ptr<IResourceManagerClient> clientTemp;
uint64_t largestValue = 0;
- const ResourceInfos &infos = mMap.valueAt(index);
- for (size_t i = 0; i < infos.size(); ++i) {
- const ResourceList &resources = infos[i].resources;
- if (pendingRemovalOnly && !infos[i].pendingRemoval) {
+ const ResourceInfos& infos = found->second;
+ for (const auto& [id, info] : infos) {
+ const ResourceList& resources = info.resources;
+ if (pendingRemovalOnly && !info.pendingRemoval) {
continue;
}
for (auto it = resources.begin(); it != resources.end(); it++) {
@@ -1175,8 +1173,8 @@
if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
- clientTemp = infos[i].client;
- uid = infos[i].uid;
+ clientTemp = info.client;
+ uid = info.uid;
}
}
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 1519e0e..aa88ac6 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -22,15 +22,13 @@
#include <set>
#include <mutex>
#include <string>
+#include <vector>
#include <aidl/android/media/BnResourceManagerService.h>
-#include <arpa/inet.h>
#include <media/MediaResource.h>
#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/threads.h>
-#include <utils/Vector.h>
namespace android {
@@ -58,7 +56,7 @@
int64_t clientId;
std::string name;
std::shared_ptr<IResourceManagerClient> client;
- uintptr_t cookie{0};
+ std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
ResourceList resources;
bool pendingRemoval{false};
};
@@ -66,9 +64,8 @@
// vector of <PID, UID>
typedef std::vector<std::pair<int32_t, uid_t>> PidUidVector;
-// TODO: convert these to std::map
-typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
-typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
+typedef std::map<int64_t, ResourceInfo> ResourceInfos;
+typedef std::map<int, ResourceInfos> PidResourceInfosMap;
class ResourceManagerService : public BnResourceManagerService {
public:
@@ -136,14 +133,15 @@
// Reclaims resources from |clients|. Returns true if reclaim succeeded
// for all clients.
- bool reclaimUnconditionallyFrom(const Vector<std::shared_ptr<IResourceManagerClient>> &clients);
+ bool reclaimUnconditionallyFrom(
+ const std::vector<std::shared_ptr<IResourceManagerClient>>& clients);
// Gets the list of all the clients who own the specified resource type.
// Returns false if any client belongs to a process with higher priority than the
// calling process. The clients will remain unchanged if returns false.
bool getAllClients_l(int callingPid, MediaResource::Type type, MediaResource::SubType subType,
PidUidVector* idList,
- Vector<std::shared_ptr<IResourceManagerClient>> *clients);
+ std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
// Gets the client who owns specified resource type from lowest possible priority process.
// Returns false if the calling process priority is not higher than the lowest process
@@ -174,7 +172,7 @@
// the result client to the given Vector.
void getClientForResource_l(int callingPid, const MediaResourceParcel *res,
PidUidVector* idList,
- Vector<std::shared_ptr<IResourceManagerClient>> *clients);
+ std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
@@ -188,13 +186,9 @@
void removeProcessInfoOverride(int pid);
void removeProcessInfoOverride_l(int pid);
- uintptr_t addCookieAndLink_l(const std::shared_ptr<IResourceManagerClient>& client,
- const sp<DeathNotifier>& notifier);
- void removeCookieAndUnlink_l(const std::shared_ptr<IResourceManagerClient>& client,
- uintptr_t cookie);
void pushReclaimAtom(const ClientInfoParcel& clientInfo,
- const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+ const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
const PidUidVector& idList, bool reclaimed);
// Get the peak concurrent pixel count (associated with the video codecs) for the process.
@@ -202,7 +196,7 @@
// Get the current concurrent pixel count (associated with the video codecs) for the process.
long getCurrentConcurrentPixelCount(int pid) const;
- mutable Mutex mLock;
+ mutable std::mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
sp<SystemCallbackInterface> mSystemCB;
sp<ServiceLog> mServiceLog;
@@ -212,15 +206,11 @@
int32_t mCpuBoostCount;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
struct ProcessInfoOverride {
- uintptr_t cookie;
+ std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
std::shared_ptr<IResourceManagerClient> client;
};
std::map<int, int> mOverridePidMap;
std::map<pid_t, ProcessInfoOverride> mProcessInfoOverrideMap;
- static std::mutex sCookieLock;
- static uintptr_t sCookieCounter GUARDED_BY(sCookieLock);
- static std::map<uintptr_t, sp<DeathNotifier> > sCookieToDeathNotifierMap
- GUARDED_BY(sCookieLock);
std::shared_ptr<ResourceObserverService> mObserverService;
std::unique_ptr<ResourceManagerMetrics> mResourceManagerMetrics;
};
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 4e575f0..ae3faea 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -131,18 +131,18 @@
const PidResourceInfosMap &map = mService->mMap;
EXPECT_EQ(2u, map.size());
- ssize_t index1 = map.indexOfKey(kTestPid1);
- ASSERT_GE(index1, 0);
- const ResourceInfos &infos1 = map[index1];
+ const auto& mapIndex1 = map.find(kTestPid1);
+ EXPECT_TRUE(mapIndex1 != map.end());
+ const ResourceInfos &infos1 = mapIndex1->second;
EXPECT_EQ(1u, infos1.size());
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, resources1);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, resources1);
- ssize_t index2 = map.indexOfKey(kTestPid2);
- ASSERT_GE(index2, 0);
- const ResourceInfos &infos2 = map[index2];
+ const auto& mapIndex2 = map.find(kTestPid2);
+ EXPECT_TRUE(mapIndex2 != map.end());
+ const ResourceInfos &infos2 = mapIndex2->second;
EXPECT_EQ(2u, infos2.size());
- expectEqResourceInfo(infos2.valueFor(getId(mTestClient2)), kTestUid2, mTestClient2, resources2);
- expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
+ expectEqResourceInfo(infos2.at(getId(mTestClient2)), kTestUid2, mTestClient2, resources2);
+ expectEqResourceInfo(infos2.at(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
}
void testCombineResourceWithNegativeValues() {
@@ -161,12 +161,12 @@
// 2) both resource entries should have been rejected, resource list should be empty.
const PidResourceInfosMap &map = mService->mMap;
EXPECT_EQ(1u, map.size());
- ssize_t index1 = map.indexOfKey(kTestPid1);
- ASSERT_GE(index1, 0);
- const ResourceInfos &infos1 = map[index1];
+ const auto& mapIndex1 = map.find(kTestPid1);
+ EXPECT_TRUE(mapIndex1 != map.end());
+ const ResourceInfos &infos1 = mapIndex1->second;
EXPECT_EQ(1u, infos1.size());
std::vector<MediaResourceParcel> expected;
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
resources1.clear();
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
@@ -181,7 +181,7 @@
// Both values should saturate to INT64_MAX
expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
resources1.clear();
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -10));
@@ -193,7 +193,7 @@
// 2) Non-drm session resource should ignore negative value addition.
expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX - 10));
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
resources1.clear();
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
@@ -206,7 +206,7 @@
expected.clear();
expected.push_back(MediaResource(MediaResource::Type::kDrmSession, 0));
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
void testConfig() {
@@ -256,9 +256,9 @@
const PidResourceInfosMap &map = mService->mMap;
EXPECT_EQ(1u, map.size());
- ssize_t index1 = map.indexOfKey(kTestPid1);
- ASSERT_GE(index1, 0);
- const ResourceInfos &infos1 = map[index1];
+ const auto& mapIndex1 = map.find(kTestPid1);
+ EXPECT_TRUE(mapIndex1 != map.end());
+ const ResourceInfos &infos1 = mapIndex1->second;
EXPECT_EQ(1u, infos1.size());
// test adding existing types to combine values
@@ -268,7 +268,7 @@
std::vector<MediaResourceParcel> expected;
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
// test adding new types (including types that differs only in subType)
resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -280,7 +280,7 @@
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
void testRemoveResource() {
@@ -299,9 +299,9 @@
const PidResourceInfosMap &map = mService->mMap;
EXPECT_EQ(1u, map.size());
- ssize_t index1 = map.indexOfKey(kTestPid1);
- ASSERT_GE(index1, 0);
- const ResourceInfos &infos1 = map[index1];
+ const auto& mapIndex1 = map.find(kTestPid1);
+ EXPECT_TRUE(mapIndex1 != map.end());
+ const ResourceInfos &infos1 = mapIndex1->second;
EXPECT_EQ(1u, infos1.size());
// test partial removal
@@ -311,13 +311,13 @@
std::vector<MediaResourceParcel> expected;
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
// test removal request with negative value, should be ignored
resources11[0].value = -10000;
mService->removeResource(client1Info, resources11);
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
// test complete removal with overshoot value
resources11[0].value = 1000;
@@ -325,7 +325,7 @@
expected.clear();
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
- expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
void testOverridePid() {
@@ -466,13 +466,12 @@
const PidResourceInfosMap &map = mService->mMap;
EXPECT_EQ(2u, map.size());
- const ResourceInfos &infos1 = map.valueFor(kTestPid1);
- const ResourceInfos &infos2 = map.valueFor(kTestPid2);
+ const ResourceInfos &infos1 = map.at(kTestPid1);
+ const ResourceInfos &infos2 = map.at(kTestPid2);
EXPECT_EQ(1u, infos1.size());
EXPECT_EQ(1u, infos2.size());
// mTestClient2 has been removed.
- // (OK to use infos2[0] as there is only 1 entry)
- EXPECT_EQ(mTestClient3, infos2[0].client);
+ EXPECT_EQ(mTestClient3, infos2.at(getId(mTestClient3)).client);
}
void testGetAllClients() {
@@ -480,7 +479,7 @@
MediaResource::Type type = MediaResource::Type::kSecureCodec;
MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
- Vector<std::shared_ptr<IResourceManagerClient> > clients;
+ std::vector<std::shared_ptr<IResourceManagerClient> > clients;
PidUidVector idList;
EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, subType, &idList, &clients));
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l