Merge "media.c2 aidl: apply interface change for IInputSurface" into main
diff --git a/camera/Android.mk b/camera/Android.mk
deleted file mode 100644
index d9068c0..0000000
--- a/camera/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-include $(call all-subdir-makefiles)
diff --git a/camera/tests/Android.bp b/camera/tests/Android.bp
new file mode 100644
index 0000000..65b8b41
--- /dev/null
+++ b/camera/tests/Android.bp
@@ -0,0 +1,52 @@
+// Copyright 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "frameworks_av_camera_license",
+ ],
+}
+
+cc_test {
+ name: "camera_client_test",
+ srcs: [
+ "VendorTagDescriptorTests.cpp",
+ "CameraBinderTests.cpp",
+ "CameraZSLTests.cpp",
+ "CameraCharacteristicsPermission.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ "libutils",
+ "libcutils",
+ "libcamera_metadata",
+ "libcamera_client",
+ "libgui",
+ "libsync",
+ "libui",
+ "libdl",
+ "libbinder",
+ ],
+ include_dirs: [
+ "system/media/private/camera/include",
+ "system/media/camera/tests",
+ "frameworks/av/services/camera/libcameraservice",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
deleted file mode 100644
index 7f8078e..0000000
--- a/camera/tests/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SRC_FILES:= \
- VendorTagDescriptorTests.cpp \
- CameraBinderTests.cpp \
- CameraZSLTests.cpp \
- CameraCharacteristicsPermission.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libutils \
- libcutils \
- libcamera_metadata \
- libcamera_client \
- libgui \
- libsync \
- libui \
- libdl \
- libbinder
-
-LOCAL_C_INCLUDES += \
- system/media/private/camera/include \
- system/media/camera/tests \
- frameworks/av/services/camera/libcameraservice \
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= camera_client_test
-LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS:= notice
-LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../NOTICE
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/media/codec2/TEST_MAPPING b/media/codec2/TEST_MAPPING
index 8a894f3..b911e11 100644
--- a/media/codec2/TEST_MAPPING
+++ b/media/codec2/TEST_MAPPING
@@ -25,5 +25,8 @@
}
]
}
+ ],
+ "postsubmit": [
+ { "name": "c2aidl_gtracker_test"}
]
}
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
index 10e4b79..76680a3 100644
--- a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
+++ b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
@@ -648,6 +648,24 @@
if (res == 0) {
ALOGV("dav1d found a sequenceHeader (%dx%d) for in_frameIndex=%ld.", seq.max_width,
seq.max_height, (long)in_frameIndex);
+ if (seq.max_width != mWidth || seq.max_height != mHeight) {
+ drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
+ mWidth = seq.max_width;
+ mHeight = seq.max_height;
+
+ C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+ if (err == C2_OK) {
+ work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
+ } else {
+ ALOGE("Config update size failed");
+ mSignalledError = true;
+ work->result = C2_CORRUPTED;
+ work->workletsProcessed = 1u;
+ return;
+ }
+ }
}
// insert OBU TD if it is not present.
@@ -921,26 +939,6 @@
return false;
}
- const int width = img.p.w;
- const int height = img.p.h;
- if (width != mWidth || height != mHeight) {
- mWidth = width;
- mHeight = height;
-
- C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
- std::vector<std::unique_ptr<C2SettingResult>> failures;
- c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
- if (err == C2_OK) {
- work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
- } else {
- ALOGE("Config update size failed");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- work->workletsProcessed = 1u;
- return false;
- }
- }
-
getVuiParams(&img);
// out_frameIndex that the decoded picture returns from dav1d.
diff --git a/media/codec2/components/raw/C2SoftRawDec.cpp b/media/codec2/components/raw/C2SoftRawDec.cpp
index a03d4e2..ea13071 100644
--- a/media/codec2/components/raw/C2SoftRawDec.cpp
+++ b/media/codec2/components/raw/C2SoftRawDec.cpp
@@ -65,7 +65,7 @@
addParameter(
DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
.withDefault(new C2StreamChannelCountInfo::output(0u, 2))
- .withFields({C2F(mChannelCount, value).inRange(1, 8)})
+ .withFields({C2F(mChannelCount, value).inRange(1, 12)})
.withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
.build());
diff --git a/media/codec2/hal/aidl/Configurable.cpp b/media/codec2/hal/aidl/Configurable.cpp
index 051e38a..2daaac2 100644
--- a/media/codec2/hal/aidl/Configurable.cpp
+++ b/media/codec2/hal/aidl/Configurable.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
+#include <android-base/hex.h>
#include <codec2/aidl/Configurable.h>
#include <codec2/aidl/ParamTypes.h>
@@ -135,8 +136,6 @@
LOG(WARNING) << "querySupportedParams -- invalid output params.";
break;
}
- } else {
- res = Status::BAD_INDEX;
}
}
paramDesc->resize(dstIx);
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 0848fc6..01b0678 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -174,20 +174,16 @@
GraphicsTracker::GraphicsTracker(int maxDequeueCount)
: mBufferCache(new BufferCache()), mMaxDequeue{maxDequeueCount},
- mMaxDequeueRequested{maxDequeueCount},
mMaxDequeueCommitted{maxDequeueCount},
- mMaxDequeueRequestedSeqId{0UL}, mMaxDequeueCommittedSeqId{0ULL},
mDequeueable{maxDequeueCount},
mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0},
mInConfig{false}, mStopped{false} {
if (maxDequeueCount < kMaxDequeueMin) {
mMaxDequeue = kMaxDequeueMin;
- mMaxDequeueRequested = kMaxDequeueMin;
mMaxDequeueCommitted = kMaxDequeueMin;
mDequeueable = kMaxDequeueMin;
} else if(maxDequeueCount > kMaxDequeueMax) {
mMaxDequeue = kMaxDequeueMax;
- mMaxDequeueRequested = kMaxDequeueMax;
mMaxDequeueCommitted = kMaxDequeueMax;
mDequeueable = kMaxDequeueMax;
}
@@ -197,34 +193,36 @@
mReadPipeFd.reset(pipefd[0]);
mWritePipeFd.reset(pipefd[1]);
- mEventQueueThread = std::thread([this](){processEvent();});
- writeIncDequeueable(mDequeueable);
+ // ctor does not require lock to be held.
+ writeIncDequeueableLocked(mDequeueable);
CHECK(ret >= 0);
- CHECK(mEventQueueThread.joinable());
}
GraphicsTracker::~GraphicsTracker() {
stop();
- if (mEventQueueThread.joinable()) {
- mEventQueueThread.join();
- }
}
bool GraphicsTracker::adjustDequeueConfLocked(bool *updateDequeue) {
// TODO: can't we adjust during config? not committing it may safe?
*updateDequeue = false;
- if (!mInConfig && mMaxDequeueRequested < mMaxDequeue) {
- int delta = mMaxDequeue - mMaxDequeueRequested;
+ if (!mInConfig && mMaxDequeueRequested.has_value() && mMaxDequeueRequested < mMaxDequeue) {
+ int delta = mMaxDequeue - mMaxDequeueRequested.value();
+ int drained = 0;
// Since we are supposed to increase mDequeuable by one already
int adjustable = mDequeueable + 1;
if (adjustable >= delta) {
- mMaxDequeue = mMaxDequeueRequested;
+ mMaxDequeue = mMaxDequeueRequested.value();
mDequeueable -= (delta - 1);
+ drained = delta - 1;
} else {
mMaxDequeue -= adjustable;
+ drained = mDequeueable;
mDequeueable = 0;
}
+ if (drained > 0) {
+ drainDequeueableLocked(drained);
+ }
if (mMaxDequeueRequested == mMaxDequeue && mMaxDequeueRequested != mMaxDequeueCommitted) {
*updateDequeue = true;
}
@@ -235,6 +233,7 @@
c2_status_t GraphicsTracker::configureGraphics(
const sp<IGraphicBufferProducer>& igbp, uint32_t generation) {
+ // TODO: wait until operations to previous IGBP is completed.
std::shared_ptr<BufferCache> prevCache;
int prevDequeueCommitted;
@@ -254,14 +253,28 @@
if (igbp) {
ret = igbp->getUniqueId(&bqId);
}
- if (ret != ::android::OK || prevCache->mGeneration == generation || prevCache->mBqId == bqId) {
+ if (ret != ::android::OK ||
+ prevCache->mGeneration == generation) {
+ ALOGE("new surface configure fail due to wrong or same bqId or same generation:"
+ "igbp(%d:%llu -> %llu), gen(%lu -> %lu)", (bool)igbp,
+ (unsigned long long)prevCache->mBqId, (unsigned long long)bqId,
+ (unsigned long)prevCache->mGeneration, (unsigned long)generation);
+ std::unique_lock<std::mutex> l(mLock);
+ mInConfig = false;
return C2_BAD_VALUE;
}
- ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted);
- if (ret != ::android::OK) {
- // TODO: sort out the error from igbp and return an error accordingly.
- return C2_CORRUPTED;
+ if (igbp) {
+ ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted);
+ if (ret != ::android::OK) {
+ ALOGE("new surface maxDequeueBufferCount configure fail");
+ // TODO: sort out the error from igbp and return an error accordingly.
+ std::unique_lock<std::mutex> l(mLock);
+ mInConfig = false;
+ return C2_CORRUPTED;
+ }
}
+ ALOGD("new surface configured with id:%llu gen:%lu maxDequeue:%d",
+ (unsigned long long)bqId, (unsigned long)generation, prevDequeueCommitted);
std::shared_ptr<BufferCache> newCache = std::make_shared<BufferCache>(bqId, generation, igbp);
{
std::unique_lock<std::mutex> l(mLock);
@@ -283,59 +296,74 @@
// (Sometimes maxDequeueCount cannot be committed if the number of
// dequeued buffer count is bigger.)
int maxDequeueToCommit;
- // max dequeue count which is committed to IGBP currently
- // (actually mMaxDequeueCommitted, but needs to be read outside lock.)
- int curMaxDequeueCommitted;
std::unique_lock<std::mutex> cl(mConfigLock);
{
std::unique_lock<std::mutex> l(mLock);
- if (mMaxDequeueRequested == maxDequeueCount) {
+ if (mMaxDequeueRequested.has_value()) {
+ if (mMaxDequeueRequested == maxDequeueCount) {
+ ALOGD("maxDequeueCount requested with %d already", maxDequeueCount);
+ return C2_OK;
+ }
+ } else if (mMaxDequeue == maxDequeueCount) {
+ ALOGD("maxDequeueCount is already %d", maxDequeueCount);
return C2_OK;
}
mInConfig = true;
mMaxDequeueRequested = maxDequeueCount;
cache = mBufferCache;
- curMaxDequeueCommitted = mMaxDequeueCommitted;
if (mMaxDequeue <= maxDequeueCount) {
maxDequeueToCommit = maxDequeueCount;
} else {
// Since mDequeuable is decreasing,
// a delievered ready to allocate event may not be fulfilled.
// Another waiting via a waitable object may be necessary in the case.
- int delta = mMaxDequeue - maxDequeueCount;
- if (delta <= mDequeueable) {
- maxDequeueToCommit = maxDequeueCount;
- mDequeueable -= delta;
- } else {
- maxDequeueToCommit = mMaxDequeue - mDequeueable;
- mDequeueable = 0;
+ int delta = std::min(mMaxDequeue - maxDequeueCount, mDequeueable);
+ maxDequeueToCommit = mMaxDequeue - delta;
+ mDequeueable -= delta;
+ if (delta > 0) {
+ drainDequeueableLocked(delta);
}
}
}
bool committed = true;
- if (cache->mIgbp && maxDequeueToCommit != curMaxDequeueCommitted) {
+ if (cache->mIgbp && maxDequeueToCommit != mMaxDequeueCommitted) {
::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(maxDequeueToCommit);
committed = (ret == ::android::OK);
- if (!committed) {
+ if (committed) {
+ ALOGD("maxDequeueCount committed to IGBP: %d", maxDequeueToCommit);
+ } else {
// This should not happen.
- ALOGE("dequeueCount failed with error(%d)", (int)ret);
+ ALOGE("maxdequeueCount update to IGBP failed with error(%d)", (int)ret);
}
}
+ int oldMaxDequeue = 0;
+ int requested = 0;
{
std::unique_lock<std::mutex> l(mLock);
mInConfig = false;
+ oldMaxDequeue = mMaxDequeue;
+ mMaxDequeue = maxDequeueToCommit; // we already drained dequeueable
if (committed) {
+ clearCacheIfNecessaryLocked(cache, maxDequeueToCommit);
mMaxDequeueCommitted = maxDequeueToCommit;
- int delta = mMaxDequeueCommitted - mMaxDequeue;
+ if (mMaxDequeueRequested == mMaxDequeueCommitted &&
+ mMaxDequeueRequested == mMaxDequeue) {
+ mMaxDequeueRequested.reset();
+ }
+ if (mMaxDequeueRequested.has_value()) {
+ requested = mMaxDequeueRequested.value();
+ }
+ int delta = mMaxDequeueCommitted - oldMaxDequeue;
if (delta > 0) {
mDequeueable += delta;
- l.unlock();
- writeIncDequeueable(delta);
+ writeIncDequeueableLocked(delta);
}
}
}
+ ALOGD("maxDqueueCount change %d -> %d: pending: %d",
+ oldMaxDequeue, maxDequeueToCommit, requested);
if (!committed) {
return C2_CORRUPTED;
@@ -350,48 +378,60 @@
std::unique_lock<std::mutex> cl(mConfigLock);
{
std::unique_lock<std::mutex> l(mLock);
- if (mMaxDequeue == mMaxDequeueRequested && mMaxDequeueCommitted != mMaxDequeueRequested) {
- dequeueCommit = mMaxDequeue;
- mInConfig = true;
- cache = mBufferCache;
- } else {
+ if (!mMaxDequeueRequested.has_value() || mMaxDequeue != mMaxDequeueRequested) {
return;
}
+ if (mMaxDequeueCommitted == mMaxDequeueRequested) {
+ // already committed. may not happen.
+ mMaxDequeueRequested.reset();
+ return;
+ }
+ dequeueCommit = mMaxDequeue;
+ mInConfig = true;
+ cache = mBufferCache;
}
bool committed = true;
if (cache->mIgbp) {
::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(dequeueCommit);
committed = (ret == ::android::OK);
- if (!committed) {
+ if (committed) {
+ ALOGD("delayed maxDequeueCount update to IGBP: %d", dequeueCommit);
+ } else {
// This should not happen.
- ALOGE("dequeueCount failed with error(%d)", (int)ret);
+ ALOGE("delayed maxdequeueCount update to IGBP failed with error(%d)", (int)ret);
}
}
- int cleared = 0;
{
// cache == mCache here, since we locked config.
std::unique_lock<std::mutex> l(mLock);
mInConfig = false;
if (committed) {
- if (cache->mIgbp && dequeueCommit < mMaxDequeueCommitted) {
- // we are shrinking # of buffers, so clearing the cache.
- for (auto it = cache->mBuffers.begin(); it != cache->mBuffers.end();) {
- uint64_t bid = it->second->mId;
- if (mDequeued.count(bid) == 0 || mDeallocating.count(bid) > 0) {
- ++cleared;
- it = cache->mBuffers.erase(it);
- } else {
- ++it;
- }
- }
- }
+ clearCacheIfNecessaryLocked(cache, dequeueCommit);
mMaxDequeueCommitted = dequeueCommit;
}
+ mMaxDequeueRequested.reset();
}
- if (cleared > 0) {
- ALOGD("%d buffers are cleared from cache, due to IGBP capacity change", cleared);
- }
+}
+void GraphicsTracker::clearCacheIfNecessaryLocked(const std::shared_ptr<BufferCache> &cache,
+ int maxDequeueCommitted) {
+ int cleared = 0;
+ size_t origCacheSize = cache->mBuffers.size();
+ if (cache->mIgbp && maxDequeueCommitted < mMaxDequeueCommitted) {
+ // we are shrinking # of buffers in the case, so evict the previous
+ // cached buffers.
+ for (auto it = cache->mBuffers.begin(); it != cache->mBuffers.end();) {
+ uint64_t bid = it->second->mId;
+ if (mDequeued.count(bid) == 0 || mDeallocating.count(bid) > 0) {
+ ++cleared;
+ it = cache->mBuffers.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ ALOGD("Cache size %zu -> %zu: maybe_cleared(%d), dequeued(%zu)",
+ origCacheSize, cache->mBuffers.size(), cleared, mDequeued.size());
}
int GraphicsTracker::getCurDequeueable() {
@@ -400,70 +440,58 @@
}
void GraphicsTracker::stop() {
- bool expected = false;
- std::unique_lock<std::mutex> l(mEventLock);
- bool updated = mStopped.compare_exchange_strong(expected, true);
- if (updated) {
- int writeFd = mWritePipeFd.release();
+ // TODO: wait until all operation to current IGBP
+ // being completed.
+ std::unique_lock<std::mutex> l(mLock);
+ if (mStopped) {
+ return;
+ }
+ mStopped = true;
+ int writeFd = mWritePipeFd.release();
+ if (writeFd >= 0) {
::close(writeFd);
- int readFd = mReadPipeFd.release();
- ::close(readFd);
- mEventCv.notify_one();
}
}
-void GraphicsTracker::writeIncDequeueable(int inc) {
+void GraphicsTracker::writeIncDequeueableLocked(int inc) {
CHECK(inc > 0 && inc < kMaxDequeueMax);
thread_local char buf[kMaxDequeueMax];
- int diff = 0;
- {
- std::unique_lock<std::mutex> l(mEventLock);
- if (mStopped) {
- return;
- }
- CHECK(mWritePipeFd.get() >= 0);
- int ret = ::write(mWritePipeFd.get(), buf, inc);
- if (ret == inc) {
- return;
- }
- diff = ret < 0 ? inc : inc - ret;
-
- // Partial write or EINTR. This will not happen in a real scenario.
- mIncDequeueable += diff;
- if (mIncDequeueable > 0) {
- l.unlock();
- mEventCv.notify_one();
- ALOGW("updating dequeueable to pipefd pending");
- }
+ if (mStopped) { // reading end closed;
+ return;
}
+ int writeFd = mWritePipeFd.get();
+ if (writeFd < 0) {
+ // initialization fail and not valid though.
+ return;
+ }
+ int ret = ::write(writeFd, buf, inc);
+ // Since this is non-blocking i/o, it never returns EINTR.
+ //
+ // ::write() to pipe guarantee to succeed atomically if it writes less than
+ // the given PIPE_BUF. And the buffer size in pipe/fifo is at least 4K and our total
+ // max pending buffer size is 64. So it never returns EAGAIN here either.
+ // See pipe(7) for further information.
+ //
+ // Other errors are serious errors and we cannot synchronize mDequeueable to
+ // length of pending buffer in pipe/fifo anymore. So better to abort here.
+ // TODO: do not abort here. (b/318717399)
+ CHECK(ret == inc);
}
-void GraphicsTracker::processEvent() {
- // This is for partial/failed writes to the writing end.
- // This may not happen in the real scenario.
+void GraphicsTracker::drainDequeueableLocked(int dec) {
+ CHECK(dec > 0 && dec < kMaxDequeueMax);
thread_local char buf[kMaxDequeueMax];
- while (true) {
- std::unique_lock<std::mutex> l(mEventLock);
- if (mStopped) {
- break;
- }
- if (mIncDequeueable > 0) {
- int inc = mIncDequeueable > kMaxDequeueMax ? kMaxDequeueMax : mIncDequeueable;
- int ret = ::write(mWritePipeFd.get(), buf, inc);
- int written = ret <= 0 ? 0 : ret;
- mIncDequeueable -= written;
- if (mIncDequeueable > 0) {
- l.unlock();
- if (ret < 0) {
- ALOGE("write to writing end failed %d", errno);
- } else {
- ALOGW("partial write %d(%d)", inc, written);
- }
- continue;
- }
- }
- mEventCv.wait(l);
+ if (mStopped) {
+ return;
}
+ int readFd = mReadPipeFd.get();
+ if (readFd < 0) {
+ // initializationf fail and not valid though.
+ return;
+ }
+ int ret = ::read(readFd, buf, dec);
+ // TODO: no dot abort here. (b/318717399)
+ CHECK(ret == dec);
}
c2_status_t GraphicsTracker::getWaitableFd(int *pipeFd) {
@@ -539,8 +567,7 @@
return;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
}
@@ -715,14 +742,13 @@
return C2_OK;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
return C2_OK;
}
void GraphicsTracker::commitDeallocate(
- std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid) {
+ std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid, bool *updateDequeue) {
std::unique_lock<std::mutex> l(mLock);
size_t del1 = mDequeued.erase(bid);
size_t del2 = mDeallocating.erase(bid);
@@ -730,9 +756,11 @@
if (cache) {
cache->unblockSlot(slotId);
}
+ if (adjustDequeueConfLocked(updateDequeue)) {
+ return;
+ }
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
@@ -758,7 +786,10 @@
// cache->mIgbp is not null, if completed is false.
(void)cache->mIgbp->cancelBuffer(slotId, rFence);
- commitDeallocate(cache, slotId, bid);
+ commitDeallocate(cache, slotId, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_OK;
}
@@ -785,8 +816,7 @@
return C2_BAD_STATE;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
return C2_BAD_STATE;
}
std::shared_ptr<BufferItem> buffer = it->second;
@@ -828,8 +858,7 @@
return;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
return;
}
}
@@ -843,6 +872,9 @@
ALOGE("retrieving AHB-ID for GraphicBlock failed");
return C2_CORRUPTED;
}
+ std::shared_ptr<_C2BlockPoolData> poolData =
+ _C2BlockFactory::GetGraphicBlockPoolData(blk);
+ _C2BlockFactory::DisownIgbaBlock(poolData);
std::shared_ptr<BufferCache> cache;
std::shared_ptr<BufferItem> buffer;
std::shared_ptr<BufferItem> oldBuffer;
@@ -870,13 +902,19 @@
if (!gb) {
ALOGE("render: realloc-ing a new buffer for migration failed");
std::shared_ptr<BufferCache> nullCache;
- commitDeallocate(nullCache, -1, bid);
+ commitDeallocate(nullCache, -1, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_REFUSED;
}
if (cache->mIgbp->attachBuffer(&(newBuffer->mSlot), gb) != ::android::OK) {
ALOGE("render: attaching a new buffer to IGBP failed");
std::shared_ptr<BufferCache> nullCache;
- commitDeallocate(nullCache, -1, bid);
+ commitDeallocate(nullCache, -1, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_REFUSED;
}
cache->waitOnSlot(newBuffer->mSlot);
@@ -890,11 +928,13 @@
CHECK(renderRes != ::android::BAD_VALUE);
ALOGE("render: failed to queueBuffer() err = %d", renderRes);
(void) cache->mIgbp->cancelBuffer(buffer->mSlot, input.fence);
- commitDeallocate(cache, buffer->mSlot, bid);
+ commitDeallocate(cache, buffer->mSlot, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_REFUSED;
}
- updateDequeue = false;
commitRender(cache, buffer, oldBuffer, output->bufferReplaced, &updateDequeue);
if (updateDequeue) {
updateDequeueConf();
@@ -909,8 +949,7 @@
if (mBufferCache->mGeneration == generation) {
if (!adjustDequeueConfLocked(&updateDequeue)) {
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
}
}
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index b872cea..85b5ec8 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -649,8 +649,8 @@
return C2_CORRUPTED;
}
size_t i = 0;
- for (auto it = paramPointers.begin();
- it != paramPointers.end(); ) {
+ size_t numUpdatedStackParams = 0;
+ for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
C2Param* paramPointer = *it;
if (numStackIndices > 0) {
--numStackIndices;
@@ -677,7 +677,9 @@
status = C2_BAD_INDEX;
continue;
}
- if (!stackParams[i++]->updateFrom(*paramPointer)) {
+ if (stackParams[i++]->updateFrom(*paramPointer)) {
+ ++numUpdatedStackParams;
+ } else {
LOG(WARNING) << "query -- param update failed: "
"index = "
<< paramPointer->index() << ".";
@@ -697,6 +699,13 @@
}
++it;
}
+ size_t numQueried = numUpdatedStackParams;
+ if (heapParams) {
+ numQueried += heapParams->size();
+ }
+ if (status == C2_OK && indices.size() != numQueried) {
+ status = C2_BAD_INDEX;
+ }
return status;
}
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 4640243..dd6c869 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -27,6 +27,7 @@
#include <mutex>
#include <set>
#include <thread>
+#include <optional>
#include <C2Buffer.h>
@@ -234,12 +235,14 @@
std::map<uint64_t, std::shared_ptr<BufferItem>> mDequeued;
std::set<uint64_t> mDeallocating;
+ // These member variables are read and modified accessed as follows.
+ // 1. mConfigLock being held
+ // Set mInConfig true with mLock in the beginning
+ // Clear mInConfig with mLock in the end
+ // 2. mLock is held and mInConfig is false.
int mMaxDequeue;
- int mMaxDequeueRequested;
int mMaxDequeueCommitted;
-
- uint32_t mMaxDequeueRequestedSeqId;
- uint32_t mMaxDequeueCommittedSeqId;
+ std::optional<int> mMaxDequeueRequested;
int mDequeueable;
@@ -271,13 +274,6 @@
::android::base::unique_fd mWritePipeFd; // The writing end file descriptor
std::atomic<bool> mStopped;
- std::thread mEventQueueThread; // Thread to handle interrupted
- // writes to the writing end.
- std::mutex mEventLock;
- std::condition_variable mEventCv;
-
- bool mStopEventThread;
- int mIncDequeueable; // pending # of write to increase dequeueable eventfd
private:
explicit GraphicsTracker(int maxDequeueCount);
@@ -289,6 +285,9 @@
bool adjustDequeueConfLocked(bool *updateDequeueConf);
void updateDequeueConf();
+ void clearCacheIfNecessaryLocked(
+ const std::shared_ptr<BufferCache> &cache,
+ int maxDequeueCommitted);
c2_status_t requestAllocate(std::shared_ptr<BufferCache> *cache);
c2_status_t requestDeallocate(uint64_t bid, const sp<Fence> &fence,
@@ -305,7 +304,9 @@
bool cached, int slotId, const sp<Fence> &fence,
std::shared_ptr<BufferItem> *buffer,
bool *updateDequeue);
- void commitDeallocate(std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid);
+ void commitDeallocate(std::shared_ptr<BufferCache> &cache,
+ int slotId, uint64_t bid,
+ bool *updateDequeue);
void commitRender(const std::shared_ptr<BufferCache> &cache,
const std::shared_ptr<BufferItem> &buffer,
const std::shared_ptr<BufferItem> &oldBuffer,
@@ -318,8 +319,8 @@
bool *cached, int *rSlotId, sp<Fence> *rFence,
std::shared_ptr<BufferItem> *buffer);
- void writeIncDequeueable(int inc);
- void processEvent();
+ void writeIncDequeueableLocked(int inc);
+ void drainDequeueableLocked(int dec);
};
} // namespace aidl::android::hardware::media::c2::implementation
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index fdb28f4..df89510 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -29,6 +29,7 @@
#include <C2BufferPriv.h>
#include <C2Config.h>
#include <C2Debug.h>
+#include <codec2/common/HalSelection.h>
#include <codec2/hidl/client.h>
#include <gui/BufferQueue.h>
#include <gui/IConsumerListener.h>
@@ -407,30 +408,45 @@
surfaceMode_t surfMode) {
using namespace android;
sp<IGraphicBufferProducer> producer = nullptr;
+ sp<IGraphicBufferConsumer> consumer = nullptr;
+ sp<GLConsumer> texture = nullptr;
+ sp<ANativeWindow> surface = nullptr;
static std::atomic_uint32_t surfaceGeneration{0};
uint32_t generation =
(getpid() << 10) |
((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1) & ((1 << 10) - 1));
int32_t maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth;
+ C2BlockPool::local_id_t poolId = C2BlockPool::BASIC_GRAPHIC;
+ std::shared_ptr<Codec2Client::Configurable> configurable;
+ bool aidl = ::android::IsCodec2AidlHalSelected();
+ if (aidl) {
+ // AIDL does not support blockpool-less mode.
+ c2_status_t poolRet = component->createBlockPool(
+ C2PlatformAllocatorStore::IGBA, &poolId, &configurable);
+ ASSERT_EQ(poolRet, C2_OK) << "setOutputSurface failed";
+ }
+
if (surfMode == SURFACE) {
- sp<IGraphicBufferConsumer> consumer = nullptr;
BufferQueue::createBufferQueue(&producer, &consumer);
ASSERT_NE(producer, nullptr) << "createBufferQueue returned invalid producer";
ASSERT_NE(consumer, nullptr) << "createBufferQueue returned invalid consumer";
- sp<GLConsumer> texture =
+ texture =
new GLConsumer(consumer, 0 /* tex */, GLConsumer::TEXTURE_EXTERNAL,
true /* useFenceSync */, false /* isControlledByApp */);
- sp<ANativeWindow> gSurface = new Surface(producer);
- ASSERT_NE(gSurface, nullptr) << "getSurface failed";
+ surface = new Surface(producer);
+ ASSERT_NE(surface, nullptr) << "failed to create Surface object";
producer->setGenerationNumber(generation);
}
- c2_status_t err = component->setOutputSurface(C2BlockPool::BASIC_GRAPHIC, producer, generation,
+ c2_status_t err = component->setOutputSurface(poolId, producer, generation,
maxDequeueBuffers);
- ASSERT_EQ(err, C2_OK) << "setOutputSurface failed";
+ std::string surfStr = surfMode == NO_SURFACE ? "NO_SURFACE" :
+ (surfMode == NULL_SURFACE ? "NULL_SURFACE" : "WITH_SURFACE");
+
+ ASSERT_EQ(err, C2_OK) << "setOutputSurface failed, surfMode: " << surfStr;
}
void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index fbb4f18..8ecb9c0 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <android/binder_process.h>
+#include <codec2/common/HalSelection.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <stdio.h>
@@ -71,7 +72,9 @@
std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mGraphicAllocator),
C2_OK);
- mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++);
+ C2PooledBlockPool::BufferPoolVer ver = ::android::IsCodec2AidlHalSelected() ?
+ C2PooledBlockPool::VER_AIDL2 : C2PooledBlockPool::VER_HIDL;
+ mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++, ver);
ASSERT_NE(mGraphicPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 3bb6593..5c1755e 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1049,7 +1049,11 @@
// Unwrap raw buffer handle from the C2Handle
native_handle_t *nh = UnwrapNativeCodec2GrallocHandle(handle);
if (!nh) {
- return;
+ nh = UnwrapNativeCodec2AhwbHandle(handle);
+ if (!nh) {
+ ALOGE("handle is not compatible to neither C2HandleGralloc nor C2HandleAhwb");
+ return;
+ }
}
// Import the raw handle so IMapper can use the buffer. The imported
// handle must be freed when the client is done with the buffer.
diff --git a/media/codec2/tests/aidl/Android.bp b/media/codec2/tests/aidl/Android.bp
new file mode 100644
index 0000000..2ad245c
--- /dev/null
+++ b/media/codec2/tests/aidl/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_test {
+ name: "c2aidl_gtracker_test",
+ test_suites: ["device-tests"],
+ defaults: [
+ "libcodec2-aidl-client-defaults",
+ ],
+
+ header_libs: [
+ "libcodec2_client_headers",
+ "libcodec2_internal",
+ "libcodec2_vndk_headers",
+ ],
+
+ srcs: [
+ "GraphicsTracker_test.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcodec2_client",
+ "libgui",
+ "libnativewindow",
+ "libui",
+ ],
+}
diff --git a/media/codec2/tests/aidl/GraphicsTracker_test.cpp b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
new file mode 100644
index 0000000..9008086
--- /dev/null
+++ b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
@@ -0,0 +1,820 @@
+/*
+ * Copyright (C) 2023 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 "GraphicsTracker_test"
+#include <unistd.h>
+
+#include <android/hardware_buffer.h>
+#include <codec2/aidl/GraphicsTracker.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
+#include <gui/IConsumerListener.h>
+#include <gui/Surface.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
+#include <C2BlockInternal.h>
+#include <C2FenceFactory.h>
+
+#include <atomic>
+#include <memory>
+#include <iostream>
+#include <thread>
+
+using ::aidl::android::hardware::media::c2::implementation::GraphicsTracker;
+using ::android::BufferItem;
+using ::android::BufferQueue;
+using ::android::Fence;
+using ::android::GraphicBuffer;
+using ::android::IGraphicBufferProducer;
+using ::android::IGraphicBufferConsumer;
+using ::android::IProducerListener;
+using ::android::IConsumerListener;
+using ::android::OK;
+using ::android::sp;
+using ::android::wp;
+
+namespace {
+struct BqStatistics {
+ std::atomic<int> mDequeued;
+ std::atomic<int> mQueued;
+ std::atomic<int> mBlocked;
+ std::atomic<int> mDropped;
+ std::atomic<int> mDiscarded;
+ std::atomic<int> mReleased;
+
+ void log() {
+ ALOGD("Dequeued: %d, Queued: %d, Blocked: %d, "
+ "Dropped: %d, Discarded %d, Released %d",
+ (int)mDequeued, (int)mQueued, (int)mBlocked,
+ (int)mDropped, (int)mDiscarded, (int)mReleased);
+ }
+
+ void clear() {
+ mDequeued = 0;
+ mQueued = 0;
+ mBlocked = 0;
+ mDropped = 0;
+ mDiscarded = 0;
+ mReleased = 0;
+ }
+};
+
+struct DummyConsumerListener : public android::BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+};
+
+struct TestConsumerListener : public android::BnConsumerListener {
+ TestConsumerListener(const sp<IGraphicBufferConsumer> &consumer)
+ : BnConsumerListener(), mConsumer(consumer) {}
+ void onFrameAvailable(const BufferItem&) override {
+ constexpr static int kRenderDelayUs = 1000000/30; // 30fps
+ BufferItem buffer;
+ // consume buffer
+ sp<IGraphicBufferConsumer> consumer = mConsumer.promote();
+ if (consumer != nullptr && consumer->acquireBuffer(&buffer, 0) == android::NO_ERROR) {
+ ::usleep(kRenderDelayUs);
+ consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, buffer.mFence);
+ }
+ }
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+
+ wp<IGraphicBufferConsumer> mConsumer;
+};
+
+struct TestProducerListener : public android::BnProducerListener {
+ TestProducerListener(std::shared_ptr<GraphicsTracker> tracker,
+ std::shared_ptr<BqStatistics> &stat,
+ uint32_t generation) : BnProducerListener(),
+ mTracker(tracker), mStat(stat), mGeneration(generation) {}
+ virtual void onBufferReleased() override {
+ auto tracker = mTracker.lock();
+ if (tracker) {
+ mStat->mReleased++;
+ tracker->onReleased(mGeneration);
+ }
+ }
+ virtual bool needsReleaseNotify() override { return true; }
+ virtual void onBuffersDiscarded(const std::vector<int32_t>&) override {}
+
+ std::weak_ptr<GraphicsTracker> mTracker;
+ std::shared_ptr<BqStatistics> mStat;
+ uint32_t mGeneration;
+};
+
+struct Frame {
+ AHardwareBuffer *buffer_;
+ sp<Fence> fence_;
+
+ Frame() : buffer_{nullptr}, fence_{nullptr} {}
+ Frame(AHardwareBuffer *buffer, sp<Fence> fence)
+ : buffer_(buffer), fence_(fence) {}
+ ~Frame() {
+ if (buffer_) {
+ AHardwareBuffer_release(buffer_);
+ }
+ }
+};
+
+struct FrameQueue {
+ bool mStopped;
+ bool mDrain;
+ std::queue<std::shared_ptr<Frame>> mQueue;
+ std::mutex mMutex;
+ std::condition_variable mCond;
+
+ FrameQueue() : mStopped{false}, mDrain{false} {}
+
+ bool queueItem(AHardwareBuffer *buffer, sp<Fence> fence) {
+ std::shared_ptr<Frame> frame = std::make_shared<Frame>(buffer, fence);
+ if (mStopped) {
+ return false;
+ }
+ if (!frame) {
+ return false;
+ }
+ std::unique_lock<std::mutex> l(mMutex);
+ mQueue.emplace(frame);
+ l.unlock();
+ mCond.notify_all();
+ return true;
+ }
+
+ void stop(bool drain = false) {
+ bool stopped = false;
+ {
+ std::unique_lock<std::mutex> l(mMutex);
+ if (!mStopped) {
+ mStopped = true;
+ mDrain = drain;
+ stopped = true;
+ }
+ l.unlock();
+ if (stopped) {
+ mCond.notify_all();
+ }
+ }
+ }
+
+ bool waitItem(std::shared_ptr<Frame> *frame) {
+ while(true) {
+ std::unique_lock<std::mutex> l(mMutex);
+ if (!mDrain && mStopped) {
+ // stop without consuming the queue.
+ return false;
+ }
+ if (!mQueue.empty()) {
+ *frame = mQueue.front();
+ mQueue.pop();
+ return true;
+ } else if (mStopped) {
+ // stop after consuming the queue.
+ return false;
+ }
+ mCond.wait(l);
+ }
+ }
+};
+
+} // namespace anonymous
+
+class GraphicsTrackerTest : public ::testing::Test {
+public:
+ const uint64_t kTestUsageFlag = GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+ void queueBuffer(FrameQueue *queue) {
+ while (true) {
+ std::shared_ptr<Frame> frame;
+ if (!queue->waitItem(&frame)) {
+ break;
+ }
+ uint64_t bid;
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ if (AHardwareBuffer_getId(frame->buffer_, &bid) !=
+ android::NO_ERROR) {
+ break;
+ }
+ } else {
+ break;
+ }
+ android::status_t ret = frame->fence_->wait(-1);
+ if (ret != android::NO_ERROR) {
+ mTracker->deallocate(bid, frame->fence_);
+ mBqStat->mDiscarded++;
+ continue;
+ }
+
+ std::shared_ptr<C2GraphicBlock> blk =
+ _C2BlockFactory::CreateGraphicBlock(frame->buffer_);
+ if (!blk) {
+ mTracker->deallocate(bid, Fence::NO_FENCE);
+ mBqStat->mDiscarded++;
+ continue;
+ }
+ IGraphicBufferProducer::QueueBufferInput input(
+ 0, false,
+ HAL_DATASPACE_UNKNOWN, android::Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ IGraphicBufferProducer::QueueBufferOutput output{};
+ c2_status_t res = mTracker->render(
+ blk->share(C2Rect(1, 1), C2Fence()),
+ input, &output);
+ if (res != C2_OK) {
+ mTracker->deallocate(bid, Fence::NO_FENCE);
+ mBqStat->mDiscarded++;
+ continue;
+ }
+ if (output.bufferReplaced) {
+ mBqStat->mDropped++;
+ }
+ mBqStat->mQueued++;
+ }
+ }
+
+ void stopTrackerAfterUs(int us) {
+ ::usleep(us);
+ mTracker->stop();
+ }
+
+protected:
+ bool init(int maxDequeueCount) {
+ mTracker = GraphicsTracker::CreateGraphicsTracker(maxDequeueCount);
+ if (!mTracker) {
+ return false;
+ }
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ if (!mProducer || !mConsumer) {
+ return false;
+ }
+ return true;
+ }
+ bool configure(sp<IProducerListener> producerListener,
+ sp<IConsumerListener> consumerListener,
+ int maxAcquiredCount = 1, bool controlledByApp = true) {
+ if (mConsumer->consumerConnect(
+ consumerListener, controlledByApp) != ::android::NO_ERROR) {
+ return false;
+ }
+ if (mConsumer->setMaxAcquiredBufferCount(maxAcquiredCount) != ::android::NO_ERROR) {
+ return false;
+ }
+ IGraphicBufferProducer::QueueBufferOutput qbo{};
+ if (mProducer->connect(producerListener,
+ NATIVE_WINDOW_API_MEDIA, true, &qbo) != ::android::NO_ERROR) {
+ return false;
+ }
+ if (mProducer->setDequeueTimeout(0) != ::android::NO_ERROR) {
+ return false;
+ }
+ return true;
+ }
+
+ virtual void TearDown() override {
+ mBqStat->log();
+ mBqStat->clear();
+
+ if (mTracker) {
+ mTracker->stop();
+ mTracker.reset();
+ }
+ if (mProducer) {
+ mProducer->disconnect(NATIVE_WINDOW_API_MEDIA);
+ }
+ mProducer.clear();
+ mConsumer.clear();
+ }
+
+protected:
+ std::shared_ptr<BqStatistics> mBqStat = std::make_shared<BqStatistics>();
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ std::shared_ptr<GraphicsTracker> mTracker;
+};
+
+
+TEST_F(GraphicsTrackerTest, AllocateAndBlockedTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new DummyConsumerListener()));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+ ASSERT_EQ(C2_OK, ret);
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bid;
+
+ // Allocate and check dequeueable
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(maxDequeueCount - (i + 1), mTracker->getCurDequeueable());
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bid));
+ ALOGD("alloced : bufferId: %llu", (unsigned long long)bid);
+ AHardwareBuffer_release(buf);
+ }
+ } else {
+ GTEST_SKIP();
+ }
+
+ // Allocate should be blocked
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ ALOGD("alloc : err(%d, %d)", ret, C2_BLOCKING);
+ ASSERT_EQ(C2_BLOCKING, ret);
+ mBqStat->mBlocked++;
+ ASSERT_EQ(0, mTracker->getCurDequeueable());
+}
+
+TEST_F(GraphicsTrackerTest, AllocateAndDeallocateTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new DummyConsumerListener()));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+ ASSERT_EQ(C2_OK, ret);
+
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bid;
+ std::vector<uint64_t> bids;
+
+ // Allocate and store buffer id
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bid));
+ bids.push_back(bid);
+ ALOGD("alloced : bufferId: %llu", (unsigned long long)bid);
+ AHardwareBuffer_release(buf);
+ }
+ } else {
+ GTEST_SKIP();
+ }
+
+ // Deallocate and check dequeueable
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ALOGD("dealloc : bufferId: %llu", (unsigned long long)bids[i]);
+ ret = mTracker->deallocate(bids[i], Fence::NO_FENCE);
+ ASSERT_EQ(C2_OK, ret);
+ ASSERT_EQ(i + 1, mTracker->getCurDequeueable());
+ mBqStat->mDiscarded++;
+ }
+}
+
+TEST_F(GraphicsTrackerTest, DropAndReleaseTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new DummyConsumerListener()));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+ ASSERT_EQ(C2_OK, ret);
+
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+ FrameQueue frameQueue;
+ std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+ AHardwareBuffer *buf1, *buf2;
+ sp<Fence> fence1, fence2;
+
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf1, &fence1);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(maxDequeueCount - 1, mTracker->getCurDequeueable());
+
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf2, &fence2);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(maxDequeueCount - 2, mTracker->getCurDequeueable());
+
+ // Queue two buffers without consuming, one should be dropped
+ ASSERT_TRUE(frameQueue.queueItem(buf1, fence1));
+ ASSERT_TRUE(frameQueue.queueItem(buf2, fence2));
+
+ frameQueue.stop(true);
+ if (queueThread.joinable()) {
+ queueThread.join();
+ }
+
+ ASSERT_EQ(maxDequeueCount - 1, mTracker->getCurDequeueable());
+
+ // Consume one buffer and release
+ BufferItem item;
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+ ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence));
+ // Nothing to consume
+ ASSERT_NE(OK, mConsumer->acquireBuffer(&item, 0));
+
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+ ASSERT_EQ(1, mBqStat->mReleased);
+ ASSERT_EQ(1, mBqStat->mDropped);
+}
+
+TEST_F(GraphicsTrackerTest, RenderTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+ const int maxNumAlloc = 20;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+
+ FrameQueue frameQueue;
+ std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+
+ int numAlloc = 0;
+
+ while (numAlloc < maxNumAlloc) {
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ c2_status_t ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ if (ret == C2_BLOCKING) {
+ mBqStat->mBlocked++;
+ c2_status_t waitRes = waitFence.wait(3000000000);
+ if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+ continue;
+ }
+ ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+ break;
+ }
+ if (ret != C2_OK) {
+ ALOGE("alloc error: c2_err(%d)", ret);
+ break;
+ }
+ mBqStat->mDequeued++;
+ if (!frameQueue.queueItem(buf, fence)) {
+ ALOGE("queue to render failed");
+ break;
+ }
+ ++numAlloc;
+ }
+
+ frameQueue.stop(true);
+ // Wait more than enough time(1 sec) to render all queued frames for sure.
+ ::usleep(1000000);
+
+ if (queueThread.joinable()) {
+ queueThread.join();
+ }
+ ASSERT_EQ(numAlloc, maxNumAlloc);
+ ASSERT_EQ(numAlloc, mBqStat->mDequeued);
+ ASSERT_EQ(mBqStat->mDequeued, mBqStat->mQueued);
+ ASSERT_EQ(mBqStat->mDequeued, mBqStat->mReleased + mBqStat->mDropped);
+}
+
+TEST_F(GraphicsTrackerTest, StopAndWaitTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 2;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *buf1, *buf2;
+ sp<Fence> fence;
+
+ ASSERT_EQ(C2_OK, mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf1, &fence));
+ mBqStat->mDequeued++;
+ AHardwareBuffer_release(buf1);
+
+ ASSERT_EQ(C2_OK, mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf2, &fence));
+ mBqStat->mDequeued++;
+ AHardwareBuffer_release(buf2);
+
+ ASSERT_EQ(0, mTracker->getCurDequeueable());
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(3000000000));
+
+ std::thread stopThread(&GraphicsTrackerTest::stopTrackerAfterUs, this, 500000);
+ ASSERT_EQ(C2_BAD_STATE, waitFence.wait(3000000000));
+
+ if (stopThread.joinable()) {
+ stopThread.join();
+ }
+}
+
+TEST_F(GraphicsTrackerTest, SurfaceChangeTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ const int maxNumAlloc = 20;
+
+ const int firstPassAlloc = 12;
+ const int firstPassRender = 8;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *bufs[maxNumAlloc];
+ sp<Fence> fences[maxNumAlloc];
+
+ FrameQueue frameQueue;
+ std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+ int numAlloc = 0;
+
+ for (int i = 0; i < firstPassRender; ++i) {
+ ASSERT_EQ(C2_OK, mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &bufs[i], &fences[i]));
+ mBqStat->mDequeued++;
+ numAlloc++;
+ ASSERT_EQ(true, frameQueue.queueItem(bufs[i], fences[i]));
+ }
+
+ while (numAlloc < firstPassAlloc) {
+ c2_status_t ret = mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &bufs[numAlloc], &fences[numAlloc]);
+ if (ret == C2_BLOCKING) {
+ mBqStat->mBlocked++;
+ c2_status_t waitRes = waitFence.wait(3000000000);
+ if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+ continue;
+ }
+ ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+ break;
+ }
+ if (ret != C2_OK) {
+ ALOGE("alloc error: c2_err(%d)", ret);
+ break;
+ }
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(numAlloc, firstPassAlloc);
+
+ // switching surface
+ sp<IGraphicBufferProducer> oldProducer = mProducer;
+ sp<IGraphicBufferConsumer> oldConsumer = mConsumer;
+ mProducer.clear();
+ mConsumer.clear();
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ ASSERT_TRUE((bool)mProducer && (bool)mConsumer);
+
+ generation += 1;
+
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ ASSERT_EQ(OK, oldProducer->disconnect(NATIVE_WINDOW_API_MEDIA));
+ oldProducer.clear();
+ oldConsumer.clear();
+
+ for (int i = firstPassRender ; i < firstPassAlloc; ++i) {
+ ASSERT_EQ(true, frameQueue.queueItem(bufs[i], fences[i]));
+ }
+
+ while (numAlloc < maxNumAlloc) {
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ c2_status_t ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ if (ret == C2_BLOCKING) {
+ mBqStat->mBlocked++;
+ c2_status_t waitRes = waitFence.wait(3000000000);
+ if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+ continue;
+ }
+ ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+ break;
+ }
+ if (ret != C2_OK) {
+ ALOGE("alloc error: c2_err(%d)", ret);
+ break;
+ }
+ mBqStat->mDequeued++;
+ if (!frameQueue.queueItem(buf, fence)) {
+ ALOGE("queue to render failed");
+ break;
+ }
+ ++numAlloc;
+ }
+
+ ASSERT_EQ(numAlloc, maxNumAlloc);
+
+ frameQueue.stop(true);
+ // Wait more than enough time(1 sec) to render all queued frames for sure.
+ ::usleep(1000000);
+
+ if (queueThread.joinable()) {
+ queueThread.join();
+ }
+ // mReleased should not be checked. IProducerListener::onBufferReleased()
+ // from the previous Surface could be missing after a new Surface was
+ // configured. Instead check # of dequeueable and queueBuffer() calls.
+ ASSERT_EQ(numAlloc, mBqStat->mQueued);
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+
+ ASSERT_EQ(C2_OK, mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &bufs[0], &fences[0]));
+}
+
+TEST_F(GraphicsTrackerTest, maxDequeueIncreaseTest) {
+ uint32_t generation = 1;
+ int maxDequeueCount = 10;
+ int dequeueIncrease = 4;
+
+ int numAlloc = 0;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bids[maxDequeueCount];
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bids[i]));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ } else {
+ GTEST_SKIP();
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[0], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+
+ maxDequeueCount += dequeueIncrease;
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueIncrease + 1; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[1], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+
+ maxDequeueCount += dequeueIncrease;
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueIncrease + 1; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+}
+
+TEST_F(GraphicsTrackerTest, maxDequeueDecreaseTest) {
+ uint32_t generation = 1;
+ int maxDequeueCount = 12;
+ int dequeueDecrease = 4;
+
+ int numAlloc = 0;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bids[maxDequeueCount];
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bids[i]));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ } else {
+ GTEST_SKIP();
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+ int discardIdx = 0;
+ maxDequeueCount -= dequeueDecrease;
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueDecrease + 1; ++i) {
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ }
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ mBqStat->mDequeued++;
+
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ maxDequeueCount -= dequeueDecrease;
+
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueDecrease - 1; ++i) {
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ }
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ mBqStat->mDequeued++;
+}
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 107ce89..60b5b29 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -383,7 +383,7 @@
}
uint8_t *pointer = nullptr;
- err = mapper.lock(handle, usage, bounds, (void **)&pointer, nullptr, nullptr);
+ err = mapper.lock(handle, usage, bounds, (void **)&pointer);
if (err != NO_ERROR || pointer == nullptr) {
return C2_CORRUPTED;
}
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 52ebe25..5d50fc3 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -335,7 +335,8 @@
p.reset();
}
} else {
- ALOGE("Create sync fence from invalid fd");
+ ALOGV("Create sync fence from invalid fd");
+ return C2Fence();
}
return C2Fence(p);
}
@@ -531,7 +532,9 @@
p = SyncFenceImpl::CreateFromNativeHandle(handle);
break;
default:
- ALOGD("Unsupported fence type %d", type);
+ ALOGV("Unsupported fence type %d", type);
+ // If this is malformed-handle close the handle here.
+ (void) native_handle_close(handle);
// return a null-fence in this case
break;
}
diff --git a/media/codec2/vndk/platform/C2IgbaBuffer.cpp b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
index 2051e8f..eafdb22 100644
--- a/media/codec2/vndk/platform/C2IgbaBuffer.cpp
+++ b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
@@ -193,7 +193,7 @@
width, height, format, usage, kBlockingFetchTimeoutNs, &origId, block, &fence);
if (res == C2_BLOCKING) {
- return C2_TIMED_OUT;
+ return C2_BLOCKING;
}
if (res != C2_OK) {
return res;
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
index e33cc0f..4436fb9 100644
--- a/media/libmedia/CharacterEncodingDetector.cpp
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -198,7 +198,9 @@
ALOGV("@@@ checking %s", name);
const char *s = mValues.getEntry(i);
int32_t inputLength = strlen(s);
- const char *enc;
+ // Use encoding determined from the combination of artist/album/title etc.
+ // as default if there is no better match found.
+ const char *enc = combinedenc;
if (!allprintable && (!strcmp(name, "artist") ||
!strcmp(name, "albumartist") ||
@@ -216,13 +218,12 @@
const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
const UCharsetMatch* bestSingleMatch = getPreferred(s, inputLength,
ucma, matches, &goodmatchSingle, &highestSingle);
- if (goodmatchSingle || highestSingle > highest)
- enc = ucsdet_getName(bestSingleMatch, &status);
- else
- enc = combinedenc;
- } else {
- // use encoding determined from the combination of artist/album/title etc.
- enc = combinedenc;
+ // getPreferred could return a null. Check for null before calling
+ // ucsdet_getName.
+ if (bestSingleMatch != NULL) {
+ if (goodmatchSingle || highestSingle > highest)
+ enc = ucsdet_getName(bestSingleMatch, &status);
+ }
}
} else {
if (isPrintableAscii(s, inputLength)) {
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index 509f7a9..0d9e0ec 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -66,7 +66,7 @@
</MediaCodec>
<MediaCodec name="c2.android.raw.decoder" type="audio/raw">
<Alias name="OMX.google.raw.decoder" />
- <Limit name="channel-count" max="8" />
+ <Limit name="channel-count" max="12" />
<Limit name="sample-rate" ranges="8000-192000" />
<Limit name="bitrate" range="1-10000000" />
</MediaCodec>
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index ee41867..24020d1 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -80,7 +80,7 @@
</MediaCodec>
<MediaCodec name="c2.android.raw.decoder" type="audio/raw">
<Alias name="OMX.google.raw.decoder" />
- <Limit name="channel-count" max="8" />
+ <Limit name="channel-count" max="12" />
<Limit name="sample-rate" ranges="8000-192000" />
<Limit name="bitrate" range="1-10000000" />
<Attribute name="software-codec" />
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 54c5697..79ab009 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -184,6 +184,9 @@
cc_defaults {
name: "libstagefright_softomx-defaults",
+ // TODO (b/316432618) Software OMX codecs are no longer used, disable building them till
+ // this code is removed completely.
+ enabled: false,
vendor_available: true,
cflags: [
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 1034d0e..f95fc4d 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -817,6 +817,7 @@
}
}
+ bool registered = false;
if (platformVersion >= __ANDROID_API_V__) {
if (!aidlStore) {
aidlStore = ::ndk::SharedRefBase::make<c2_aidl::utils::ComponentStore>(
@@ -826,23 +827,27 @@
std::string(c2_aidl::IComponentStore::descriptor) + "/software";
binder_exception_t ex = AServiceManager_addService(
aidlStore->asBinder().get(), serviceName.c_str());
- if (ex != EX_NONE) {
+ if (ex == EX_NONE) {
+ registered = true;
+ } else {
LOG(ERROR) << "Cannot register software Codec2 AIDL service.";
- return;
}
}
if (!hidlStore) {
- hidlStore = ::android::sp<V1_0::utils::ComponentStore>::make(
+ hidlStore = ::android::sp<V1_2::utils::ComponentStore>::make(
std::make_shared<H2C2ComponentStore>(nullptr));
- hidlVer = "1.0";
+ hidlVer = "1.2";
}
- if (hidlStore->registerAsService("software") != android::OK) {
+ if (hidlStore->registerAsService("software") == android::OK) {
+ registered = true;
+ } else {
LOG(ERROR) << "Cannot register software Codec2 v" << hidlVer << " service.";
- return;
}
- LOG(INFO) << "Software Codec2 service created and registered.";
+ if (registered) {
+ LOG(INFO) << "Software Codec2 service created and registered.";
+ }
ABinderProcess_joinThreadPool();
::android::hardware::joinRpcThreadpool();
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 0a8d2ab..d096d63 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -189,6 +189,8 @@
],
dictionary: "mkv_extractor_fuzzer.dict",
+
+ corpus: ["corpus/*"],
}
cc_fuzz {
diff --git a/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c b/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c
new file mode 100755
index 0000000..8b31683
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e b/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e
new file mode 100755
index 0000000..f4d475d
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3 b/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3
new file mode 100755
index 0000000..8438e66
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69 b/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69
new file mode 100755
index 0000000..2f622cd
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600 b/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600
new file mode 100755
index 0000000..f053c01
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65 b/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65
new file mode 100755
index 0000000..872451c
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8 b/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8
new file mode 100755
index 0000000..2f7e3ea
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687 b/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687
new file mode 100755
index 0000000..10b5f9a
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620 b/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620
new file mode 100755
index 0000000..969b7a2
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498 b/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498
new file mode 100755
index 0000000..bd146b1
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da b/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da
new file mode 100755
index 0000000..7cf844e
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da
Binary files differ
diff --git a/media/module/extractors/wav/WAVExtractor.cpp b/media/module/extractors/wav/WAVExtractor.cpp
index 9c3bac6..d278103 100644
--- a/media/module/extractors/wav/WAVExtractor.cpp
+++ b/media/module/extractors/wav/WAVExtractor.cpp
@@ -219,7 +219,7 @@
mNumChannels = U16_LE_AT(&formatSpec[2]);
- if (mNumChannels < 1 || mNumChannels > FCC_8) {
+ if (mNumChannels < 1 || mNumChannels > FCC_12) {
ALOGE("Unsupported number of channels (%d)", mNumChannels);
return AMEDIA_ERROR_UNSUPPORTED;
}
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 8b9dde3..7196d79 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -217,10 +217,12 @@
"libmediautils",
"libnativewindow",
"libgui",
+ "libhidlbase",
"libutils",
"libui",
"libcutils",
"android.hardware.graphics.bufferqueue@1.0",
+ "android.hidl.token@1.0",
],
header_libs: [
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index b722b74..4fc9918 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -534,7 +534,8 @@
* Get the native_handle_t corresponding to the ANativeWindow owned by the
* AImageReader provided.
*
- * This is deprecated in API level 35 and will return AMEDIA_ERROR_UNKNOWN.
+ * This is deprecated on devices with vendor API level greater than 34 and
+ * will return AMEDIA_ERROR_UNKNOWN on those devices.
* The native_handle_t is no longer used with AIDL interfaces and
* ANativeWindow is used directly instead.
* Use AImageRead_getWindow to get the ANativeWindow and use that object.
diff --git a/media/ndk/tests/AImageReaderWindowHandleTest.cpp b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
index 27864c2..5608d57 100644
--- a/media/ndk/tests/AImageReaderWindowHandleTest.cpp
+++ b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <android/hidl/token/1.0/ITokenManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
#include <media/NdkImageReader.h>
#include <media/NdkImage.h>
#include <mediautils/AImageReaderUtils.h>
@@ -30,6 +33,8 @@
using HGraphicBufferProducer = hardware::graphics::bufferqueue::V1_0::
IGraphicBufferProducer;
using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+using hidl::manager::V1_2::IServiceManager;
+using hidl::token::V1_0::ITokenManager;
using aimg::AImageReader_getHGBPFromHandle;
typedef IGraphicBufferProducer::QueueBufferInput QueueBufferInput;
@@ -133,7 +138,15 @@
// Check that we can create a native_handle_t corresponding to the
// AImageReader.
native_handle_t *nh = nullptr;
- AImageReader_getWindowNativeHandle(imageReader_, &nh);
+ media_status_t status = AImageReader_getWindowNativeHandle(imageReader_, &nh);
+
+ // On newer devices without the HIDL TokenManager service this API is
+ // deprecated and will return an error.
+ if (IServiceManager::Transport::EMPTY ==
+ hardware::defaultServiceManager1_2()->getTransport(ITokenManager::descriptor, "default")) {
+ EXPECT_EQ(status, AMEDIA_ERROR_UNKNOWN);
+ return;
+ }
ASSERT_NE(nh, nullptr);
// Check that there are only ints in the handle.
diff --git a/media/utils/include/mediautils/ExtendedAccumulator.h b/media/utils/include/mediautils/ExtendedAccumulator.h
index 7e3e170..30045f3 100644
--- a/media/utils/include/mediautils/ExtendedAccumulator.h
+++ b/media/utils/include/mediautils/ExtendedAccumulator.h
@@ -48,9 +48,9 @@
public:
enum class Wrap {
- NORMAL = 0,
- UNDERFLOW = 1,
- OVERFLOW = 2,
+ Normal = 0,
+ Underflow = 1,
+ Overflow = 2,
};
using UnsignedInt = Integral;
@@ -63,11 +63,11 @@
std::pair<SignedInt, Wrap> poll(UnsignedInt value) {
auto acc = mAccumulated.load(std::memory_order_relaxed);
const auto bottom_bits = static_cast<UnsignedInt>(acc);
- std::pair<SignedInt, Wrap> res = {0, Wrap::NORMAL};
+ std::pair<SignedInt, Wrap> res = {0, Wrap::Normal};
const bool overflow = __builtin_sub_overflow(value, bottom_bits, &res.first);
if (overflow) {
- res.second = (res.first > 0) ? Wrap::OVERFLOW : Wrap::UNDERFLOW;
+ res.second = (res.first > 0) ? Wrap::Overflow : Wrap::Underflow;
}
const bool acc_overflow = __builtin_add_overflow(acc, res.first, &acc);
diff --git a/media/utils/tests/extended_accumulator_tests.cpp b/media/utils/tests/extended_accumulator_tests.cpp
index e243e7e..2591df0 100644
--- a/media/utils/tests/extended_accumulator_tests.cpp
+++ b/media/utils/tests/extended_accumulator_tests.cpp
@@ -68,10 +68,10 @@
EXPECT_EQ(result, delta);
// Test overflow/underflow event reporting.
- if (next < base) EXPECT_EQ(TestDetect::Wrap::UNDERFLOW, status);
+ if (next < base) EXPECT_EQ(TestDetect::Wrap::Underflow, status);
else if (next > base + std::numeric_limits<TestUInt>::max())
- EXPECT_EQ(TestDetect::Wrap::OVERFLOW, status);
- else EXPECT_EQ(TestDetect::Wrap::NORMAL, status);
+ EXPECT_EQ(TestDetect::Wrap::Overflow, status);
+ else EXPECT_EQ(TestDetect::Wrap::Normal, status);
}
// Test this utility on every combination of prior and update value for the
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index ae60ed0..2577ca8 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -23,6 +23,7 @@
#include <audio_utils/mutex.h>
#include <audio_utils/LinearMap.h>
#include <binder/AppOpsManager.h>
+#include <utils/RWLock.h>
namespace android {
@@ -352,6 +353,7 @@
// Must hold thread lock to access tee patches
template <class F>
void forEachTeePatchTrack_l(F f) {
+ RWLock::AutoRLock readLock(mTeePatchesRWLock);
for (auto& tp : mTeePatches) { f(tp.patchTrack); }
};
@@ -387,6 +389,7 @@
audio_output_flags_t mFlags;
TeePatches mTeePatches;
std::optional<TeePatches> mTeePatchesToUpdate;
+ RWLock mTeePatchesRWLock;
const float mSpeed;
const bool mIsSpatialized;
const bool mIsBitPerfect;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 224c65b..4fe5b84 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1081,7 +1081,13 @@
// Additionally PatchProxyBufferProvider::obtainBuffer (called by PathTrack::getNextBuffer)
// does not allow 0 frame size request contrary to getNextBuffer
}
- for (auto& teePatch : mTeePatches) {
+ TeePatches teePatches;
+ if (mTeePatchesRWLock.tryReadLock() == NO_ERROR) {
+ // Cache a copy of tee patches in case it is updated while using.
+ teePatches = mTeePatches;
+ mTeePatchesRWLock.unlock();
+ }
+ for (auto& teePatch : teePatches) {
IAfPatchRecord* patchRecord = teePatch.patchRecord.get();
const size_t framesWritten = patchRecord->writeFrames(
sourceBuffer.i8, frameCount, mFrameSize);
@@ -1094,7 +1100,7 @@
using namespace std::chrono_literals;
// Average is ~20us per track, this should virtually never be logged (Logging takes >200us)
ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__,
- spent.count(), mTeePatches.size());
+ spent.count(), teePatches.size());
}
// ExtendedAudioBufferProvider interface
@@ -1616,7 +1622,10 @@
void Track::updateTeePatches_l() {
if (mTeePatchesToUpdate.has_value()) {
forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->destroy(); });
- mTeePatches = mTeePatchesToUpdate.value();
+ {
+ RWLock::AutoWLock writeLock(mTeePatchesRWLock);
+ mTeePatches = std::move(mTeePatchesToUpdate.value());
+ }
if (mState == TrackBase::ACTIVE || mState == TrackBase::RESUMING ||
mState == TrackBase::STOPPING_1) {
forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->start(); });
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index a2f17c2..506b3bc 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -95,31 +95,6 @@
"android.hidl.memory@1.0",
],
- runtime_libs: [
- "libstagefright_soft_aacdec",
- "libstagefright_soft_aacenc",
- "libstagefright_soft_amrdec",
- "libstagefright_soft_amrnbenc",
- "libstagefright_soft_amrwbenc",
- "libstagefright_soft_avcdec",
- "libstagefright_soft_avcenc",
- "libstagefright_soft_flacdec",
- "libstagefright_soft_flacenc",
- "libstagefright_soft_g711dec",
- "libstagefright_soft_gsmdec",
- "libstagefright_soft_hevcdec",
- "libstagefright_soft_mp3dec",
- "libstagefright_soft_mpeg2dec",
- "libstagefright_soft_mpeg4dec",
- "libstagefright_soft_mpeg4enc",
- "libstagefright_soft_opusdec",
- "libstagefright_soft_rawdec",
- "libstagefright_soft_vorbisdec",
- "libstagefright_soft_vpxdec",
- "libstagefright_soft_vpxenc",
- "libstagefright_softomx_plugin",
- ],
-
// OMX interfaces force this to stay in 32-bit mode;
compile_multilib: "32",
diff --git a/tools/mainline_hook_partial.sh b/tools/mainline_hook_partial.sh
index cd3e579..63ae4c0 100755
--- a/tools/mainline_hook_partial.sh
+++ b/tools/mainline_hook_partial.sh
Binary files differ
diff --git a/tools/mainline_hook_project.sh b/tools/mainline_hook_project.sh
index 1cc3b2b..d58143e 100755
--- a/tools/mainline_hook_project.sh
+++ b/tools/mainline_hook_project.sh
@@ -16,8 +16,8 @@
# tunables
-DEV_BRANCH=master
-MAINLINE_BRANCH=tm-mainline-prod
+DEV_BRANCH=main
+MAINLINE_BRANCH=udc-mainline-prod
###
RED=$(tput setaf 1)