[automerger skipped] Merge "Merge Android R" am: 0bbd9a10e5 -s ours am: fcc43c2c03 -s ours am: 9e98556449 -s ours am: e88bfc12fa -s ours
am skip reason: Change-Id Ic54c8dcf210e9b375e7fdce6444c7d882a1784d6 with SHA-1 451a36a9a6 is in history
Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1422365
Change-Id: I3a4a56bbb9ca5b1823319914b94cbbf547f6fd38
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index c02c81b..bef2ea0 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -142,7 +142,8 @@
camera_frame_metadata_t metadata;
if (data.dataAvail() > 0) {
metadata.number_of_faces = data.readInt32();
- if (metadata.number_of_faces <= 0 ||
+ // Zero faces is a valid case, to notify clients that no faces are now visible
+ if (metadata.number_of_faces < 0 ||
metadata.number_of_faces > (int32_t)(INT32_MAX / sizeof(camera_face_t))) {
ALOGE("%s: Too large face count: %d", __FUNCTION__, metadata.number_of_faces);
return BAD_VALUE;
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index f05c2d2..f75e4c7 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -6,8 +6,11 @@
capabilities BLOCK_SUSPEND
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
-
- onrestart setprop sys.audio.restart.hal 1
+ onrestart restart vendor.audio-hal
+ onrestart restart vendor.audio-hal-4-0-msd
+ # Keep the original service names for backward compatibility
+ onrestart restart vendor.audio-hal-2-0
+ onrestart restart audio-hal-2-0
on property:vts.native_server.on=1
stop audioserver
@@ -37,11 +40,16 @@
start audio-hal-2-0
on property:sys.audio.restart.hal=1
- restart vendor.audio-hal
- restart vendor.audio-hal-4-0-msd
+ # See b/159966243. Avoid restart loop between audioserver and HAL.
# Keep the original service names for backward compatibility
- restart vendor.audio-hal-2-0
- restart audio-hal-2-0
+ stop vendor.audio-hal
+ stop vendor.audio-hal-4-0-msd
+ stop vendor.audio-hal-2-0
+ stop audio-hal-2-0
+ start vendor.audio-hal
+ start vendor.audio-hal-4-0-msd
+ start vendor.audio-hal-2-0
+ start audio-hal-2-0
# reset the property
setprop sys.audio.restart.hal 0
diff --git a/media/codec2/components/gav1/Android.bp b/media/codec2/components/gav1/Android.bp
index 5c4abb7..f374089 100644
--- a/media/codec2/components/gav1/Android.bp
+++ b/media/codec2/components/gav1/Android.bp
@@ -13,8 +13,4 @@
srcs: ["C2SoftGav1Dec.cpp"],
static_libs: ["libgav1"],
-
- include_dirs: [
- "external/libgav1/libgav1/",
- ],
}
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 5dffa50..2273e71 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -288,9 +288,7 @@
void C2SoftGav1Dec::onRelease() { destroyDecoder(); }
c2_status_t C2SoftGav1Dec::onFlush_sm() {
- Libgav1StatusCode status =
- mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
- /*user_private_data=*/0);
+ Libgav1StatusCode status = mCodecCtx->SignalEOS();
if (status != kLibgav1StatusOk) {
ALOGE("Failed to flush av1 decoder. status: %d.", status);
return C2_CORRUPTED;
@@ -299,7 +297,7 @@
// Dequeue frame (if any) that was enqueued previously.
const libgav1::DecoderBuffer *buffer;
status = mCodecCtx->DequeueFrame(&buffer);
- if (status != kLibgav1StatusOk) {
+ if (status != kLibgav1StatusOk && status != kLibgav1StatusNothingToDequeue) {
ALOGE("Failed to dequeue frame after flushing the av1 decoder. status: %d",
status);
return C2_CORRUPTED;
@@ -433,7 +431,8 @@
TIME_DIFF(mTimeEnd, mTimeStart, delay);
const Libgav1StatusCode status =
- mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex);
+ mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex,
+ /*buffer_private_data=*/nullptr);
GETTIME(&mTimeEnd, nullptr);
TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
@@ -448,9 +447,7 @@
}
} else {
- const Libgav1StatusCode status =
- mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
- /*user_private_data=*/0);
+ const Libgav1StatusCode status = mCodecCtx->SignalEOS();
if (status != kLibgav1StatusOk) {
ALOGE("Failed to flush av1 decoder. status: %d.", status);
work->result = C2_CORRUPTED;
@@ -598,13 +595,14 @@
const libgav1::DecoderBuffer *buffer;
const Libgav1StatusCode status = mCodecCtx->DequeueFrame(&buffer);
- if (status != kLibgav1StatusOk) {
+ if (status != kLibgav1StatusOk && status != kLibgav1StatusNothingToDequeue) {
ALOGE("av1 decoder DequeueFrame failed. status: %d.", status);
return false;
}
- // |buffer| can be NULL if status was equal to kLibgav1StatusOk. This is not
- // an error. This could mean one of two things:
+ // |buffer| can be NULL if status was equal to kLibgav1StatusOk or
+ // kLibgav1StatusNothingToDequeue. This is not an error. This could mean one
+ // of two things:
// - The EnqueueFrame() call was either a flush (called with nullptr).
// - The enqueued frame did not have any displayable frames.
if (!buffer) {
@@ -724,9 +722,7 @@
return C2_OMITTED;
}
- Libgav1StatusCode status =
- mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
- /*user_private_data=*/0);
+ const Libgav1StatusCode status = mCodecCtx->SignalEOS();
if (status != kLibgav1StatusOk) {
ALOGE("Failed to flush av1 decoder. status: %d.", status);
return C2_CORRUPTED;
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index a7c08bb..555adc9 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -18,8 +18,8 @@
#define ANDROID_C2_SOFT_GAV1_DEC_H_
#include <SimpleC2Component.h>
-#include "libgav1/src/decoder.h"
-#include "libgav1/src/decoder_settings.h"
+#include "libgav1/src/gav1/decoder.h"
+#include "libgav1/src/gav1/decoder_settings.h"
#define GETTIME(a, b) gettimeofday(a, b);
#define TIME_DIFF(start, end, diff) \
diff --git a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
index 15564d9..a8b5377 100644
--- a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
+++ b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
@@ -279,6 +279,8 @@
// skip 7 <type + "vorbis"> bytes
makeBitReader((const uint8_t *)data + 7, inSize - 7, &buf, &ref, &bits);
if (data[0] == 1) {
+ // release any memory that vorbis_info_init will blindly overwrite
+ vorbis_info_clear(mVi);
vorbis_info_init(mVi);
if (0 != _vorbis_unpack_info(mVi, &bits)) {
ALOGE("Encountered error while unpacking info");
@@ -323,6 +325,8 @@
work->result = C2_CORRUPTED;
return;
}
+ // release any memory that vorbis_dsp_init will blindly overwrite
+ vorbis_dsp_clear(mState);
if (0 != vorbis_dsp_init(mState, mVi)) {
ALOGE("Encountered error while dsp init");
mSignalledError = true;
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index e58a1e4..c49a16c 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -272,8 +272,6 @@
// The output format can be processed without a registered slot.
if (outputFormat) {
- ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
- mName, outputFormat->debugString().c_str());
updateSkipCutBuffer(outputFormat, entry.notify);
}
@@ -301,6 +299,10 @@
}
if (!entry.notify) {
+ if (outputFormat) {
+ ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
+ mName, outputFormat->debugString().c_str());
+ }
mPending.pop_front();
return DISCARD;
}
@@ -317,6 +319,10 @@
// Append information from the front stash entry to outBuffer.
(*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
(*outBuffer)->meta()->setInt32("flags", entry.flags);
+ if (outputFormat) {
+ ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
+ mName, outputFormat->debugString().c_str());
+ }
ALOGV("[%s] popFromStashAndRegister: "
"out buffer index = %zu [%p] => %p + %zu (%lld)",
mName, *index, outBuffer->get(),
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 509e063..d6671e3 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -742,6 +742,8 @@
void *iMemPointer;
audio_track_cblk_t* cblk;
status_t status;
+ static const int32_t kMaxCreateAttempts = 3;
+ int32_t remainingAttempts = kMaxCreateAttempts;
if (audioFlinger == 0) {
ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId);
@@ -803,15 +805,24 @@
input.sessionId = mSessionId;
originalSessionId = mSessionId;
- record = audioFlinger->createRecord(input,
- output,
- &status);
+ do {
+ record = audioFlinger->createRecord(input, output, &status);
+ if (status == NO_ERROR) {
+ break;
+ }
+ if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
+ ALOGE("%s(%d): AudioFlinger could not create record track, status: %d",
+ __func__, mPortId, status);
+ goto exit;
+ }
+ // FAILED_TRANSACTION happens under very specific conditions causing a state mismatch
+ // between audio policy manager and audio flinger during the input stream open sequence
+ // and can be recovered by retrying.
+ // Leave time for race condition to clear before retrying and randomize delay
+ // to reduce the probability of concurrent retries in locked steps.
+ usleep((20 + rand() % 30) * 10000);
+ } while (1);
- if (status != NO_ERROR) {
- ALOGE("%s(%d): AudioFlinger could not create record track, status: %d",
- __func__, mPortId, status);
- goto exit;
- }
ALOG_ASSERT(record != 0);
// AudioFlinger now owns the reference to the I/O handle,
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index 80bd093..8d374c9 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -234,17 +234,20 @@
static_assert(NCHAN > 0 && NCHAN <= 8);
static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL
|| MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
- || MIXTYPE == MIXTYPE_STEREOEXPAND);
+ || MIXTYPE == MIXTYPE_STEREOEXPAND
+ || MIXTYPE == MIXTYPE_MONOEXPAND);
auto proc = [](auto& a, const auto& b) {
if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
- || MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ || MIXTYPE == MIXTYPE_STEREOEXPAND
+ || MIXTYPE == MIXTYPE_MONOEXPAND) {
a += b;
} else {
a = b;
}
};
auto inp = [&in]() -> const TI& {
- if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND
+ || MIXTYPE == MIXTYPE_MONOEXPAND) {
return *in;
} else {
return *in++;
@@ -312,6 +315,8 @@
* TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
* Input channel count is 1.
* vol: represents volume array.
+ * This uses stereo balanced volume vol[0] and vol[1].
+ * Before R, this was a full volume array but was called only for channels <= 2.
*
* This accumulates into the out pointer.
*
@@ -356,17 +361,13 @@
do {
TA auxaccum = 0;
if constexpr (MIXTYPE == MIXTYPE_MULTI) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
vol[i] += volinc[i];
}
- } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
- for (int i = 0; i < NCHAN; ++i) {
- *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
- vol[i] += volinc[i];
- }
- in++;
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
vol[i] += volinc[i];
@@ -383,11 +384,13 @@
vol[0] += volinc[0];
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
|| MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_MONOEXPAND
|| MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(
out, in, vol, [&auxaccum] (auto &a, const auto &b) {
return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
});
+ if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
vol[0] += volinc[0];
vol[1] += volinc[1];
@@ -401,17 +404,13 @@
} else {
do {
if constexpr (MIXTYPE == MIXTYPE_MULTI) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
vol[i] += volinc[i];
}
- } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
- for (int i = 0; i < NCHAN; ++i) {
- *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
- vol[i] += volinc[i];
- }
- in++;
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
vol[i] += volinc[i];
@@ -428,10 +427,12 @@
vol[0] += volinc[0];
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
|| MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_MONOEXPAND
|| MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
return MixMul<TO, TI, TV>(a, b);
});
+ if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
vol[0] += volinc[0];
vol[1] += volinc[1];
@@ -454,15 +455,12 @@
do {
TA auxaccum = 0;
if constexpr (MIXTYPE == MIXTYPE_MULTI) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
}
- } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
- for (int i = 0; i < NCHAN; ++i) {
- *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
- }
- in++;
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
}
@@ -476,11 +474,13 @@
}
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
|| MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_MONOEXPAND
|| MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(
out, in, vol, [&auxaccum] (auto &a, const auto &b) {
return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
});
+ if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
} else /* constexpr */ {
static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
@@ -490,16 +490,14 @@
} while (--frameCount);
} else {
do {
+ // ALOGD("Mixtype:%d NCHAN:%d", MIXTYPE, NCHAN);
if constexpr (MIXTYPE == MIXTYPE_MULTI) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
}
- } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
- for (int i = 0; i < NCHAN; ++i) {
- *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
- }
- in++;
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
+ static_assert(NCHAN <= 2);
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
}
@@ -513,10 +511,12 @@
}
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
|| MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_MONOEXPAND
|| MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
return MixMul<TO, TI, TV>(a, b);
});
+ if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
} else /* constexpr */ {
static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
diff --git a/media/libaudioprocessing/tests/mixerops_benchmark.cpp b/media/libaudioprocessing/tests/mixerops_benchmark.cpp
index 86f5429..7a4c5c7 100644
--- a/media/libaudioprocessing/tests/mixerops_benchmark.cpp
+++ b/media/libaudioprocessing/tests/mixerops_benchmark.cpp
@@ -74,28 +74,32 @@
}
}
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 2);
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 2);
+// MULTI mode and MULTI_SAVEONLY mode are not used by AudioMixer for channels > 2,
+// which is ensured by a static_assert (won't compile for those configurations).
+// So we benchmark MIXTYPE_MULTI_MONOVOL and MIXTYPE_MULTI_SAVEONLY_MONOVOL compared
+// with MIXTYPE_MULTI_STEREOVOL and MIXTYPE_MULTI_SAVEONLY_STEREOVOL.
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 2);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 2);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 2);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 2);
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 4);
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 4);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 4);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 4);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 4);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 4);
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 5);
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 5);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 5);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 5);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 5);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 5);
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 8);
-BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 8);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 8);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 8);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 8);
BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 8);
-BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI, 8);
-BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY, 8);
+BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_MONOVOL, 8);
+BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 8);
BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_STEREOVOL, 8);
BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 8);
diff --git a/media/libstagefright/FrameCaptureProcessor.cpp b/media/libstagefright/FrameCaptureProcessor.cpp
index 96c1195..63238bc 100644
--- a/media/libstagefright/FrameCaptureProcessor.cpp
+++ b/media/libstagefright/FrameCaptureProcessor.cpp
@@ -171,6 +171,8 @@
if (err != OK) {
ALOGW("wait for fence returned err %d", err);
}
+
+ mRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL);
return OK;
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 8f7d4bf..d99596e 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2774,7 +2774,7 @@
// even if the file is well-formed and the primary picture is correct.
// Reserve item ids for samples + grid
- size_t numItemsToReserve = mNumTiles + (mNumTiles > 1);
+ size_t numItemsToReserve = mNumTiles + (mNumTiles > 0);
status_t err = mOwner->reserveItemId_l(numItemsToReserve, &mItemIdBase);
if (err != OK) {
return err;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 5d17f97..31c800e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2043,20 +2043,25 @@
} else if (mFlags & kFlagOutputBuffersChanged) {
PostReplyWithError(replyID, INFO_OUTPUT_BUFFERS_CHANGED);
mFlags &= ~kFlagOutputBuffersChanged;
- } else if (mFlags & kFlagOutputFormatChanged) {
- PostReplyWithError(replyID, INFO_FORMAT_CHANGED);
- mFlags &= ~kFlagOutputFormatChanged;
} else {
sp<AMessage> response = new AMessage;
- ssize_t index = dequeuePortBuffer(kPortIndexOutput);
-
- if (index < 0) {
- CHECK_EQ(index, -EAGAIN);
+ BufferInfo *info = peekNextPortBuffer(kPortIndexOutput);
+ if (!info) {
return false;
}
- const sp<MediaCodecBuffer> &buffer =
- mPortBuffers[kPortIndexOutput][index].mData;
+ // In synchronous mode, output format change should be handled
+ // at dequeue to put the event at the correct order.
+
+ const sp<MediaCodecBuffer> &buffer = info->mData;
+ handleOutputFormatChangeIfNeeded(buffer);
+ if (mFlags & kFlagOutputFormatChanged) {
+ PostReplyWithError(replyID, INFO_FORMAT_CHANGED);
+ mFlags &= ~kFlagOutputFormatChanged;
+ return true;
+ }
+
+ ssize_t index = dequeuePortBuffer(kPortIndexOutput);
response->setSize("index", index);
response->setSize("offset", buffer->offset());
@@ -2540,107 +2545,13 @@
break;
}
- sp<RefBase> obj;
- CHECK(msg->findObject("buffer", &obj));
- sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
-
- if (mOutputFormat != buffer->format()) {
- if (mFlags & kFlagUseBlockModel) {
- sp<AMessage> diff1 = mOutputFormat->changesFrom(buffer->format());
- sp<AMessage> diff2 = buffer->format()->changesFrom(mOutputFormat);
- std::set<std::string> keys;
- size_t numEntries = diff1->countEntries();
- AMessage::Type type;
- for (size_t i = 0; i < numEntries; ++i) {
- keys.emplace(diff1->getEntryNameAt(i, &type));
- }
- numEntries = diff2->countEntries();
- for (size_t i = 0; i < numEntries; ++i) {
- keys.emplace(diff2->getEntryNameAt(i, &type));
- }
- sp<WrapperObject<std::set<std::string>>> changedKeys{
- new WrapperObject<std::set<std::string>>{std::move(keys)}};
- buffer->meta()->setObject("changedKeys", changedKeys);
- }
- mOutputFormat = buffer->format();
- ALOGV("[%s] output format changed to: %s",
- mComponentName.c_str(), mOutputFormat->debugString(4).c_str());
-
- if (mSoftRenderer == NULL &&
- mSurface != NULL &&
- (mFlags & kFlagUsesSoftwareRenderer)) {
- AString mime;
- CHECK(mOutputFormat->findString("mime", &mime));
-
- // TODO: propagate color aspects to software renderer to allow better
- // color conversion to RGB. For now, just mark dataspace for YUV
- // rendering.
- int32_t dataSpace;
- if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
- ALOGD("[%s] setting dataspace on output surface to #%x",
- mComponentName.c_str(), dataSpace);
- int err = native_window_set_buffers_data_space(
- mSurface.get(), (android_dataspace)dataSpace);
- ALOGW_IF(err != 0, "failed to set dataspace on surface (%d)", err);
- }
- if (mOutputFormat->contains("hdr-static-info")) {
- HDRStaticInfo info;
- if (ColorUtils::getHDRStaticInfoFromFormat(mOutputFormat, &info)) {
- setNativeWindowHdrMetadata(mSurface.get(), &info);
- }
- }
-
- sp<ABuffer> hdr10PlusInfo;
- if (mOutputFormat->findBuffer("hdr10-plus-info", &hdr10PlusInfo)
- && hdr10PlusInfo != nullptr && hdr10PlusInfo->size() > 0) {
- native_window_set_buffers_hdr10_plus_metadata(mSurface.get(),
- hdr10PlusInfo->size(), hdr10PlusInfo->data());
- }
-
- if (mime.startsWithIgnoreCase("video/")) {
- mSurface->setDequeueTimeout(-1);
- mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees);
- }
- }
-
- requestCpuBoostIfNeeded();
-
- if (mFlags & kFlagIsEncoder) {
- // Before we announce the format change we should
- // collect codec specific data and amend the output
- // format as necessary.
- int32_t flags = 0;
- (void) buffer->meta()->findInt32("flags", &flags);
- if ((flags & BUFFER_FLAG_CODECCONFIG) && !(mFlags & kFlagIsSecure)) {
- status_t err =
- amendOutputFormatWithCodecSpecificData(buffer);
-
- if (err != OK) {
- ALOGE("Codec spit out malformed codec "
- "specific data!");
- }
- }
- }
- if (mFlags & kFlagIsAsync) {
- onOutputFormatChanged();
- } else {
- mFlags |= kFlagOutputFormatChanged;
- postActivityNotificationIfPossible();
- }
-
- // Notify mCrypto of video resolution changes
- if (mCrypto != NULL) {
- int32_t left, top, right, bottom, width, height;
- if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
- mCrypto->notifyResolution(right - left + 1, bottom - top + 1);
- } else if (mOutputFormat->findInt32("width", &width)
- && mOutputFormat->findInt32("height", &height)) {
- mCrypto->notifyResolution(width, height);
- }
- }
- }
-
if (mFlags & kFlagIsAsync) {
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+ sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+
+ // In asynchronous mode, output format change is processed immediately.
+ handleOutputFormatChangeIfNeeded(buffer);
onOutputBufferAvailable();
} else if (mFlags & kFlagDequeueOutputPending) {
CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID));
@@ -3469,6 +3380,106 @@
}
}
+void MediaCodec::handleOutputFormatChangeIfNeeded(const sp<MediaCodecBuffer> &buffer) {
+ sp<AMessage> format = buffer->format();
+ if (mOutputFormat == format) {
+ return;
+ }
+ if (mFlags & kFlagUseBlockModel) {
+ sp<AMessage> diff1 = mOutputFormat->changesFrom(format);
+ sp<AMessage> diff2 = format->changesFrom(mOutputFormat);
+ std::set<std::string> keys;
+ size_t numEntries = diff1->countEntries();
+ AMessage::Type type;
+ for (size_t i = 0; i < numEntries; ++i) {
+ keys.emplace(diff1->getEntryNameAt(i, &type));
+ }
+ numEntries = diff2->countEntries();
+ for (size_t i = 0; i < numEntries; ++i) {
+ keys.emplace(diff2->getEntryNameAt(i, &type));
+ }
+ sp<WrapperObject<std::set<std::string>>> changedKeys{
+ new WrapperObject<std::set<std::string>>{std::move(keys)}};
+ buffer->meta()->setObject("changedKeys", changedKeys);
+ }
+ mOutputFormat = format;
+ ALOGV("[%s] output format changed to: %s",
+ mComponentName.c_str(), mOutputFormat->debugString(4).c_str());
+
+ if (mSoftRenderer == NULL &&
+ mSurface != NULL &&
+ (mFlags & kFlagUsesSoftwareRenderer)) {
+ AString mime;
+ CHECK(mOutputFormat->findString("mime", &mime));
+
+ // TODO: propagate color aspects to software renderer to allow better
+ // color conversion to RGB. For now, just mark dataspace for YUV
+ // rendering.
+ int32_t dataSpace;
+ if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
+ ALOGD("[%s] setting dataspace on output surface to #%x",
+ mComponentName.c_str(), dataSpace);
+ int err = native_window_set_buffers_data_space(
+ mSurface.get(), (android_dataspace)dataSpace);
+ ALOGW_IF(err != 0, "failed to set dataspace on surface (%d)", err);
+ }
+ if (mOutputFormat->contains("hdr-static-info")) {
+ HDRStaticInfo info;
+ if (ColorUtils::getHDRStaticInfoFromFormat(mOutputFormat, &info)) {
+ setNativeWindowHdrMetadata(mSurface.get(), &info);
+ }
+ }
+
+ sp<ABuffer> hdr10PlusInfo;
+ if (mOutputFormat->findBuffer("hdr10-plus-info", &hdr10PlusInfo)
+ && hdr10PlusInfo != nullptr && hdr10PlusInfo->size() > 0) {
+ native_window_set_buffers_hdr10_plus_metadata(mSurface.get(),
+ hdr10PlusInfo->size(), hdr10PlusInfo->data());
+ }
+
+ if (mime.startsWithIgnoreCase("video/")) {
+ mSurface->setDequeueTimeout(-1);
+ mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees);
+ }
+ }
+
+ requestCpuBoostIfNeeded();
+
+ if (mFlags & kFlagIsEncoder) {
+ // Before we announce the format change we should
+ // collect codec specific data and amend the output
+ // format as necessary.
+ int32_t flags = 0;
+ (void) buffer->meta()->findInt32("flags", &flags);
+ if ((flags & BUFFER_FLAG_CODECCONFIG) && !(mFlags & kFlagIsSecure)) {
+ status_t err =
+ amendOutputFormatWithCodecSpecificData(buffer);
+
+ if (err != OK) {
+ ALOGE("Codec spit out malformed codec "
+ "specific data!");
+ }
+ }
+ }
+ if (mFlags & kFlagIsAsync) {
+ onOutputFormatChanged();
+ } else {
+ mFlags |= kFlagOutputFormatChanged;
+ postActivityNotificationIfPossible();
+ }
+
+ // Notify mCrypto of video resolution changes
+ if (mCrypto != NULL) {
+ int32_t left, top, right, bottom, width, height;
+ if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
+ mCrypto->notifyResolution(right - left + 1, bottom - top + 1);
+ } else if (mOutputFormat->findInt32("width", &width)
+ && mOutputFormat->findInt32("height", &height)) {
+ mCrypto->notifyResolution(width, height);
+ }
+ }
+}
+
void MediaCodec::extractCSD(const sp<AMessage> &format) {
mCSD.clear();
@@ -3934,19 +3945,31 @@
return OK;
}
-ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
+MediaCodec::BufferInfo *MediaCodec::peekNextPortBuffer(int32_t portIndex) {
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
List<size_t> *availBuffers = &mAvailPortBuffers[portIndex];
if (availBuffers->empty()) {
+ return nullptr;
+ }
+
+ return &mPortBuffers[portIndex][*availBuffers->begin()];
+}
+
+ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
+ CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
+
+ BufferInfo *info = peekNextPortBuffer(portIndex);
+ if (!info) {
return -EAGAIN;
}
+ List<size_t> *availBuffers = &mAvailPortBuffers[portIndex];
size_t index = *availBuffers->begin();
+ CHECK_EQ(info, &mPortBuffers[portIndex][index]);
availBuffers->erase(availBuffers->begin());
- BufferInfo *info = &mPortBuffers[portIndex][index];
CHECK(!info->mOwnedByClient);
{
Mutex::Autolock al(mBufferLock);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index f7e6c27..8057312 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -445,6 +445,7 @@
size_t updateBuffers(int32_t portIndex, const sp<AMessage> &msg);
status_t onQueueInputBuffer(const sp<AMessage> &msg);
status_t onReleaseOutputBuffer(const sp<AMessage> &msg);
+ BufferInfo *peekNextPortBuffer(int32_t portIndex);
ssize_t dequeuePortBuffer(int32_t portIndex);
status_t getBufferAndFormat(
@@ -476,6 +477,7 @@
status_t onSetParameters(const sp<AMessage> ¶ms);
status_t amendOutputFormatWithCodecSpecificData(const sp<MediaCodecBuffer> &buffer);
+ void handleOutputFormatChangeIfNeeded(const sp<MediaCodecBuffer> &buffer);
bool isExecuting() const;
uint64_t getGraphicBufferSize();
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1935cde..619f0e7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2068,8 +2068,8 @@
Mutex::Autolock _l(mLock);
RecordThread *thread = checkRecordThread_l(output.inputId);
if (thread == NULL) {
- ALOGE("createRecord() checkRecordThread_l failed, input handle %d", output.inputId);
- lStatus = BAD_VALUE;
+ ALOGW("createRecord() checkRecordThread_l failed, input handle %d", output.inputId);
+ lStatus = FAILED_TRANSACTION;
goto Exit;
}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 384ddb5..615e8aa 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7870,7 +7870,8 @@
AutoMutex lock(mLock);
if (recordTrack->isInvalid()) {
recordTrack->clearSyncStartEvent();
- return INVALID_OPERATION;
+ ALOGW("%s track %d: invalidated before startInput", __func__, recordTrack->portId());
+ return DEAD_OBJECT;
}
if (mActiveTracks.indexOf(recordTrack) >= 0) {
if (recordTrack->mState == TrackBase::PAUSING) {
@@ -7900,7 +7901,8 @@
recordTrack->mState = TrackBase::STARTING_2;
// STARTING_2 forces destroy to call stopInput.
}
- return INVALID_OPERATION;
+ ALOGW("%s track %d: invalidated after startInput", __func__, recordTrack->portId());
+ return DEAD_OBJECT;
}
if (recordTrack->mState != TrackBase::STARTING_1) {
ALOGW("%s(%d): unsynchronized mState:%d change",
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d366bb7..db25e57 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -2226,7 +2226,8 @@
RecordThread *recordThread = (RecordThread *)thread.get();
return recordThread->start(this, event, triggerSession);
} else {
- return BAD_VALUE;
+ ALOGW("%s track %d: thread was destroyed", __func__, portId());
+ return DEAD_OBJECT;
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ae71959..12c6ae5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2267,7 +2267,7 @@
sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
if (inputDesc == 0) {
ALOGW("%s no input for client %d", __FUNCTION__, portId);
- return BAD_VALUE;
+ return DEAD_OBJECT;
}
audio_io_handle_t input = inputDesc->mIoHandle;
sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
@@ -3172,6 +3172,8 @@
if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/);
waitMs = updateCallRouting(newDevices, delayMs);
+ // Only apply special touch sound delay once
+ delayMs = 0;
}
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
@@ -3181,6 +3183,8 @@
// preventing the force re-routing in case of default dev that distinguishes on address.
// Let's give back to engine full device choice decision however.
waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs);
+ // Only apply special touch sound delay once
+ delayMs = 0;
}
if (forceVolumeReeval && !newDevices.isEmpty()) {
applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
@@ -5665,7 +5669,7 @@
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet());
const uint32_t latency = desc->latency() * 2;
- if (latency > maxLatency) {
+ if (desc->isActive(latency * 2) && latency > maxLatency) {
maxLatency = latency;
}
}
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index e847f9f..a6e8989 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -488,9 +488,9 @@
}
bool isAccessibility = mUidPolicy->isA11yUid(current->uid);
- // Clients capturing for Accessibility services are not considered
+ // Clients capturing for Accessibility services or virtual sources are not considered
// for top or latest active to avoid masking regular clients started before
- if (!isAccessibility) {
+ if (!isAccessibility && !isVirtualSource(current->attributes.source)) {
bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
bool isPrivacySensitive =
(current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b5de1b7..3d9998a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -3745,9 +3745,14 @@
__FUNCTION__, cameraId.string());
return;
}
+
+ // Collect the logical cameras without holding mStatusLock in updateStatus
+ // as that can lead to a deadlock(b/162192331).
+ auto logicalCameraIds = getLogicalCameras(cameraId);
// Update the status for this camera state, then send the onStatusChangedCallbacks to each
// of the listeners with both the mStatusLock and mStatusListenerLock held
- state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3]
+ state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3,
+ &logicalCameraIds]
(const String8& cameraId, StatusInternal status) {
if (status != StatusInternal::ENUMERATING) {
@@ -3767,8 +3772,8 @@
}
Mutex::Autolock lock(mStatusListenerLock);
-
- notifyPhysicalCameraStatusLocked(mapToInterface(status), cameraId, deviceKind);
+ notifyPhysicalCameraStatusLocked(mapToInterface(status), String16(cameraId),
+ logicalCameraIds, deviceKind);
for (auto& listener : mListenerList) {
bool isVendorListener = listener->isVendorListener();
@@ -3886,8 +3891,9 @@
return OK;
}
-void CameraService::notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId,
- SystemCameraKind deviceKind) {
+std::list<String16> CameraService::getLogicalCameras(
+ const String8& physicalCameraId) {
+ std::list<String16> retList;
Mutex::Autolock lock(mCameraStatesLock);
for (const auto& state : mCameraStates) {
std::vector<std::string> physicalCameraIds;
@@ -3895,26 +3901,39 @@
// This is not a logical multi-camera.
continue;
}
- if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), cameraId.c_str())
+ if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), physicalCameraId.c_str())
== physicalCameraIds.end()) {
// cameraId is not a physical camera of this logical multi-camera.
continue;
}
- String16 id16(state.first), physicalId16(cameraId);
+ retList.emplace_back(String16(state.first));
+ }
+ return retList;
+}
+
+void CameraService::notifyPhysicalCameraStatusLocked(int32_t status,
+ const String16& physicalCameraId, const std::list<String16>& logicalCameraIds,
+ SystemCameraKind deviceKind) {
+ // mStatusListenerLock is expected to be locked
+ for (const auto& logicalCameraId : logicalCameraIds) {
for (auto& listener : mListenerList) {
+ // Note: we check only the deviceKind of the physical camera id
+ // since, logical camera ids and their physical camera ids are
+ // guaranteed to have the same system camera kind.
if (shouldSkipStatusUpdates(deviceKind, listener->isVendorListener(),
listener->getListenerPid(), listener->getListenerUid())) {
ALOGV("Skipping discovery callback for system-only camera device %s",
- cameraId.c_str());
+ String8(physicalCameraId).c_str());
continue;
}
listener->getListener()->onPhysicalCameraStatusChanged(status,
- id16, physicalId16);
+ logicalCameraId, physicalCameraId);
}
}
}
+
void CameraService::blockClientsForUid(uid_t uid) {
const auto clients = mActiveClientManager.getAll();
for (auto& current : clients) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 35e13e7..6771718 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -49,6 +49,7 @@
#include <set>
#include <string>
+#include <list>
#include <map>
#include <memory>
#include <optional>
@@ -1006,8 +1007,13 @@
hardware::camera::common::V1_0::TorchModeStatus status);
// notify physical camera status when the physical camera is public.
- void notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId,
- SystemCameraKind deviceKind);
+ // Expects mStatusListenerLock to be locked.
+ void notifyPhysicalCameraStatusLocked(int32_t status, const String16& physicalCameraId,
+ const std::list<String16>& logicalCameraIds, SystemCameraKind deviceKind);
+
+ // get list of logical cameras which are backed by physicalCameraId
+ std::list<String16> getLogicalCameras(const String8& physicalCameraId);
+
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 32d118d..876d70d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1344,6 +1344,20 @@
}
}
+ // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
+ // before setCallback returns
+ hardware::Return<Status> status = interface->setCallback(this);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), status.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to register callbacks with camera provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+
hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
if (!linked.isOk()) {
ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
@@ -1372,7 +1386,6 @@
return res;
}
- Status status;
// Get initial list of camera devices, if any
std::vector<std::string> devices;
hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
@@ -1437,26 +1450,43 @@
}
}
- // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
- // before setCallback returns. setCallback must be called after addDevice so that
- // the physical camera status callback can look up available regular
- // cameras.
- hardware::Return<Status> st = interface->setCallback(this);
- if (!st.isOk()) {
- ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), st.description().c_str());
- return DEAD_OBJECT;
- }
- if (st != Status::OK) {
- ALOGE("%s: Unable to register callbacks with camera provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(st);
- }
-
ALOGI("Camera provider %s ready with %zu camera devices",
mProviderName.c_str(), mDevices.size());
- mInitialized = true;
+ // Process cached status callbacks
+ std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus =
+ std::make_unique<std::vector<CameraStatusInfoT>>();
+ {
+ std::lock_guard<std::mutex> lock(mInitLock);
+
+ for (auto& statusInfo : mCachedStatus) {
+ std::string id, physicalId;
+ status_t res = OK;
+ if (statusInfo.isPhysicalCameraStatus) {
+ res = physicalCameraDeviceStatusChangeLocked(&id, &physicalId,
+ statusInfo.cameraId, statusInfo.physicalCameraId, statusInfo.status);
+ } else {
+ res = cameraDeviceStatusChangeLocked(&id, statusInfo.cameraId, statusInfo.status);
+ }
+ if (res == OK) {
+ cachedStatus->emplace_back(statusInfo.isPhysicalCameraStatus,
+ id.c_str(), physicalId.c_str(), statusInfo.status);
+ }
+ }
+ mCachedStatus.clear();
+
+ mInitialized = true;
+ }
+
+ // The cached status change callbacks cannot be fired directly from this
+ // function, due to same-thread deadlock trying to acquire mInterfaceMutex
+ // twice.
+ if (listener != nullptr) {
+ mInitialStatusCallbackFuture = std::async(std::launch::async,
+ &CameraProviderManager::ProviderInfo::notifyInitialStatusChange, this,
+ listener, std::move(cachedStatus));
+ }
+
return OK;
}
@@ -1734,104 +1764,139 @@
CameraDeviceStatus newStatus) {
sp<StatusListener> listener;
std::string id;
- bool initialized = false;
+ std::lock_guard<std::mutex> lock(mInitLock);
+
+ if (!mInitialized) {
+ mCachedStatus.emplace_back(false /*isPhysicalCameraStatus*/,
+ cameraDeviceName.c_str(), std::string().c_str(), newStatus);
+ return hardware::Void();
+ }
+
{
std::lock_guard<std::mutex> lock(mLock);
- bool known = false;
- for (auto& deviceInfo : mDevices) {
- if (deviceInfo->mName == cameraDeviceName) {
- ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(),
- deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus));
- deviceInfo->mStatus = newStatus;
- // TODO: Handle device removal (NOT_PRESENT)
- id = deviceInfo->mId;
- known = true;
- break;
- }
- }
- // Previously unseen device; status must not be NOT_PRESENT
- if (!known) {
- if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
- ALOGW("Camera provider %s says an unknown camera device %s is not present. Curious.",
- mProviderName.c_str(), cameraDeviceName.c_str());
- return hardware::Void();
- }
- addDevice(cameraDeviceName, newStatus, &id);
- } else if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
- removeDevice(id);
+ if (OK != cameraDeviceStatusChangeLocked(&id, cameraDeviceName, newStatus)) {
+ return hardware::Void();
}
listener = mManager->getStatusListener();
- initialized = mInitialized;
- if (reCacheConcurrentStreamingCameraIdsLocked() != OK) {
- ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ",
- __FUNCTION__, mProviderName.c_str());
- }
}
+
// Call without lock held to allow reentrancy into provider manager
- // Don't send the callback if providerInfo hasn't been initialized.
- // CameraService will initialize device status after provider is
- // initialized
- if (listener != nullptr && initialized) {
+ if (listener != nullptr) {
listener->onDeviceStatusChanged(String8(id.c_str()), newStatus);
}
+
return hardware::Void();
}
+status_t CameraProviderManager::ProviderInfo::cameraDeviceStatusChangeLocked(
+ std::string* id, const hardware::hidl_string& cameraDeviceName,
+ CameraDeviceStatus newStatus) {
+ bool known = false;
+ std::string cameraId;
+ for (auto& deviceInfo : mDevices) {
+ if (deviceInfo->mName == cameraDeviceName) {
+ ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(),
+ deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus));
+ deviceInfo->mStatus = newStatus;
+ // TODO: Handle device removal (NOT_PRESENT)
+ cameraId = deviceInfo->mId;
+ known = true;
+ break;
+ }
+ }
+ // Previously unseen device; status must not be NOT_PRESENT
+ if (!known) {
+ if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
+ ALOGW("Camera provider %s says an unknown camera device %s is not present. Curious.",
+ mProviderName.c_str(), cameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+ addDevice(cameraDeviceName, newStatus, &cameraId);
+ } else if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
+ removeDevice(cameraId);
+ }
+ if (reCacheConcurrentStreamingCameraIdsLocked() != OK) {
+ ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ",
+ __FUNCTION__, mProviderName.c_str());
+ }
+ *id = cameraId;
+ return OK;
+}
+
hardware::Return<void> CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChange(
const hardware::hidl_string& cameraDeviceName,
const hardware::hidl_string& physicalCameraDeviceName,
CameraDeviceStatus newStatus) {
sp<StatusListener> listener;
std::string id;
- bool initialized = false;
+ std::string physicalId;
+ std::lock_guard<std::mutex> lock(mInitLock);
+
+ if (!mInitialized) {
+ mCachedStatus.emplace_back(true /*isPhysicalCameraStatus*/, cameraDeviceName,
+ physicalCameraDeviceName, newStatus);
+ return hardware::Void();
+ }
+
{
std::lock_guard<std::mutex> lock(mLock);
- bool known = false;
- for (auto& deviceInfo : mDevices) {
- if (deviceInfo->mName == cameraDeviceName) {
- id = deviceInfo->mId;
- if (!deviceInfo->mIsLogicalCamera) {
- ALOGE("%s: Invalid combination of camera id %s, physical id %s",
- __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str());
- return hardware::Void();
- }
- if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
- physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) {
- ALOGE("%s: Invalid combination of camera id %s, physical id %s",
- __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str());
- return hardware::Void();
- }
- ALOGI("Camera device %s physical device %s status is now %s, was %s",
- cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(),
- deviceStatusToString(newStatus), deviceStatusToString(
- deviceInfo->mPhysicalStatus[physicalCameraDeviceName]));
- known = true;
- break;
- }
- }
- // Previously unseen device; status must not be NOT_PRESENT
- if (!known) {
- ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.",
- mProviderName.c_str(), cameraDeviceName.c_str(),
- physicalCameraDeviceName.c_str());
+ if (OK != physicalCameraDeviceStatusChangeLocked(&id, &physicalId, cameraDeviceName,
+ physicalCameraDeviceName, newStatus)) {
return hardware::Void();
}
+
listener = mManager->getStatusListener();
- initialized = mInitialized;
}
// Call without lock held to allow reentrancy into provider manager
- // Don't send the callback if providerInfo hasn't been initialized.
- // CameraService will initialize device status after provider is
- // initialized
- if (listener != nullptr && initialized) {
- String8 physicalId(physicalCameraDeviceName.c_str());
+ if (listener != nullptr) {
listener->onDeviceStatusChanged(String8(id.c_str()),
- physicalId, newStatus);
+ String8(physicalId.c_str()), newStatus);
}
return hardware::Void();
}
+status_t CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChangeLocked(
+ std::string* id, std::string* physicalId,
+ const hardware::hidl_string& cameraDeviceName,
+ const hardware::hidl_string& physicalCameraDeviceName,
+ CameraDeviceStatus newStatus) {
+ bool known = false;
+ std::string cameraId;
+ for (auto& deviceInfo : mDevices) {
+ if (deviceInfo->mName == cameraDeviceName) {
+ cameraId = deviceInfo->mId;
+ if (!deviceInfo->mIsLogicalCamera) {
+ ALOGE("%s: Invalid combination of camera id %s, physical id %s",
+ __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+ if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
+ physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) {
+ ALOGE("%s: Invalid combination of camera id %s, physical id %s",
+ __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+ ALOGI("Camera device %s physical device %s status is now %s",
+ cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(),
+ deviceStatusToString(newStatus));
+ known = true;
+ break;
+ }
+ }
+ // Previously unseen device; status must not be NOT_PRESENT
+ if (!known) {
+ ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.",
+ mProviderName.c_str(), cameraDeviceName.c_str(),
+ physicalCameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+
+ *id = cameraId;
+ *physicalId = physicalCameraDeviceName.c_str();
+ return OK;
+}
+
hardware::Return<void> CameraProviderManager::ProviderInfo::torchModeStatusChange(
const hardware::hidl_string& cameraDeviceName,
TorchModeStatus newStatus) {
@@ -1986,6 +2051,20 @@
return INVALID_OPERATION;
}
+void CameraProviderManager::ProviderInfo::notifyInitialStatusChange(
+ sp<StatusListener> listener,
+ std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus) {
+ for (auto& statusInfo : *cachedStatus) {
+ if (statusInfo.isPhysicalCameraStatus) {
+ listener->onDeviceStatusChanged(String8(statusInfo.cameraId.c_str()),
+ String8(statusInfo.physicalCameraId.c_str()), statusInfo.status);
+ } else {
+ listener->onDeviceStatusChanged(
+ String8(statusInfo.cameraId.c_str()), statusInfo.status);
+ }
+ }
+}
+
template<class DeviceInfoT>
std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
CameraProviderManager::ProviderInfo::initializeDeviceInfo(
@@ -2689,9 +2768,11 @@
CameraProviderManager::ProviderInfo::~ProviderInfo() {
+ if (mInitialStatusCallbackFuture.valid()) {
+ mInitialStatusCallbackFuture.wait();
+ }
// Destruction of ProviderInfo is only supposed to happen when the respective
// CameraProvider interface dies, so do not unregister callbacks.
-
}
status_t CameraProviderManager::mapToStatusT(const Status& s) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 25d3639..a0e5f8f 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -22,6 +22,7 @@
#include <unordered_set>
#include <string>
#include <mutex>
+#include <future>
#include <camera/camera2/ConcurrentCamera.h>
#include <camera/CameraParameters2.h>
@@ -403,6 +404,15 @@
const hardware::hidl_string& physicalCameraDeviceName,
hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
+ status_t cameraDeviceStatusChangeLocked(
+ std::string* id, const hardware::hidl_string& cameraDeviceName,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus);
+ status_t physicalCameraDeviceStatusChangeLocked(
+ std::string* id, std::string* physicalId,
+ const hardware::hidl_string& cameraDeviceName,
+ const hardware::hidl_string& physicalCameraDeviceName,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus);
+
// hidl_death_recipient interface - this locks the parent mInterfaceMutex
virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override;
@@ -444,8 +454,6 @@
const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
hardware::camera::common::V1_0::CameraDeviceStatus mStatus;
- std::map<std::string, hardware::camera::common::V1_0::CameraDeviceStatus>
- mPhysicalStatus;
wp<ProviderInfo> mParentProvider;
@@ -600,7 +608,27 @@
CameraProviderManager *mManager;
+ struct CameraStatusInfoT {
+ bool isPhysicalCameraStatus = false;
+ hardware::hidl_string cameraId;
+ hardware::hidl_string physicalCameraId;
+ hardware::camera::common::V1_0::CameraDeviceStatus status;
+ CameraStatusInfoT(bool isForPhysicalCamera, const hardware::hidl_string& id,
+ const hardware::hidl_string& physicalId,
+ hardware::camera::common::V1_0::CameraDeviceStatus s) :
+ isPhysicalCameraStatus(isForPhysicalCamera), cameraId(id),
+ physicalCameraId(physicalId), status(s) {}
+ };
+
+ // Lock to synchronize between initialize() and camera status callbacks
+ std::mutex mInitLock;
bool mInitialized = false;
+ std::vector<CameraStatusInfoT> mCachedStatus;
+ // End of scope for mInitLock
+
+ std::future<void> mInitialStatusCallbackFuture;
+ void notifyInitialStatusChange(sp<StatusListener> listener,
+ std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus);
std::vector<std::unordered_set<std::string>> mConcurrentCameraIdCombinations;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index eea5ef1..08cde5d 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -1218,13 +1218,13 @@
return;
}
+ bufRet.streamId = streamId;
if (outputStream->isAbandoned()) {
bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
allReqsSucceeds = false;
continue;
}
- bufRet.streamId = streamId;
size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
uint32_t numBuffersRequested = bufReq.numBuffersRequested;
size_t totalHandout = handOutBufferCount + numBuffersRequested;