Merge "Camera: Move app ops to start/stop of streaming" into sc-dev
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index fc5b75d..bab651f 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -454,19 +454,11 @@
} // namespace
-static IV_COLOR_FORMAT_T GetIvColorFormat() {
- static IV_COLOR_FORMAT_T sColorFormat =
- (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_UV) ? IV_YUV_420SP_UV :
- (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_VU) ? IV_YUV_420SP_VU :
- IV_YUV_420P;
- return sColorFormat;
-}
-
C2SoftAvcEnc::C2SoftAvcEnc(
const char *name, c2_node_id_t id, const std::shared_ptr<IntfImpl> &intfImpl)
: SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
mIntf(intfImpl),
- mIvVideoColorFormat(GetIvColorFormat()),
+ mIvVideoColorFormat(IV_YUV_420P),
mAVCEncProfile(IV_PROFILE_BASE),
mAVCEncLevel(41),
mStarted(false),
@@ -1034,7 +1026,8 @@
// Assume worst case output buffer size to be equal to number of bytes in input
mOutBufferSize = std::max(width * height * 3 / 2, kMinOutBufferSize);
- mIvVideoColorFormat = GetIvColorFormat();
+ // TODO
+ mIvVideoColorFormat = IV_YUV_420P;
ALOGD("Params width %d height %d level %d colorFormat %d bframes %d", width,
height, mAVCEncLevel, mIvVideoColorFormat, mBframes);
@@ -1332,6 +1325,7 @@
mSize->width, input->height(), mSize->height);
return C2_BAD_VALUE;
}
+ ALOGV("width = %d, height = %d", input->width(), input->height());
const C2PlanarLayout &layout = input->layout();
uint8_t *yPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_Y]);
uint8_t *uPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_U]);
@@ -1368,8 +1362,7 @@
return C2_BAD_VALUE;
}
- if (mIvVideoColorFormat == IV_YUV_420P
- && layout.planes[layout.PLANE_Y].colInc == 1
+ if (layout.planes[layout.PLANE_Y].colInc == 1
&& layout.planes[layout.PLANE_U].colInc == 1
&& layout.planes[layout.PLANE_V].colInc == 1
&& uStride == vStride
@@ -1377,61 +1370,21 @@
// I420 compatible - already set up above
break;
}
- if (mIvVideoColorFormat == IV_YUV_420SP_UV
- && layout.planes[layout.PLANE_Y].colInc == 1
- && layout.planes[layout.PLANE_U].colInc == 2
- && layout.planes[layout.PLANE_V].colInc == 2
- && uStride == vStride
- && yStride == vStride
- && uPlane + 1 == vPlane) {
- // NV12 compatible - already set up above
- break;
- }
- if (mIvVideoColorFormat == IV_YUV_420SP_VU
- && layout.planes[layout.PLANE_Y].colInc == 1
- && layout.planes[layout.PLANE_U].colInc == 2
- && layout.planes[layout.PLANE_V].colInc == 2
- && uStride == vStride
- && yStride == vStride
- && uPlane == vPlane + 1) {
- // NV21 compatible - already set up above
- break;
- }
// copy to I420
yStride = width;
uStride = vStride = yStride / 2;
MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
- MediaImage2 img;
- switch (mIvVideoColorFormat) {
- case IV_YUV_420P:
- img = CreateYUV420PlanarMediaImage2(width, height, yStride, height);
- yPlane = conversionBuffer.data();
- uPlane = yPlane + yPlaneSize;
- vPlane = uPlane + yPlaneSize / 4;
- break;
- case IV_YUV_420SP_VU:
- img = CreateYUV420SemiPlanarMediaImage2(width, height, yStride, height);
- img.mPlane[MediaImage2::U].mOffset++;
- img.mPlane[MediaImage2::V].mOffset--;
- yPlane = conversionBuffer.data();
- vPlane = yPlane + yPlaneSize;
- uPlane = vPlane + 1;
- break;
- case IV_YUV_420SP_UV:
- default:
- img = CreateYUV420SemiPlanarMediaImage2(width, height, yStride, height);
- yPlane = conversionBuffer.data();
- uPlane = yPlane + yPlaneSize;
- vPlane = uPlane + 1;
- break;
- }
+ MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, yStride, height);
status_t err = ImageCopy(conversionBuffer.data(), &img, *input);
if (err != OK) {
ALOGE("Buffer conversion failed: %d", err);
return C2_BAD_VALUE;
}
+ yPlane = conversionBuffer.data();
+ uPlane = yPlane + yPlaneSize;
+ vPlane = uPlane + yPlaneSize / 4;
break;
}
@@ -1477,17 +1430,15 @@
break;
}
- case IV_YUV_420SP_VU:
- uPlane = vPlane;
- [[fallthrough]];
case IV_YUV_420SP_UV:
+ case IV_YUV_420SP_VU:
default:
{
ps_inp_raw_buf->apv_bufs[0] = yPlane;
ps_inp_raw_buf->apv_bufs[1] = uPlane;
ps_inp_raw_buf->au4_wd[0] = mSize->width;
- ps_inp_raw_buf->au4_wd[1] = mSize->width / 2;
+ ps_inp_raw_buf->au4_wd[1] = mSize->width;
ps_inp_raw_buf->au4_ht[0] = mSize->height;
ps_inp_raw_buf->au4_ht[1] = mSize->height / 2;
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index fb3fbd0..dfad226 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -110,17 +110,20 @@
}
case kWhatStop: {
int32_t err = thiz->onStop();
+ thiz->mOutputBlockPool.reset();
Reply(msg, &err);
break;
}
case kWhatReset: {
thiz->onReset();
+ thiz->mOutputBlockPool.reset();
mRunning = false;
Reply(msg);
break;
}
case kWhatRelease: {
thiz->onRelease();
+ thiz->mOutputBlockPool.reset();
mRunning = false;
Reply(msg);
break;
diff --git a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy
index f701987..5d0284f 100644
--- a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy
@@ -35,7 +35,7 @@
# on ARM is statically loaded at 0xffff 0000. See
# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
# for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
munmap: 1
prctl: 1
writev: 1
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 63ae5cd..15d2989 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1798,17 +1798,19 @@
}
status_t CCodec::setSurface(const sp<Surface> &surface) {
- Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
- const std::unique_ptr<Config> &config = *configLocked;
- if (config->mTunneled && config->mSidebandHandle != nullptr) {
- sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(surface.get());
- status_t err = native_window_set_sideband_stream(
- nativeWindow.get(),
- const_cast<native_handle_t *>(config->mSidebandHandle->handle()));
- if (err != OK) {
- ALOGE("NativeWindow(%p) native_window_set_sideband_stream(%p) failed! (err %d).",
- nativeWindow.get(), config->mSidebandHandle->handle(), err);
- return err;
+ {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ if (config->mTunneled && config->mSidebandHandle != nullptr) {
+ sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(surface.get());
+ status_t err = native_window_set_sideband_stream(
+ nativeWindow.get(),
+ const_cast<native_handle_t *>(config->mSidebandHandle->handle()));
+ if (err != OK) {
+ ALOGE("NativeWindow(%p) native_window_set_sideband_stream(%p) failed! (err %d).",
+ nativeWindow.get(), config->mSidebandHandle->handle(), err);
+ return err;
+ }
}
}
return mChannel->setSurface(surface);
@@ -2149,80 +2151,92 @@
}
// handle configuration changes in work done
- Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
- const std::unique_ptr<Config> &config = *configLocked;
- Config::Watcher<C2StreamInitDataInfo::output> initData =
- config->watch<C2StreamInitDataInfo::output>();
- if (!work->worklets.empty()
- && (work->worklets.front()->output.flags
- & C2FrameData::FLAG_DISCARD_FRAME) == 0) {
+ std::unique_ptr<C2Param> initData;
+ sp<AMessage> outputFormat = nullptr;
+ {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ Config::Watcher<C2StreamInitDataInfo::output> initDataWatcher =
+ config->watch<C2StreamInitDataInfo::output>();
+ if (!work->worklets.empty()
+ && (work->worklets.front()->output.flags
+ & C2FrameData::FLAG_DISCARD_FRAME) == 0) {
- // copy buffer info to config
- std::vector<std::unique_ptr<C2Param>> updates;
- for (const std::unique_ptr<C2Param> ¶m
- : work->worklets.front()->output.configUpdate) {
- updates.push_back(C2Param::Copy(*param));
- }
- unsigned stream = 0;
- for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) {
- for (const std::shared_ptr<const C2Info> &info : buf->info()) {
- // move all info into output-stream #0 domain
- updates.emplace_back(C2Param::CopyAsStream(*info, true /* output */, stream));
+ // copy buffer info to config
+ std::vector<std::unique_ptr<C2Param>> updates;
+ for (const std::unique_ptr<C2Param> ¶m
+ : work->worklets.front()->output.configUpdate) {
+ updates.push_back(C2Param::Copy(*param));
+ }
+ unsigned stream = 0;
+ std::vector<std::shared_ptr<C2Buffer>> &outputBuffers =
+ work->worklets.front()->output.buffers;
+ for (const std::shared_ptr<C2Buffer> &buf : outputBuffers) {
+ for (const std::shared_ptr<const C2Info> &info : buf->info()) {
+ // move all info into output-stream #0 domain
+ updates.emplace_back(
+ C2Param::CopyAsStream(*info, true /* output */, stream));
+ }
+
+ const std::vector<C2ConstGraphicBlock> blocks = buf->data().graphicBlocks();
+ // for now only do the first block
+ if (!blocks.empty()) {
+ // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u",
+ // block.crop().left, block.crop().top,
+ // block.crop().width, block.crop().height,
+ // block.width(), block.height());
+ const C2ConstGraphicBlock &block = blocks[0];
+ updates.emplace_back(new C2StreamCropRectInfo::output(
+ stream, block.crop()));
+ updates.emplace_back(new C2StreamPictureSizeInfo::output(
+ stream, block.crop().width, block.crop().height));
+ }
+ ++stream;
}
- const std::vector<C2ConstGraphicBlock> blocks = buf->data().graphicBlocks();
- // for now only do the first block
- if (!blocks.empty()) {
- // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u",
- // block.crop().left, block.crop().top,
- // block.crop().width, block.crop().height,
- // block.width(), block.height());
- const C2ConstGraphicBlock &block = blocks[0];
- updates.emplace_back(new C2StreamCropRectInfo::output(stream, block.crop()));
- updates.emplace_back(new C2StreamPictureSizeInfo::output(
- stream, block.crop().width, block.crop().height));
- }
- ++stream;
- }
+ sp<AMessage> oldFormat = config->mOutputFormat;
+ config->updateConfiguration(updates, config->mOutputDomain);
+ RevertOutputFormatIfNeeded(oldFormat, config->mOutputFormat);
- sp<AMessage> outputFormat = config->mOutputFormat;
- config->updateConfiguration(updates, config->mOutputDomain);
- RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
-
- // copy standard infos to graphic buffers if not already present (otherwise, we
- // may overwrite the actual intermediate value with a final value)
- stream = 0;
- const static C2Param::Index stdGfxInfos[] = {
- C2StreamRotationInfo::output::PARAM_TYPE,
- C2StreamColorAspectsInfo::output::PARAM_TYPE,
- C2StreamDataSpaceInfo::output::PARAM_TYPE,
- C2StreamHdrStaticInfo::output::PARAM_TYPE,
- C2StreamHdr10PlusInfo::output::PARAM_TYPE,
- C2StreamPixelAspectRatioInfo::output::PARAM_TYPE,
- C2StreamSurfaceScalingInfo::output::PARAM_TYPE
- };
- for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) {
- if (buf->data().graphicBlocks().size()) {
- for (C2Param::Index ix : stdGfxInfos) {
- if (!buf->hasInfo(ix)) {
- const C2Param *param =
- config->getConfigParameterValue(ix.withStream(stream));
- if (param) {
- std::shared_ptr<C2Param> info(C2Param::Copy(*param));
- buf->setInfo(std::static_pointer_cast<C2Info>(info));
+ // copy standard infos to graphic buffers if not already present (otherwise, we
+ // may overwrite the actual intermediate value with a final value)
+ stream = 0;
+ const static C2Param::Index stdGfxInfos[] = {
+ C2StreamRotationInfo::output::PARAM_TYPE,
+ C2StreamColorAspectsInfo::output::PARAM_TYPE,
+ C2StreamDataSpaceInfo::output::PARAM_TYPE,
+ C2StreamHdrStaticInfo::output::PARAM_TYPE,
+ C2StreamHdr10PlusInfo::output::PARAM_TYPE,
+ C2StreamPixelAspectRatioInfo::output::PARAM_TYPE,
+ C2StreamSurfaceScalingInfo::output::PARAM_TYPE
+ };
+ for (const std::shared_ptr<C2Buffer> &buf : outputBuffers) {
+ if (buf->data().graphicBlocks().size()) {
+ for (C2Param::Index ix : stdGfxInfos) {
+ if (!buf->hasInfo(ix)) {
+ const C2Param *param =
+ config->getConfigParameterValue(ix.withStream(stream));
+ if (param) {
+ std::shared_ptr<C2Param> info(C2Param::Copy(*param));
+ buf->setInfo(std::static_pointer_cast<C2Info>(info));
+ }
}
}
}
+ ++stream;
}
- ++stream;
}
- }
- if (config->mInputSurface) {
- config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
+ if (config->mInputSurface) {
+ config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
+ }
+ if (initDataWatcher.hasChanged()) {
+ initData = C2Param::Copy(*initDataWatcher.update().get());
+ }
+ outputFormat = config->mOutputFormat;
}
mChannel->onWorkDone(
- std::move(work), config->mOutputFormat,
- initData.hasChanged() ? initData.update().get() : nullptr);
+ std::move(work), outputFormat,
+ initData ? (C2StreamInitDataInfo::output *)initData.get() : nullptr);
break;
}
case kWhatWatch: {
@@ -2307,9 +2321,13 @@
pendingDeadline = true;
}
}
- Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
- const std::unique_ptr<Config> &config = *configLocked;
- if (config->mTunneled == false && name.empty()) {
+ bool tunneled = false;
+ {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ tunneled = config->mTunneled;
+ }
+ if (!tunneled && name.empty()) {
constexpr std::chrono::steady_clock::duration kWorkDurationThreshold = 3s;
std::chrono::steady_clock::duration elapsed = mChannel->elapsed();
if (elapsed >= kWorkDurationThreshold) {
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index a78d811..0966988 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -346,7 +346,7 @@
}
return (img->mPlane[1].mColInc == 2
&& img->mPlane[2].mColInc == 2
- && (img->mPlane[2].mOffset - img->mPlane[1].mOffset == 1));
+ && (img->mPlane[2].mOffset == img->mPlane[1].mOffset + 1));
}
bool IsNV21(const MediaImage2 *img) {
@@ -355,7 +355,7 @@
}
return (img->mPlane[1].mColInc == 2
&& img->mPlane[2].mColInc == 2
- && (img->mPlane[1].mOffset - img->mPlane[2].mOffset == 1));
+ && (img->mPlane[1].mOffset == img->mPlane[2].mOffset + 1));
}
bool IsI420(const MediaImage2 *img) {
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 1bbe443..f4a40a8 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
#include <audio_utils/primitives.h>
#include <aaudio/AAudio.h>
+#include <media/MediaMetricsItem.h>
#include "client/AudioStreamInternalCapture.h"
#include "utility/AudioClock.h"
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 3f17e6b..71bde90 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -19,6 +19,7 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <media/MediaMetricsItem.h>
#include <utils/Trace.h>
#include "client/AudioStreamInternalPlay.h"
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index e8f71be..ef83c8e 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -59,6 +59,10 @@
if (!mMetricsId.empty()) {
android::mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM)
+ .set(AMEDIAMETRICS_PROP_ENCODINGREQUESTED,
+ android::toString(mDeviceFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL,
+ AudioGlobal_convertPerformanceModeToText(getPerformanceMode()))
.record();
}
@@ -124,7 +128,12 @@
.set(AMEDIAMETRICS_PROP_PERFORMANCEMODE,
AudioGlobal_convertPerformanceModeToText(getPerformanceMode()))
.set(AMEDIAMETRICS_PROP_SHARINGMODE,
- AudioGlobal_convertSharingModeToText(getSharingMode()));
+ AudioGlobal_convertSharingModeToText(getSharingMode()))
+ .set(AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, getBufferCapacity())
+ .set(AMEDIAMETRICS_PROP_BURSTFRAMES, getFramesPerBurst())
+ .set(AMEDIAMETRICS_PROP_DIRECTION,
+ AudioGlobal_convertDirectionToText(getDirection()));
+
if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
item.set(AMEDIAMETRICS_PROP_PLAYERIID, mPlayerBase->getPlayerIId());
}
@@ -338,6 +347,22 @@
return AAUDIO_OK;
}
+void AudioStream::close_l() {
+ // Releasing the stream will set the state to CLOSING.
+ assert(getState() == AAUDIO_STREAM_STATE_CLOSING);
+ // setState() prevents a transition from CLOSING to any state other than CLOSED.
+ // State is checked by destructor.
+ setState(AAUDIO_STREAM_STATE_CLOSED);
+
+ if (!mMetricsId.empty()) {
+ android::mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_FRAMESTRANSFERRED,
+ getDirection() == AAUDIO_DIRECTION_INPUT ? getFramesWritten()
+ : getFramesRead())
+ .record();
+ }
+}
+
void AudioStream::setState(aaudio_stream_state_t state) {
ALOGD("%s(s#%d) from %d to %d", __func__, getId(), mState, state);
if (state == mState) {
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index abf62f3..3930964 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -146,13 +146,7 @@
* Free any resources not already freed by release_l().
* Assume release_l() already called.
*/
- virtual void close_l() REQUIRES(mStreamLock) {
- // Releasing the stream will set the state to CLOSING.
- assert(getState() == AAUDIO_STREAM_STATE_CLOSING);
- // setState() prevents a transition from CLOSING to any state other than CLOSED.
- // State is checked by destructor.
- setState(AAUDIO_STREAM_STATE_CLOSED);
- }
+ virtual void close_l() REQUIRES(mStreamLock);
public:
// This is only used to identify a stream in the logs without
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 7733a04..e3ac6ff 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -308,11 +308,19 @@
}
void AudioStreamRecord::close_l() {
+ // The callbacks are normally joined in the AudioRecord destructor.
+ // But if another object has a reference to the AudioRecord then
+ // it will not get deleted here.
+ // So we should join callbacks explicitly before returning.
+ // Unlock around the join to avoid deadlocks if the callback tries to lock.
+ // This can happen if the callback returns AAUDIO_CALLBACK_RESULT_STOP
+ mStreamLock.unlock();
+ mAudioRecord->stopAndJoinCallbacks();
+ mStreamLock.lock();
+
mAudioRecord.clear();
- // Do not close mFixedBlockWriter because a data callback
- // thread might still be running if someone else has a reference
- // to mAudioRecord.
- // It has a unique_ptr to its buffer so it will clean up by itself.
+ // Do not close mFixedBlockReader. It has a unique_ptr to its buffer
+ // so it will clean up by itself.
AudioStream::close_l();
}
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 142a85c..df97658 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -259,12 +259,18 @@
}
void AudioStreamTrack::close_l() {
- // Stop callbacks before deleting mFixedBlockReader memory.
+ // The callbacks are normally joined in the AudioTrack destructor.
+ // But if another object has a reference to the AudioTrack then
+ // it will not get deleted here.
+ // So we should join callbacks explicitly before returning.
+ // Unlock around the join to avoid deadlocks if the callback tries to lock.
+ // This can happen if the callback returns AAUDIO_CALLBACK_RESULT_STOP
+ mStreamLock.unlock();
+ mAudioTrack->stopAndJoinCallbacks();
+ mStreamLock.lock();
mAudioTrack.clear();
- // Do not close mFixedBlockReader because a data callback
- // thread might still be running if someone else has a reference
- // to mAudioRecord.
- // It has a unique_ptr to its buffer so it will clean up by itself.
+ // Do not close mFixedBlockReader. It has a unique_ptr to its buffer
+ // so it will clean up by itself.
AudioStream::close_l();
}
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index f9eebd7..98e9727 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -209,9 +209,9 @@
}
cc_test {
- name: "test_stop_hang",
+ name: "test_callback_race",
defaults: ["libaaudio_tests_defaults"],
- srcs: ["test_stop_hang.cpp"],
+ srcs: ["test_callback_race.cpp"],
shared_libs: [
"libaaudio",
"libbinder",
diff --git a/media/libaaudio/tests/test_callback_race.cpp b/media/libaaudio/tests/test_callback_race.cpp
new file mode 100644
index 0000000..843d5d7
--- /dev/null
+++ b/media/libaaudio/tests/test_callback_race.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/**
+ * Test whether the callback is joined before the close finishes.
+ *
+ * Start a stream with a callback.
+ * The callback just sleeps for a long time.
+ * While the callback is sleeping, close() the stream from the main thread.
+ * Then check to make sure the callback was joined before the close() returns.
+ *
+ * This can hang if there are deadlocks. So make sure you get a PASSED result.
+ */
+
+#include <atomic>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <aaudio/AAudio.h>
+
+// Sleep long enough that the foreground has a change to call close.
+static constexpr int kCallbackSleepMicros = 600 * 1000;
+
+class AudioEngine {
+public:
+
+ // Check for a crash or late callback if we close without stopping.
+ void checkCloseJoins(aaudio_direction_t direction,
+ aaudio_performance_mode_t perfMode,
+ aaudio_data_callback_result_t callbackResult) {
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+ mCallbackResult = callbackResult;
+ startStreamForStall(direction, perfMode);
+ // When the callback starts it will go to sleep.
+ waitForCallbackToStart();
+
+ printf("call AAudioStream_close()\n");
+ ASSERT_FALSE(mCallbackFinished); // Still sleeping?
+ aaudio_result_t result = AAudioStream_close(mStream); // May hang here!
+ ASSERT_TRUE(mCallbackFinished);
+ ASSERT_EQ(AAUDIO_OK, result);
+ printf("AAudioStream_close() returned %d\n", result);
+
+ ASSERT_EQ(AAUDIO_OK, mError.load());
+ // Did calling stop() from callback fail? It should have.
+ ASSERT_NE(AAUDIO_OK, mStopResult.load());
+ }
+
+private:
+ void startStreamForStall(aaudio_direction_t direction,
+ aaudio_performance_mode_t perfMode) {
+ AAudioStreamBuilder* builder = nullptr;
+ aaudio_result_t result = AAUDIO_OK;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ result = AAudio_createStreamBuilder(&builder);
+ ASSERT_EQ(AAUDIO_OK, result);
+
+ // Request stream properties.
+ AAudioStreamBuilder_setDirection(builder, direction);
+ AAudioStreamBuilder_setPerformanceMode(builder, perfMode);
+ AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, this);
+ AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, this);
+
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(builder, &mStream);
+ AAudioStreamBuilder_delete(builder);
+ ASSERT_EQ(AAUDIO_OK, result);
+
+ // Check to see what kind of stream we actually got.
+ int32_t deviceId = AAudioStream_getDeviceId(mStream);
+ aaudio_performance_mode_t
+ actualPerfMode = AAudioStream_getPerformanceMode(mStream);
+ printf("-------- opened: deviceId = %3d, perfMode = %d\n",
+ deviceId,
+ actualPerfMode);
+
+ // Start stream.
+ result = AAudioStream_requestStart(mStream);
+ ASSERT_EQ(AAUDIO_OK, result);
+ }
+
+ void waitForCallbackToStart() {
+ // Wait for callback to say it has been called.
+ int countDownMillis = 2000;
+ constexpr int countDownPeriodMillis = 50;
+ while (!mCallbackStarted && countDownMillis > 0) {
+ printf("Waiting for callback to start, %d\n", countDownMillis);
+ usleep(countDownPeriodMillis * 1000);
+ countDownMillis -= countDownPeriodMillis;
+ }
+ ASSERT_LT(0, countDownMillis);
+ ASSERT_TRUE(mCallbackStarted);
+ }
+
+// Callback function that fills the audio output buffer.
+ static aaudio_data_callback_result_t s_myDataCallbackProc(
+ AAudioStream *stream,
+ void *userData,
+ void * /*audioData */,
+ int32_t /* numFrames */
+ ) {
+ AudioEngine* engine = (AudioEngine*) userData;
+ engine->mCallbackStarted = true;
+ usleep(kCallbackSleepMicros);
+ // it is illegal to call stop() from the callback. It should
+ // return an error and not hang.
+ engine->mStopResult = AAudioStream_requestStop(stream);
+ engine->mCallbackFinished = true;
+ return engine->mCallbackResult;
+ }
+
+ static void s_myErrorCallbackProc(
+ AAudioStream * /* stream */,
+ void *userData,
+ aaudio_result_t error) {
+ AudioEngine *engine = (AudioEngine *)userData;
+ engine->mError = error;
+ }
+
+ AAudioStream* mStream = nullptr;
+
+ std::atomic<aaudio_result_t> mError{AAUDIO_OK}; // written by error callback
+ std::atomic<bool> mCallbackStarted{false}; // written by data callback
+ std::atomic<bool> mCallbackFinished{false}; // written by data callback
+ std::atomic<aaudio_data_callback_result_t> mCallbackResult{AAUDIO_CALLBACK_RESULT_CONTINUE};
+ std::atomic<aaudio_result_t> mStopResult{AAUDIO_OK};
+};
+
+/*********************************************************************/
+// Tell the callback to return AAUDIO_CALLBACK_RESULT_CONTINUE.
+
+TEST(test_close_timing, aaudio_close_joins_input_none) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_none) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+TEST(test_close_timing, aaudio_close_joins_input_lowlat) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_lowlat) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+/*********************************************************************/
+// Tell the callback to return AAUDIO_CALLBACK_RESULT_STOP.
+
+TEST(test_close_timing, aaudio_close_joins_input_lowlat_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_lowlat_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_none_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
+
+TEST(test_close_timing, aaudio_close_joins_input_none_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
diff --git a/media/libaaudio/tests/test_stop_hang.cpp b/media/libaaudio/tests/test_stop_hang.cpp
deleted file mode 100644
index 982ff4a..0000000
--- a/media/libaaudio/tests/test_stop_hang.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-/**
- * Return stop from the callback
- * and then close the stream immediately.
- */
-
-#include <atomic>
-#include <mutex>
-#include <stdio.h>
-#include <thread>
-#include <unistd.h>
-
-#include <aaudio/AAudio.h>
-
-#define DURATION_SECONDS 5
-
-struct AudioEngine {
- AAudioStreamBuilder *builder = nullptr;
- AAudioStream *stream = nullptr;
- std::thread *thread = nullptr;
-
- std::atomic<bool> started{false};
- std::mutex doneLock; // Use a mutex so we can sleep on it while join()ing.
- std::atomic<bool> done{false};
-
- aaudio_result_t join() {
- aaudio_result_t result = AAUDIO_ERROR_INVALID_STATE;
- if (stream != nullptr) {
- while (true) {
- {
- // Will block if the thread is running.
- // This mutex is used to close() immediately after the callback returns
- // and before the requestStop_l() is called.
- std::lock_guard<std::mutex> lock(doneLock);
- if (done) break;
- }
- printf("join() got mutex but stream not done!");
- usleep(10 * 1000); // sleep then check again
- }
- result = AAudioStream_close(stream);
- stream = nullptr;
- }
- return result;
- }
-};
-
-// Callback function that fills the audio output buffer.
-static aaudio_data_callback_result_t s_myDataCallbackProc(
- AAudioStream *stream,
- void *userData,
- void *audioData,
- int32_t numFrames
-) {
- (void) stream;
- (void) audioData;
- (void) numFrames;
- AudioEngine *engine = (struct AudioEngine *)userData;
- std::lock_guard<std::mutex> lock(engine->doneLock);
- engine->started = true;
- usleep(DURATION_SECONDS * 1000 * 1000); // Mimic SynthMark procedure.
- engine->done = true;
- return AAUDIO_CALLBACK_RESULT_STOP;
-}
-
-static void s_myErrorCallbackProc(
- AAudioStream *stream __unused,
- void *userData __unused,
- aaudio_result_t error) {
- printf("%s() - error = %d\n", __func__, error);
-}
-
-static aaudio_result_t s_OpenAudioStream(struct AudioEngine *engine) {
- // Use an AAudioStreamBuilder to contain requested parameters.
- aaudio_result_t result = AAudio_createStreamBuilder(&engine->builder);
- if (result != AAUDIO_OK) {
- printf("AAudio_createStreamBuilder returned %s",
- AAudio_convertResultToText(result));
- return result;
- }
-
- // Request stream properties.
- AAudioStreamBuilder_setPerformanceMode(engine->builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
- AAudioStreamBuilder_setDataCallback(engine->builder, s_myDataCallbackProc, engine);
- AAudioStreamBuilder_setErrorCallback(engine->builder, s_myErrorCallbackProc, engine);
-
- // Create an AAudioStream using the Builder.
- result = AAudioStreamBuilder_openStream(engine->builder, &engine->stream);
- if (result != AAUDIO_OK) {
- printf("AAudioStreamBuilder_openStream returned %s",
- AAudio_convertResultToText(result));
- return result;
- }
-
- return result;
-}
-
-int main(int argc, char **argv) {
- (void) argc;
- (void) argv;
- struct AudioEngine engine;
- aaudio_result_t result = AAUDIO_OK;
- int errorCount = 0;
-
- // Make printf print immediately so that debug info is not stuck
- // in a buffer if we hang or crash.
- setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
-
- printf("Test Return Stop Hang V1.0\n");
-
- result = s_OpenAudioStream(&engine);
- if (result != AAUDIO_OK) {
- printf("s_OpenAudioStream returned %s\n",
- AAudio_convertResultToText(result));
- errorCount++;
- }
-
- // Check to see what kind of stream we actually got.
- int32_t deviceId = AAudioStream_getDeviceId(engine.stream);
- aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(engine.stream);
- printf("-------- opened: deviceId = %3d, perfMode = %d\n", deviceId, actualPerfMode);
-
- // Start stream.
- result = AAudioStream_requestStart(engine.stream);
- printf("AAudioStream_requestStart() returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result);
- if (result != AAUDIO_OK) {
- errorCount++;
- } else {
- int counter = 0;
- while (!engine.started) {
- printf("Waiting for stream to start, %d\n", counter++);
- usleep(5 * 1000);
- }
- printf("You should see more messages %d seconds after this. If not then the test failed!\n",
- DURATION_SECONDS);
- result = engine.join(); // This might hang!
- AAudioStreamBuilder_delete(engine.builder);
- engine.builder = nullptr;
- }
-
- printf("aaudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- printf("test %s\n", errorCount ? "FAILED" : "PASSED");
-
- return errorCount ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index e15ef3d..90f6f41 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -181,21 +181,9 @@
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
.record();
+ stopAndJoinCallbacks(); // checks mStatus
+
if (mStatus == NO_ERROR) {
- // Make sure that callback function exits in the case where
- // it is looping on buffer empty condition in obtainBuffer().
- // Otherwise the callback thread will never exit.
- stop();
- if (mAudioRecordThread != 0) {
- mProxy->interrupt();
- mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
- mAudioRecordThread->requestExitAndWait();
- mAudioRecordThread.clear();
- }
- // No lock here: worst case we remove a NULL callback which will be a nop
- if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
- }
IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mAudioRecord.clear();
mCblkMemory.clear();
@@ -208,6 +196,27 @@
}
}
+void AudioRecord::stopAndJoinCallbacks() {
+ // Prevent nullptr crash if it did not open properly.
+ if (mStatus != NO_ERROR) return;
+
+ // Make sure that callback function exits in the case where
+ // it is looping on buffer empty condition in obtainBuffer().
+ // Otherwise the callback thread will never exit.
+ stop();
+ if (mAudioRecordThread != 0) {
+ mProxy->interrupt();
+ mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
+ mAudioRecordThread->requestExitAndWait();
+ mAudioRecordThread.clear();
+ }
+ // No lock here: worst case we remove a NULL callback which will be a nop
+ if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
+ // This may not stop all of these device callbacks!
+ // TODO: Add some sort of protection.
+ AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
+ }
+}
status_t AudioRecord::set(
audio_source_t inputSource,
uint32_t sampleRate,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6c9e85c..1bc3baa 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -327,21 +327,9 @@
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
.record();
+ stopAndJoinCallbacks(); // checks mStatus
+
if (mStatus == NO_ERROR) {
- // Make sure that callback function exits in the case where
- // it is looping on buffer full condition in obtainBuffer().
- // Otherwise the callback thread will never exit.
- stop();
- if (mAudioTrackThread != 0) {
- mProxy->interrupt();
- mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
- mAudioTrackThread->requestExitAndWait();
- mAudioTrackThread.clear();
- }
- // No lock here: worst case we remove a NULL callback which will be a nop
- if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
- }
IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
mCblkMemory.clear();
@@ -355,6 +343,29 @@
}
}
+void AudioTrack::stopAndJoinCallbacks() {
+ // Prevent nullptr crash if it did not open properly.
+ if (mStatus != NO_ERROR) return;
+
+ // Make sure that callback function exits in the case where
+ // it is looping on buffer full condition in obtainBuffer().
+ // Otherwise the callback thread will never exit.
+ stop();
+ if (mAudioTrackThread != 0) { // not thread safe
+ mProxy->interrupt();
+ mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
+ mAudioTrackThread->requestExitAndWait();
+ mAudioTrackThread.clear();
+ }
+ // No lock here: worst case we remove a NULL callback which will be a nop
+ if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
+ // This may not stop all of these device callbacks!
+ // TODO: Add some sort of protection.
+ AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
+ mDeviceCallback.clear();
+ }
+}
+
status_t AudioTrack::set(
audio_stream_type_t streamType,
uint32_t sampleRate,
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 82a29d4..3467c3a 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -303,6 +303,19 @@
void stop();
bool stopped() const;
+ /* Calls stop() and then wait for all of the callbacks to return.
+ * It is safe to call this if stop() or pause() has already been called.
+ *
+ * This function is called from the destructor. But since AudioRecord
+ * is ref counted, the destructor may be called later than desired.
+ * This can be called explicitly as part of closing an AudioRecord
+ * if you want to be certain that callbacks have completely finished.
+ *
+ * This is not thread safe and should only be called from one thread,
+ * ideally as the AudioRecord is being closed.
+ */
+ void stopAndJoinCallbacks();
+
/* Return the sink sample rate for this record track in Hz.
* If specified as zero in constructor or set(), this will be the source sample rate.
* Unlike AudioTrack, the sample rate is const after initialization, so doesn't need a lock.
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index d167c40..c293343 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -479,6 +479,19 @@
void stop();
bool stopped() const;
+ /* Call stop() and then wait for all of the callbacks to return.
+ * It is safe to call this if stop() or pause() has already been called.
+ *
+ * This function is called from the destructor. But since AudioTrack
+ * is ref counted, the destructor may be called later than desired.
+ * This can be called explicitly as part of closing an AudioTrack
+ * if you want to be certain that callbacks have completely finished.
+ *
+ * This is not thread safe and should only be called from one thread,
+ * ideally as the AudioTrack is being closed.
+ */
+ void stopAndJoinCallbacks();
+
/* Flush a stopped or paused track. All previously buffered data is discarded immediately.
* This has the effect of draining the buffers without mixing or output.
* Flush is intended for streaming mode, for example before switching to non-contiguous content.
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index de4f8d4..383bae8 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -160,6 +160,12 @@
#define AMEDIAMETRICS_PROP_VOLUME_LEFT "volume.left" // double (AudioTrack)
#define AMEDIAMETRICS_PROP_VOLUME_RIGHT "volume.right" // double (AudioTrack)
#define AMEDIAMETRICS_PROP_WHERE "where" // string value
+// EncodingRequested is the encoding format requested by the app
+#define AMEDIAMETRICS_PROP_ENCODINGREQUESTED "encodingRequested" // string
+// PerformanceModeActual is the actual selected performance mode, could be "none', "loeLatency" or
+// "powerSaving"
+#define AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL "performanceModeActual" // string
+#define AMEDIAMETRICS_PROP_FRAMESTRANSFERRED "framesTransferred" // int64_t, transferred frames
// Timing values: millisecond values are suffixed with MS and the type is double
// nanosecond values are suffixed with NS and the type is int64.
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index 68e2875..9705f3c 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -19,6 +19,7 @@
#define VALIDATE_STATE 1
+#include <android/permission_manager.h>
#include <inttypes.h>
#include <media/TranscodingSessionController.h>
#include <media/TranscodingUidPolicy.h>
@@ -193,7 +194,7 @@
~Pacer() = default;
- bool onSessionStarted(uid_t uid);
+ bool onSessionStarted(uid_t uid, uid_t callingUid);
void onSessionCompleted(uid_t uid, std::chrono::microseconds runningTime);
void onSessionCancelled(uid_t uid);
@@ -212,9 +213,49 @@
std::chrono::steady_clock::time_point lastCompletedTime;
};
std::map<uid_t, UidHistoryEntry> mUidHistoryMap;
+ std::unordered_set<uid_t> mMtpUids;
+ std::unordered_set<uid_t> mNonMtpUids;
+
+ bool isSubjectToQuota(uid_t uid, uid_t callingUid);
};
-bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid) {
+bool TranscodingSessionController::Pacer::isSubjectToQuota(uid_t uid, uid_t callingUid) {
+ // Submitting with self uid is not limited (which can only happen if it's used as an
+ // app-facing API). MediaProvider usage always submit on behalf of other uids.
+ if (uid == callingUid) {
+ return false;
+ }
+
+ if (mMtpUids.find(uid) != mMtpUids.end()) {
+ return false;
+ }
+
+ if (mNonMtpUids.find(uid) != mNonMtpUids.end()) {
+ return true;
+ }
+
+ // We don't have MTP permission info about this uid yet, check permission and save the result.
+ int32_t result;
+ if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
+ if (APermissionManager_checkPermission("android.permission.ACCESS_MTP", -1 /*pid*/, uid,
+ &result) == PERMISSION_MANAGER_STATUS_OK &&
+ result == PERMISSION_MANAGER_PERMISSION_GRANTED) {
+ mMtpUids.insert(uid);
+ return false;
+ }
+ }
+
+ mNonMtpUids.insert(uid);
+ return true;
+}
+
+bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid, uid_t callingUid) {
+ if (!isSubjectToQuota(uid, callingUid)) {
+ ALOGI("Pacer::onSessionStarted: uid %d (caling uid: %d): not subject to quota", uid,
+ callingUid);
+ return true;
+ }
+
// If uid doesn't exist, only insert the entry and mark session active. Skip quota checking.
if (mUidHistoryMap.find(uid) == mUidHistoryMap.end()) {
mUidHistoryMap.emplace(uid, UidHistoryEntry{});
@@ -494,7 +535,7 @@
// Check if at least one client has quota to start the session.
bool keepForClient = false;
for (uid_t uid : topSession->allClientUids) {
- if (mPacer->onSessionStarted(uid)) {
+ if (mPacer->onSessionStarted(uid, topSession->callingUid)) {
keepForClient = true;
// DO NOT break here, because book-keeping still needs to happen
// for the other uids.
diff --git a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
index 9e7fa95..ef9c4f8 100644
--- a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -339,19 +339,37 @@
EXPECT_EQ(mTranscoder.use_count(), 2);
}
- void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess,
- bool pauseLastSuccessSession = false) {
+ void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess) {
testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {},
- pauseLastSuccessSession);
+ false /*pauseLastSuccessSession*/, true /*useRealCallingUid*/);
+ }
+
+ void testPacerHelperWithPause(int numSubmits, int sessionDurationMs, int expectedSuccess) {
+ testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {},
+ true /*pauseLastSuccessSession*/, true /*useRealCallingUid*/);
+ }
+
+ void testPacerHelperWithMultipleUids(int numSubmits, int sessionDurationMs, int expectedSuccess,
+ const std::shared_ptr<TestClientCallback>& client,
+ const std::vector<int>& additionalClientUids) {
+ testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, client,
+ additionalClientUids, false /*pauseLastSuccessSession*/,
+ true /*useRealCallingUid*/);
+ }
+
+ void testPacerHelperWithSelfUid(int numSubmits, int sessionDurationMs, int expectedSuccess) {
+ testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {},
+ false /*pauseLastSuccessSession*/, false /*useRealCallingUid*/);
}
void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess,
const std::shared_ptr<TestClientCallback>& client,
- const std::vector<int>& additionalClientUids,
- bool pauseLastSuccessSession) {
+ const std::vector<int>& additionalClientUids, bool pauseLastSuccessSession,
+ bool useRealCallingUid) {
+ uid_t callingUid = useRealCallingUid ? ::getuid() : client->clientUid();
for (int i = 0; i < numSubmits; i++) {
- mController->submit(client->clientId(), SESSION(i), client->clientUid(),
- client->clientUid(), mRealtimeRequest, client);
+ mController->submit(client->clientId(), SESSION(i), callingUid, client->clientUid(),
+ mRealtimeRequest, client);
for (int additionalUid : additionalClientUids) {
mController->addClientUid(client->clientId(), SESSION(i), additionalUid);
}
@@ -1294,8 +1312,7 @@
TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) {
ALOGD("TestTranscoderPacerDuringPause");
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
- true /*pauseLastSuccessSession*/);
+ testPacerHelperWithPause(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/);
}
/*
@@ -1305,17 +1322,26 @@
TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerMultipleUids) {
ALOGD("TestTranscoderPacerMultipleUids");
// First, run mClientCallback0 to the point of no quota.
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
- mClientCallback0, {}, false /*pauseLastSuccessSession*/);
+ testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 10 /*expectedSuccess*/, mClientCallback0, {});
// Make UID(0) block on Client1's sessions too, Client1's quota should not be affected.
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
- mClientCallback1, {UID(0)}, false /*pauseLastSuccessSession*/);
+ testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 10 /*expectedSuccess*/, mClientCallback1, {UID(0)});
// Make UID(10) block on Client2's sessions. We expect to see 11 succeeds (instead of 10),
// because the addClientUid() is called after the submit, and first session is already
// started by the time UID(10) is added. UID(10) allowed us to run the 11th session,
// after that both UID(10) and UID(2) are out of quota.
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 11 /*expectedSuccess*/,
- mClientCallback2, {UID(10)}, false /*pauseLastSuccessSession*/);
+ testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 11 /*expectedSuccess*/, mClientCallback2, {UID(10)});
+}
+
+/*
+ * Use same uid for clientUid and callingUid, should not be limited by quota.
+ */
+TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerSelfUid) {
+ ALOGD("TestTranscoderPacerSelfUid");
+ testPacerHelperWithSelfUid(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 12 /*expectedSuccess*/);
}
} // namespace android
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 04a9b17..b381033 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1678,7 +1678,7 @@
if (msg->findString("mime", &mime)) {
meta->setCString(kKeyMIMEType, mime.c_str());
} else {
- ALOGI("did not find mime type");
+ ALOGV("did not find mime type");
return BAD_VALUE;
}
@@ -1728,7 +1728,7 @@
meta->setInt32(kKeyWidth, width);
meta->setInt32(kKeyHeight, height);
} else {
- ALOGI("did not find width and/or height");
+ ALOGV("did not find width and/or height");
return BAD_VALUE;
}
@@ -1817,7 +1817,7 @@
int32_t numChannels, sampleRate;
if (!msg->findInt32("channel-count", &numChannels) ||
!msg->findInt32("sample-rate", &sampleRate)) {
- ALOGI("did not find channel-count and/or sample-rate");
+ ALOGV("did not find channel-count and/or sample-rate");
return BAD_VALUE;
}
meta->setInt32(kKeyChannelCount, numChannels);
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 784e802..30d0ae6 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -146,6 +146,10 @@
int WriteOpusHeader(const OpusHeader &header, int input_sample_rate,
uint8_t* output, size_t output_size) {
// See https://wiki.xiph.org/OggOpus#ID_Header.
+ if (header.channels < 1 || header.channels > kMaxChannels) {
+ ALOGE("Invalid channel count: %d", header.channels);
+ return -1;
+ }
const size_t total_size = kOpusHeaderStreamMapOffset + header.channels;
if (output_size < total_size) {
ALOGE("Output buffer too small for header.");
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 1a5609a..6371769 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -684,6 +684,7 @@
constexpr char FEATURE_AdaptivePlayback[] = "adaptive-playback";
constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
constexpr char FEATURE_PartialFrame[] = "partial-frame";
+constexpr char FEATURE_QpBounds[] = "qp-bounds";
constexpr char FEATURE_SecurePlayback[] = "secure-playback";
constexpr char FEATURE_TunneledPlayback[] = "tunneled-playback";
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 52dc0cf..9e48c1f 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -46,6 +46,7 @@
"libbinder",
"libcutils",
"liblog",
+ "libpermission",
"libutils",
"libhidlbase",
"android.hardware.graphics.bufferqueue@1.0",
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 562c213..84ed656 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -253,6 +253,18 @@
// Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
};
+// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
+struct FreeDelete {
+ // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
+ void operator()(const void* ptr) const {
+ free(const_cast<void*>(ptr));
+ }
+};
+
+// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
+template <typename T>
+using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
+
template <class T>
constexpr void (*xmlDeleter)(T* t);
template <>
@@ -608,7 +620,7 @@
}
// Tokenize and Convert Sources name to port pointer
PolicyAudioPortVector sources;
- std::unique_ptr<char[]> sourcesLiteral{strndup(
+ UniqueCPtr<char> sourcesLiteral{strndup(
sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
char *devTag = strtok(sourcesLiteral.get(), ",");
while (devTag != NULL) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index dd44c54..ad359ec 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2229,7 +2229,8 @@
// Prevent from storing invalid requested device id in clients
requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
device = mEngine->getInputDeviceForAttributes(attributes, uid, &policyMix);
- ALOGV("%s found device type is 0x%X", __FUNCTION__, device->type());
+ ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
+ __FUNCTION__, device->type());
}
if (device == nullptr) {
ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 32c0267..07c889b 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -114,6 +114,7 @@
"libutils",
"libbinder",
"libactivitymanager_aidl",
+ "libpermission",
"libcutils",
"libmedia",
"libmediautils",
@@ -163,6 +164,7 @@
export_shared_lib_headers: [
"libbinder",
"libactivitymanager_aidl",
+ "libpermission",
"libcamera_client",
"libfmq",
"libsensorprivacy",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c6172f1..b0f386d 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -146,6 +146,7 @@
void CameraService::onFirstRef()
{
+
ALOGI("CameraService process starting");
BnCameraService::onFirstRef();
@@ -752,6 +753,10 @@
return Status::ok();
}
+void CameraService::clearCachedVariables() {
+ BasicClient::BasicClient::sCameraService = nullptr;
+}
+
int CameraService::getDeviceVersion(const String8& cameraId, int* facing, int* orientation) {
ATRACE_CALL();
@@ -2154,10 +2159,15 @@
return addListenerHelper(listener, cameraStatuses);
}
+binder::Status CameraService::addListenerTest(const sp<hardware::ICameraServiceListener>& listener,
+ std::vector<hardware::CameraStatus>* cameraStatuses) {
+ return addListenerHelper(listener, cameraStatuses, false, true);
+}
+
Status CameraService::addListenerHelper(const sp<ICameraServiceListener>& listener,
/*out*/
std::vector<hardware::CameraStatus> *cameraStatuses,
- bool isVendorListener) {
+ bool isVendorListener, bool isProcessLocalTest) {
ATRACE_CALL();
@@ -2188,7 +2198,7 @@
sp<ServiceListener> serviceListener =
new ServiceListener(this, listener, clientUid, clientPid, isVendorListener,
openCloseCallbackAllowed);
- auto ret = serviceListener->initialize();
+ auto ret = serviceListener->initialize(isProcessLocalTest);
if (ret != NO_ERROR) {
String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
strerror(-ret), ret);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d745950..2b4f9a2 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -190,7 +190,8 @@
binder::Status addListenerHelper(const sp<hardware::ICameraServiceListener>& listener,
/*out*/
- std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false);
+ std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false,
+ bool isProcessLocalTest = false);
// Monitored UIDs availability notification
void notifyMonitoredUids();
@@ -219,6 +220,19 @@
int* orientation = nullptr);
/////////////////////////////////////////////////////////////////////
+ // Methods to be used in CameraService class tests only
+ //
+ // CameraService class test method only - clear static variables in the
+ // cameraserver process, which otherwise might affect multiple test runs.
+ void clearCachedVariables();
+
+ // Add test listener, linkToDeath won't be called since this is for process
+ // local testing.
+ binder::Status addListenerTest(const sp<hardware::ICameraServiceListener>& listener,
+ /*out*/
+ std::vector<hardware::CameraStatus>* cameraStatuses);
+
+ /////////////////////////////////////////////////////////////////////
// Shared utilities
static binder::Status filterGetInfoErrorCode(status_t err);
@@ -226,6 +240,7 @@
// CameraClient functionality
class BasicClient : public virtual RefBase {
+ friend class CameraService;
public:
virtual status_t initialize(sp<CameraProviderManager> manager,
const String8& monitorTags) = 0;
@@ -940,7 +955,10 @@
mIsVendorListener(isVendorClient),
mOpenCloseCallbackAllowed(openCloseCallbackAllowed) { }
- status_t initialize() {
+ status_t initialize(bool isProcessLocalTest) {
+ if (isProcessLocalTest) {
+ return OK;
+ }
return IInterface::asBinder(mListener)->linkToDeath(this);
}
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index c7d7c4b..3d74f0b 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -44,6 +44,7 @@
"libcutils",
"libcameraservice",
"libcamera_client",
+ "liblog",
"libui",
"libgui",
"android.hardware.camera.common@1.0",
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 54550a5..985b2f8 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -18,8 +18,18 @@
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
+#define LOG_TAG "CameraServiceFuzzer"
+//#define LOG_NDEBUG 0
+
#include <CameraService.h>
+#include <device3/Camera3StreamInterface.h>
+#include <android/hardware/BnCameraServiceListener.h>
+#include <android/hardware/camera2/BnCameraDeviceCallbacks.h>
#include <android/hardware/ICameraServiceListener.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/android_filesystem_config.h>
@@ -30,6 +40,7 @@
using namespace std;
const int32_t kPreviewThreshold = 8;
+const int32_t kNumRequestsTested = 8;
const nsecs_t kPreviewTimeout = 5000000000; // .5 [s.]
const nsecs_t kEventTimeout = 10000000000; // 1 [s.]
const size_t kMaxNumLines = USHRT_MAX;
@@ -39,6 +50,23 @@
hardware::ICameraService::CAMERA_TYPE_ALL};
const int kCameraApiVersion[] = {android::CameraService::API_VERSION_1,
android::CameraService::API_VERSION_2};
+const uint8_t kSensorPixelModes[] = {ANDROID_SENSOR_PIXEL_MODE_DEFAULT,
+ ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION};
+const int32_t kRequestTemplates[] = {
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_PREVIEW,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_STILL_CAPTURE,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_RECORD,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_VIDEO_SNAPSHOT,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_MANUAL,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_ZERO_SHUTTER_LAG
+};
+
+const int32_t kRotations[] = {
+ camera3::CAMERA_STREAM_ROTATION_0,
+ camera3::CAMERA_STREAM_ROTATION_90,
+ camera3::CAMERA_STREAM_ROTATION_270
+};
+
const int kLayerMetadata[] = {
0x00100000 /*GRALLOC_USAGE_RENDERSCRIPT*/, 0x00000003 /*GRALLOC_USAGE_SW_READ_OFTEN*/,
0x00000100 /*GRALLOC_USAGE_HW_TEXTURE*/, 0x00000800 /*GRALLOC_USAGE_HW_COMPOSER*/,
@@ -69,15 +97,15 @@
class CameraFuzzer : public ::android::hardware::BnCameraClient {
public:
- CameraFuzzer() = default;
+ CameraFuzzer(sp<CameraService> cs, std::shared_ptr<FuzzedDataProvider> fp) :
+ mCameraService(cs), mFuzzedDataProvider(fp) {};
~CameraFuzzer() { deInit(); }
- bool init();
- void process(const uint8_t *data, size_t size);
+ void process();
void deInit();
private:
- FuzzedDataProvider *mFuzzedDataProvider = nullptr;
sp<CameraService> mCameraService = nullptr;
+ std::shared_ptr<FuzzedDataProvider> mFuzzedDataProvider = nullptr;
sp<SurfaceComposerClient> mComposerClient = nullptr;
int32_t mNumCameras = 0;
size_t mPreviewBufferCount = 0;
@@ -167,19 +195,7 @@
return rc;
}
-bool CameraFuzzer::init() {
- setuid(AID_MEDIA);
- mCameraService = new CameraService();
- if (mCameraService) {
- return true;
- }
- return false;
-}
-
void CameraFuzzer::deInit() {
- if (mCameraService) {
- mCameraService = nullptr;
- }
if (mComposerClient) {
mComposerClient->dispose();
}
@@ -298,12 +314,12 @@
for (int32_t cameraId = 0; cameraId < mNumCameras; ++cameraId) {
getCameraInformation(cameraId);
- const String16 opPackageName("com.fuzzer.poc");
::android::binder::Status rc;
sp<ICamera> cameraDevice;
- rc = mCameraService->connect(this, cameraId, opPackageName, AID_MEDIA, AID_ROOT,
- &cameraDevice);
+ rc = mCameraService->connect(this, cameraId, String16(),
+ android::CameraService::USE_CALLING_UID, android::CameraService::USE_CALLING_PID,
+ &cameraDevice);
if (!rc.isOk()) {
// camera not connected
return;
@@ -405,8 +421,7 @@
}
}
-void CameraFuzzer::process(const uint8_t *data, size_t size) {
- mFuzzedDataProvider = new FuzzedDataProvider(data, size);
+void CameraFuzzer::process() {
getNumCameras();
invokeCameraSound();
if (mNumCameras > 0) {
@@ -415,19 +430,169 @@
invokeDump();
invokeShellCommand();
invokeNotifyCalls();
- delete mFuzzedDataProvider;
+}
+
+class TestCameraServiceListener : public hardware::BnCameraServiceListener {
+public:
+ virtual ~TestCameraServiceListener() {};
+
+ virtual binder::Status onStatusChanged(int32_t , const String16&) {
+ return binder::Status::ok();
+ };
+
+ virtual binder::Status onPhysicalCameraStatusChanged(int32_t /*status*/,
+ const String16& /*cameraId*/, const String16& /*physicalCameraId*/) {
+ // No op
+ return binder::Status::ok();
+ };
+
+ virtual binder::Status onTorchStatusChanged(int32_t /*status*/, const String16& /*cameraId*/) {
+ return binder::Status::ok();
+ };
+
+ virtual binder::Status onCameraAccessPrioritiesChanged() {
+ // No op
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCameraOpened(const String16& /*cameraId*/,
+ const String16& /*clientPackageName*/) {
+ // No op
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCameraClosed(const String16& /*cameraId*/) {
+ // No op
+ return binder::Status::ok();
+ }
+};
+
+class TestCameraDeviceCallbacks : public hardware::camera2::BnCameraDeviceCallbacks {
+public:
+ TestCameraDeviceCallbacks() {}
+
+ virtual ~TestCameraDeviceCallbacks() {}
+
+ virtual binder::Status onDeviceError(int /*errorCode*/,
+ const CaptureResultExtras& /*resultExtras*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onDeviceIdle() {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCaptureStarted(const CaptureResultExtras& /*resultExtras*/,
+ int64_t /*timestamp*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+ const CaptureResultExtras& /*resultExtras*/,
+ const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onPrepared(int /*streamId*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onRepeatingRequestError(
+ int64_t /*lastFrameNumber*/, int32_t /*stoppedSequenceId*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onRequestQueueEmpty() {
+ return binder::Status::ok();
+ }
+};
+
+class Camera2Fuzzer {
+ public:
+ Camera2Fuzzer(sp<CameraService> cs, std::shared_ptr<FuzzedDataProvider> fp) :
+ mCameraService(cs), mFuzzedDataProvider(fp) { };
+ ~Camera2Fuzzer() {}
+ void process();
+ private:
+ sp<CameraService> mCameraService = nullptr;
+ std::shared_ptr<FuzzedDataProvider> mFuzzedDataProvider = nullptr;
+};
+
+void Camera2Fuzzer::process() {
+ sp<TestCameraServiceListener> listener = new TestCameraServiceListener();
+ std::vector<hardware::CameraStatus> statuses;
+ mCameraService->addListenerTest(listener, &statuses);
+ for (auto s : statuses) {
+ sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
+ sp<hardware::camera2::ICameraDeviceUser> device;
+ mCameraService->connectDevice(callbacks, String16(s.cameraId), String16(), {},
+ android::CameraService::USE_CALLING_UID, &device);
+ if (device == nullptr) {
+ continue;
+ }
+ device->beginConfigure();
+ sp<IGraphicBufferProducer> gbProducer;
+ sp<IGraphicBufferConsumer> gbConsumer;
+ BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
+ sp<BufferItemConsumer> opaqueConsumer = new BufferItemConsumer(gbConsumer,
+ GRALLOC_USAGE_SW_READ_NEVER, /*maxImages*/8, /*controlledByApp*/true);
+ opaqueConsumer->setName(String8("Roger"));
+
+ // Set to VGA dimension for default, as that is guaranteed to be present
+ gbConsumer->setDefaultBufferSize(640, 480);
+ gbConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+
+ sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false));
+
+ String16 noPhysicalId;
+ size_t rotations = sizeof(kRotations) / sizeof(int32_t) - 1;
+ OutputConfiguration output(gbProducer,
+ kRotations[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, rotations)],
+ noPhysicalId);
+ int streamId;
+ device->createStream(output, &streamId);
+ CameraMetadata sessionParams;
+ std::vector<int> offlineStreamIds;
+ device->endConfigure(/*isConstrainedHighSpeed*/ mFuzzedDataProvider->ConsumeBool(),
+ sessionParams, ns2ms(systemTime()), &offlineStreamIds);
+
+ CameraMetadata requestTemplate;
+ size_t requestTemplatesSize = sizeof(kRequestTemplates) /sizeof(int32_t) - 1;
+ device->createDefaultRequest(kRequestTemplates[
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, requestTemplatesSize)],
+ /*out*/&requestTemplate);
+ hardware::camera2::CaptureRequest request;
+ request.mSurfaceList.add(surface);
+ request.mIsReprocess = false;
+ hardware::camera2::utils::SubmitInfo info;
+ for (int i = 0; i < kNumRequestsTested; i++) {
+ uint8_t sensorPixelMode =
+ kSensorPixelModes[mFuzzedDataProvider->ConsumeBool() ? 1 : 0];
+ requestTemplate.update(ANDROID_SENSOR_PIXEL_MODE, &sensorPixelMode, 1);
+ request.mPhysicalCameraSettings.clear();
+ request.mPhysicalCameraSettings.push_back({s.cameraId.string(), requestTemplate});
+ device->submitRequest(request, /*streaming*/false, /*out*/&info);
+ ALOGV("%s : camera id %s submit request id %d",__FUNCTION__, s.cameraId.string(),
+ info.mRequestId);
+ }
+ device->disconnect();
+ }
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 1) {
return 0;
}
- sp<CameraFuzzer> camerafuzzer = new CameraFuzzer();
+ setuid(AID_CAMERASERVER);
+ std::shared_ptr<FuzzedDataProvider> fp = std::make_shared<FuzzedDataProvider>(data, size);
+ sp<CameraService> cs = new CameraService();
+ cs->clearCachedVariables();
+ sp<CameraFuzzer> camerafuzzer = new CameraFuzzer(cs, fp);
if (!camerafuzzer) {
return 0;
}
- if (camerafuzzer->init()) {
- camerafuzzer->process(data, size);
- }
+ camerafuzzer->process();
+ Camera2Fuzzer camera2fuzzer(cs, fp);
+ camera2fuzzer.process();
return 0;
}
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 2b797b8..dbc68b2 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -245,7 +245,7 @@
});
}));
- // Handle legacy aaudio stream statistics
+ // Handle legacy aaudio playback stream statistics
mActions.addAction(
AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
@@ -254,6 +254,15 @@
mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
}));
+ // Handle legacy aaudio capture stream statistics
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
+ mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
+ }));
+
// Handle mmap aaudio stream statistics
mActions.addAction(
AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
@@ -949,7 +958,8 @@
key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
int64_t totalFramesTransferred = -1;
- // TODO: log and get total frames transferred
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
std::string perfModeRequestedStr;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
@@ -957,8 +967,11 @@
const auto perfModeRequested =
types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
- int32_t perfModeActual = 0;
- // TODO: log and get actual performance mode
+ std::string perfModeActualStr;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
+ const auto perfModeActual =
+ types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
std::string sharingModeStr;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
@@ -972,8 +985,10 @@
std::string serializedDeviceTypes;
// TODO: only routed device id is logged, but no device type
- int32_t formatApp = 0;
- // TODO: log format from app
+ std::string formatAppStr;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_ENCODINGREQUESTED, &formatAppStr);
+ const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
std::string formatDeviceStr;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
@@ -981,7 +996,8 @@
const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
std::string logSessionId;
- // TODO: log logSessionId
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
int32_t sampleRate = 0;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
@@ -1001,11 +1017,11 @@
<< " channel_count:" << channelCount
<< " total_frames_transferred:" << totalFramesTransferred
<< " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
- << " perf_mode_actual:" << perfModeActual
+ << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
<< " sharing:" << sharingMode << "(" << sharingModeStr << ")"
<< " xrun_count:" << xrunCount
<< " device_type:" << serializedDeviceTypes
- << " format_app:" << formatApp
+ << " format_app:" << formatApp << "(" << formatAppStr << ")"
<< " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
<< " log_session_id: " << logSessionId
<< " sample_rate: " << sampleRate
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 5e672ee..1d64878 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -545,12 +545,13 @@
return AStatsManager_PULL_SKIP;
}
std::lock_guard _l(mLock);
+ bool dumped = false;
for (auto &item : mPullableItems[key]) {
if (const auto sitem = item.lock()) {
- dump2Statsd(sitem, data, mStatsdLog);
+ dumped |= dump2Statsd(sitem, data, mStatsdLog);
}
}
mPullableItems[key].clear();
- return AStatsManager_PULL_SUCCESS;
+ return dumped ? AStatsManager_PULL_SUCCESS : AStatsManager_PULL_SKIP;
}
} // namespace android
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index 8a2158f..381f441 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -33,7 +33,7 @@
#include "cleaner.h"
#include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -51,7 +51,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::CodecData metrics_proto;
+ ::android::stats::mediametrics_message::CodecData metrics_proto;
// flesh out the protobuf we'll hand off with our data
//
diff --git a/services/mediametrics/statsd_drm.cpp b/services/mediametrics/statsd_drm.cpp
index 27fd089..73b8872 100644
--- a/services/mediametrics/statsd_drm.cpp
+++ b/services/mediametrics/statsd_drm.cpp
@@ -188,6 +188,11 @@
(void) item->getString("plugin_metrics", &plugin_metrics);
const auto plugin_raw(base64DecodeNoPad(plugin_metrics));
+ if (serialized_metrics.size() == 0 && plugin_metrics.size() == 0) {
+ ALOGD("statsd_mediadrm_puller skipping empty entry");
+ return false;
+ }
+
std::string vendor;
(void) item->getString("vendor", &vendor);
std::string description;
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index faea58f..13dd3d3 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -38,6 +38,10 @@
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
+AAudioServiceEndpoint::~AAudioServiceEndpoint() {
+ ALOGD("%s() called", __func__);
+}
+
std::string AAudioServiceEndpoint::dump() const NO_THREAD_SAFETY_ANALYSIS {
std::stringstream result;
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 72090c2..a7f63d3 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -43,7 +43,7 @@
, public AAudioStreamParameters {
public:
- virtual ~AAudioServiceEndpoint() = default;
+ virtual ~AAudioServiceEndpoint();
virtual std::string dump() const;
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 556710d..7294a58 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -51,8 +51,6 @@
: mMmapStream(nullptr)
, mAAudioService(audioService) {}
-AAudioServiceEndpointMMAP::~AAudioServiceEndpointMMAP() {}
-
std::string AAudioServiceEndpointMMAP::dump() const {
std::stringstream result;
@@ -357,7 +355,10 @@
// This is called by AudioFlinger when it wants to destroy a stream.
void AAudioServiceEndpointMMAP::onTearDown(audio_port_handle_t portHandle) {
ALOGD("%s(portHandle = %d) called", __func__, portHandle);
- std::thread asyncTask(&AAudioServiceEndpointMMAP::handleTearDownAsync, this, portHandle);
+ android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
+ std::thread asyncTask([holdEndpoint, portHandle]() {
+ holdEndpoint->handleTearDownAsync(portHandle);
+ });
asyncTask.detach();
}
@@ -378,9 +379,11 @@
ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
if (getDeviceId() != deviceId) {
if (getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
- std::thread asyncTask([this, deviceId]() {
- disconnectRegisteredStreams();
- setDeviceId(deviceId);
+ android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
+ std::thread asyncTask([holdEndpoint, deviceId]() {
+ ALOGD("onRoutingChanged() asyncTask launched");
+ holdEndpoint->disconnectRegisteredStreams();
+ holdEndpoint->setDeviceId(deviceId);
});
asyncTask.detach();
} else {
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index 24b161d..5a53885 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -44,7 +44,7 @@
public:
explicit AAudioServiceEndpointMMAP(android::AAudioService &audioService);
- virtual ~AAudioServiceEndpointMMAP();
+ virtual ~AAudioServiceEndpointMMAP() = default;
std::string dump() const override;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 8638f36..dbacd75 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -67,8 +67,7 @@
// If the stream is deleted when OPEN or in use then audio resources will leak.
// This would indicate an internal error. So we want to find this ASAP.
LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
- || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
- || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+ || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED),
"service stream %p still open, state = %d",
this, getState());
}
@@ -229,7 +228,7 @@
aaudio_result_t result = AAUDIO_OK;
if (auto state = getState();
- state == AAUDIO_STREAM_STATE_CLOSED || state == AAUDIO_STREAM_STATE_DISCONNECTED) {
+ state == AAUDIO_STREAM_STATE_CLOSED || isDisconnected_l()) {
ALOGW("%s() already CLOSED, returns INVALID_STATE, handle = %d",
__func__, getHandle());
return AAUDIO_ERROR_INVALID_STATE;
@@ -261,8 +260,14 @@
sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
setState(AAUDIO_STREAM_STATE_STARTED);
mThreadEnabled.store(true);
+ // Make sure this object does not get deleted before the run() method
+ // can protect it by making a strong pointer.
+ incStrong(nullptr); // See run() method.
result = mTimestampThread.start(this);
- if (result != AAUDIO_OK) goto error;
+ if (result != AAUDIO_OK) {
+ decStrong(nullptr); // run() can't do it so we have to do it here.
+ goto error;
+ }
return result;
@@ -336,7 +341,12 @@
setState(AAUDIO_STREAM_STATE_STOPPING);
+ // Temporarily unlock because we are joining the timestamp thread and it may try
+ // to acquire mLock.
+ mLock.unlock();
result = stopTimestampThread();
+ mLock.lock();
+
if (result != AAUDIO_OK) {
disconnect_l();
return result;
@@ -396,7 +406,12 @@
__attribute__((no_sanitize("integer")))
void AAudioServiceStreamBase::run() {
ALOGD("%s() %s entering >>>>>>>>>>>>>> TIMESTAMPS", __func__, getTypeText());
+ // Hold onto the ref counted stream until the end.
+ android::sp<AAudioServiceStreamBase> holdStream(this);
TimestampScheduler timestampScheduler;
+ // Balance the incStrong from when the thread was launched.
+ holdStream->decStrong(nullptr);
+
timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
timestampScheduler.start(AudioClock::getNanoseconds());
int64_t nextTime = timestampScheduler.nextAbsoluteTime();
@@ -432,8 +447,7 @@
}
void AAudioServiceStreamBase::disconnect_l() {
- if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED
- && getState() != AAUDIO_STREAM_STATE_CLOSED) {
+ if (!isDisconnected_l() && getState() != AAUDIO_STREAM_STATE_CLOSED) {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT)
@@ -441,7 +455,7 @@
.record();
sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
- setState(AAUDIO_STREAM_STATE_DISCONNECTED);
+ setDisconnected_l(true);
}
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 8e5c8ef..c42df0f 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -265,6 +265,13 @@
aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+ bool isDisconnected_l() const REQUIRES(mLock) {
+ return mDisconnected;
+ }
+ void setDisconnected_l(bool flag) REQUIRES(mLock) {
+ mDisconnected = flag;
+ }
+
pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
std::mutex mUpMessageQueueLock;
@@ -322,6 +329,8 @@
// for example a full message queue. Note that this atomic is unrelated to mCloseNeeded.
std::atomic<bool> mSuspended{false};
+ bool mDisconnected GUARDED_BY(mLock) {false};
+
protected:
// Locking order is important.
// Acquire mLock before acquiring AAudioServiceEndpoint::mLockStreams
diff --git a/services/tuner/TunerDescrambler.cpp b/services/tuner/TunerDescrambler.cpp
index bdf826c..b7ae167 100644
--- a/services/tuner/TunerDescrambler.cpp
+++ b/services/tuner/TunerDescrambler.cpp
@@ -111,11 +111,11 @@
DemuxPid hidlPid;
switch (pid.getTag()) {
case TunerDemuxPid::tPid: {
- hidlPid.tPid((uint16_t)pid.tPid);
+ hidlPid.tPid((uint16_t)pid.get<TunerDemuxPid::tPid>());
break;
}
case TunerDemuxPid::mmtpPid: {
- hidlPid.mmtpPid((uint16_t)pid.mmtpPid);
+ hidlPid.mmtpPid((uint16_t)pid.get<TunerDemuxPid::mmtpPid>());
break;
}
}
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index e957b83..039fd31 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -685,7 +685,7 @@
DemuxFilterMediaEvent mediaEvent = e.media();
TunerFilterMediaEvent tunerMedia;
- tunerMedia.streamId = static_cast<int>(mediaEvent.streamId);
+ tunerMedia.streamId = static_cast<char16_t>(mediaEvent.streamId);
tunerMedia.isPtsPresent = mediaEvent.isPtsPresent;
tunerMedia.pts = static_cast<long>(mediaEvent.pts);
tunerMedia.dataLength = static_cast<int>(mediaEvent.dataLength);
@@ -732,10 +732,10 @@
DemuxFilterSectionEvent sectionEvent = e.section();
TunerFilterSectionEvent tunerSection;
- tunerSection.tableId = static_cast<char>(sectionEvent.tableId);
- tunerSection.version = static_cast<char>(sectionEvent.version);
- tunerSection.sectionNum = static_cast<char>(sectionEvent.sectionNum);
- tunerSection.dataLength = static_cast<char>(sectionEvent.dataLength);
+ tunerSection.tableId = static_cast<char16_t>(sectionEvent.tableId);
+ tunerSection.version = static_cast<char16_t>(sectionEvent.version);
+ tunerSection.sectionNum = static_cast<char16_t>(sectionEvent.sectionNum);
+ tunerSection.dataLength = static_cast<char16_t>(sectionEvent.dataLength);
TunerFilterEvent tunerEvent;
tunerEvent.set<TunerFilterEvent::section>(move(tunerSection));
@@ -749,8 +749,8 @@
DemuxFilterPesEvent pesEvent = e.pes();
TunerFilterPesEvent tunerPes;
- tunerPes.streamId = static_cast<char>(pesEvent.streamId);
- tunerPes.dataLength = static_cast<int>(pesEvent.dataLength);
+ tunerPes.streamId = static_cast<char16_t>(pesEvent.streamId);
+ tunerPes.dataLength = static_cast<char16_t>(pesEvent.dataLength);
tunerPes.mpuSequenceNumber = static_cast<int>(pesEvent.mpuSequenceNumber);
TunerFilterEvent tunerEvent;
@@ -777,9 +777,9 @@
}
if (tsRecordEvent.pid.getDiscriminator() == DemuxPid::hidl_discriminator::tPid) {
- tunerTsRecord.pid = static_cast<char>(tsRecordEvent.pid.tPid());
+ tunerTsRecord.pid = static_cast<char16_t>(tsRecordEvent.pid.tPid());
} else {
- tunerTsRecord.pid = static_cast<char>(Constant::INVALID_TS_PID);
+ tunerTsRecord.pid = static_cast<char16_t>(Constant::INVALID_TS_PID);
}
tunerTsRecord.scIndexMask = scIndexMask;
@@ -839,7 +839,7 @@
tunerDownload.itemFragmentIndex = static_cast<int>(downloadEvent.itemFragmentIndex);
tunerDownload.mpuSequenceNumber = static_cast<int>(downloadEvent.mpuSequenceNumber);
tunerDownload.lastItemFragmentIndex = static_cast<int>(downloadEvent.lastItemFragmentIndex);
- tunerDownload.dataLength = static_cast<char>(downloadEvent.dataLength);
+ tunerDownload.dataLength = static_cast<char16_t>(downloadEvent.dataLength);
TunerFilterEvent tunerEvent;
tunerEvent.set<TunerFilterEvent::download>(move(tunerDownload));
@@ -853,7 +853,7 @@
DemuxFilterIpPayloadEvent ipPayloadEvent = e.ipPayload();
TunerFilterIpPayloadEvent tunerIpPayload;
- tunerIpPayload.dataLength = static_cast<char>(ipPayloadEvent.dataLength);
+ tunerIpPayload.dataLength = static_cast<char16_t>(ipPayloadEvent.dataLength);
TunerFilterEvent tunerEvent;
tunerEvent.set<TunerFilterEvent::ipPayload>(move(tunerIpPayload));
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl
index 51c6378..8b238b6 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl
@@ -22,7 +22,7 @@
* {@hide}
*/
union TunerDemuxPid {
- int tPid;
+ char tPid;
- int mmtpPid;
+ char mmtpPid;
}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl
index 5842c0d..c3dbce9 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl
@@ -25,7 +25,7 @@
* {@hide}
*/
parcelable TunerFilterMediaEvent {
- int streamId;
+ char streamId;
/**
* true if PTS is present in PES header.
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl
index f7ee286..dc1ecc6 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl
@@ -27,7 +27,7 @@
/**
* Data size in bytes of PES data
*/
- int dataLength;
+ char dataLength;
/**
* MPU sequence number of filtered data
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl
index 0923868..9a11fd5 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl
@@ -27,7 +27,7 @@
*/
int frequency;
- int streamId;
+ char streamId;
int streamIdType;
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl
index 2ae9092..dff9f4a 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl
@@ -27,7 +27,7 @@
*/
int frequency;
- int streamId;
+ char streamId;
int streamIdType;