Merge "TimeCheck: Track audio Hidl hwbinder calls" into tm-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index b9b9bde..570ca01 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -56,6 +56,7 @@
prebuilts: [
"code_coverage.policy",
"com.android.media-mediatranscoding.rc",
+ "com.android.media-mediatranscoding.32rc",
"crash_dump.policy",
"mediaextractor.policy",
"media-linker-config",
@@ -177,6 +178,7 @@
],
prebuilts: [
"com.android.media.swcodec-mediaswcodec.rc",
+ "com.android.media.swcodec-mediaswcodec.32rc",
"com.android.media.swcodec-ld.config.txt",
"mediaswcodec.policy",
"code_coverage.policy",
@@ -201,17 +203,34 @@
compressible: true,
}
+// install as mediatranscoding.* and mediaswcodec.* instead of init.*
+// so we are ready for day we have more than 1 *rc file within the apex.
+
prebuilt_etc {
name: "com.android.media-mediatranscoding.rc",
src: "mediatranscoding.rc",
- filename: "init.rc",
+ filename: "mediatranscoding.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "com.android.media-mediatranscoding.32rc",
+ src: "mediatranscoding.32rc",
+ filename: "mediatranscoding.32rc",
installable: false,
}
prebuilt_etc {
name: "com.android.media.swcodec-mediaswcodec.rc",
src: "mediaswcodec.rc",
- filename: "init.rc",
+ filename: "mediaswcodec.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "com.android.media.swcodec-mediaswcodec.32rc",
+ src: "mediaswcodec.32rc",
+ filename: "mediaswcodec.32rc",
installable: false,
}
diff --git a/apex/mediaswcodec.32rc b/apex/mediaswcodec.32rc
index 79aef36..f40d172 100644
--- a/apex/mediaswcodec.32rc
+++ b/apex/mediaswcodec.32rc
@@ -1,3 +1,5 @@
+## for SDK releases >= 32
+##
service media.swcodec /apex/com.android.media.swcodec/bin/mediaswcodec
class main
user mediacodec
diff --git a/apex/mediaswcodec.rc b/apex/mediaswcodec.rc
index 0c9b8c8..46799c7 100644
--- a/apex/mediaswcodec.rc
+++ b/apex/mediaswcodec.rc
@@ -1,3 +1,6 @@
+## for SDK releases 29..31
+## where writepid has not yet been replaced by task_profiles
+##
service media.swcodec /apex/com.android.media.swcodec/bin/mediaswcodec
class main
user mediacodec
diff --git a/apex/mediatranscoding.32rc b/apex/mediatranscoding.32rc
index 5169462..edba9b9 100644
--- a/apex/mediatranscoding.32rc
+++ b/apex/mediatranscoding.32rc
@@ -1,3 +1,6 @@
+## for SDK releases >= 32
+##
+#
# media.transcoding service is defined on com.android.media apex which goes back
# to API29, but we only want it started on API31+ devices. So we declare it as
# "disabled" and start it explicitly on boot.
diff --git a/apex/mediatranscoding.rc b/apex/mediatranscoding.rc
index ae9f8ba..6e453be 100644
--- a/apex/mediatranscoding.rc
+++ b/apex/mediatranscoding.rc
@@ -1,3 +1,7 @@
+## for SDK releases 29..31
+## where writepid has not yet been replaced by task_profiles
+##
+#
# media.transcoding service is defined on com.android.media apex which goes back
# to API29, but we only want it started on API31+ devices. So we declare it as
# "disabled" and start it explicitly on boot.
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index d8d6f06..bc4053d 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -261,7 +261,7 @@
for (const ui::PlaneLayout &plane : planes) {
layout->rootPlanes++;
uint32_t lastOffsetInBits = 0;
- uint32_t rootIx = 0;
+ uint32_t rootIx = layout->numPlanes;
for (const PlaneLayoutComponent &component : plane.components) {
if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
@@ -309,7 +309,6 @@
layout->numPlanes++;
lastOffsetInBits = component.offsetInBits + component.sizeInBits;
- rootIx++;
}
}
return C2_OK;
@@ -699,17 +698,6 @@
C2PlanarLayout::PLANE_V, // rootIx
0, // offset
};
- // handle interleaved formats
- intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
- if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chroma_step) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
- layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
- } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chroma_step) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
- layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
- }
break;
}
@@ -830,17 +818,6 @@
C2PlanarLayout::PLANE_V, // rootIx
0, // offset
};
- // handle interleaved formats
- intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
- if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chroma_step) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
- layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
- } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chroma_step) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
- layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
- }
break;
}
@@ -886,6 +863,29 @@
}
mLocked = true;
+ // handle interleaved formats
+ if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) {
+ intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+ intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc;
+ if (uvOffset > 0 && uvOffset < uvColInc) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+ layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+ } else if (uvOffset < 0 && uvOffset > -uvColInc) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+ layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+ }
+ }
+
+ ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d",
+ layout->type, layout->numPlanes, layout->rootPlanes);
+ for (int i = 0; i < layout->numPlanes; ++i) {
+ const C2PlaneInfo &plane = layout->planes[i];
+ ALOGV("C2AllocationGralloc::map: plane[%d]: colInc=%d rowInc=%d rootIx=%u offset=%u",
+ i, plane.colInc, plane.rowInc, plane.rootIx, plane.offset);
+ }
+
return C2_OK;
}
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index e55bdc0..2115cc3 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -228,10 +228,10 @@
tv.tv_nsec = timeoutNs % 1000000000;
int ret = syscall(__NR_futex, &mCond, FUTEX_WAIT, waitId, &tv, NULL, 0);
- if (ret == 0 || ret == EAGAIN) {
+ if (ret == 0 || errno == EAGAIN) {
return C2_OK;
}
- if (ret == EINTR || ret == ETIMEDOUT) {
+ if (errno == EINTR || errno == ETIMEDOUT) {
return C2_TIMED_OUT;
}
return C2_BAD_VALUE;
diff --git a/media/libstagefright/timedtext/test/Android.bp b/media/libstagefright/timedtext/test/Android.bp
index 58c68ef..ae97c50 100644
--- a/media/libstagefright/timedtext/test/Android.bp
+++ b/media/libstagefright/timedtext/test/Android.bp
@@ -36,7 +36,6 @@
static_libs: [
"libstagefright_timedtext",
- "libstagefright_foundation",
],
header_libs: [
@@ -47,6 +46,7 @@
"liblog",
"libmedia",
"libbinder",
+ "libstagefright_foundation",
],
cflags: [
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e45de32..5720551 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3192,9 +3192,10 @@
}
}
}
- return mEffects.registerEffect(desc, io, session, id,
- (strategy == streamToStrategy(AUDIO_STREAM_MUSIC) ||
- strategy == PRODUCT_STRATEGY_NONE));
+ bool isMusicEffect = (session != AUDIO_SESSION_OUTPUT_STAGE)
+ && ((strategy == streamToStrategy(AUDIO_STREAM_MUSIC)
+ || strategy == PRODUCT_STRATEGY_NONE));
+ return mEffects.registerEffect(desc, io, session, id, isMusicEffect);
}
status_t AudioPolicyManager::unregisterEffect(int id)
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 69300be..1e2dccb 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -81,7 +81,6 @@
"device3/Camera3OutputUtils.cpp",
"device3/Camera3DeviceInjectionMethods.cpp",
"device3/UHRCropAndMeteringRegionMapper.cpp",
- "device3/PreviewFrameScheduler.cpp",
"device3/hidl/HidlCamera3Device.cpp",
"device3/hidl/HidlCamera3OfflineSession.cpp",
"device3/hidl/HidlCamera3OutputUtils.cpp",
@@ -112,7 +111,6 @@
],
shared_libs: [
- "libandroid",
"libbase",
"libdl",
"libexif",
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index aeffd24..55acec4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2649,7 +2649,7 @@
status_t Camera3Device::registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
- bool hasAppCallback, nsecs_t maxExpectedDuration,
+ bool hasAppCallback, nsecs_t minExpectedDuration, nsecs_t maxExpectedDuration,
const std::set<std::set<String8>>& physicalCameraIds,
bool isStillCapture, bool isZslCapture, bool rotateAndCropAuto,
const std::set<std::string>& cameraIdsWithZoom,
@@ -2659,8 +2659,9 @@
ssize_t res;
res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
- hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture,
- rotateAndCropAuto, cameraIdsWithZoom, requestTimeNs, outputSurfaces));
+ hasAppCallback, minExpectedDuration, maxExpectedDuration, physicalCameraIds,
+ isStillCapture, isZslCapture, rotateAndCropAuto, cameraIdsWithZoom, requestTimeNs,
+ outputSurfaces));
if (res < 0) return res;
if (mInFlightMap.size() == 1) {
@@ -3216,13 +3217,16 @@
return true;
}
-nsecs_t Camera3Device::RequestThread::calculateMaxExpectedDuration(const camera_metadata_t *request) {
- nsecs_t maxExpectedDuration = kDefaultExpectedDuration;
+std::pair<nsecs_t, nsecs_t> Camera3Device::RequestThread::calculateExpectedDurationRange(
+ const camera_metadata_t *request) {
+ std::pair<nsecs_t, nsecs_t> expectedRange(
+ InFlightRequest::kDefaultMinExpectedDuration,
+ InFlightRequest::kDefaultMaxExpectedDuration);
camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
find_camera_metadata_ro_entry(request,
ANDROID_CONTROL_AE_MODE,
&e);
- if (e.count == 0) return maxExpectedDuration;
+ if (e.count == 0) return expectedRange;
switch (e.data.u8[0]) {
case ANDROID_CONTROL_AE_MODE_OFF:
@@ -3230,13 +3234,15 @@
ANDROID_SENSOR_EXPOSURE_TIME,
&e);
if (e.count > 0) {
- maxExpectedDuration = e.data.i64[0];
+ expectedRange.first = e.data.i64[0];
+ expectedRange.second = expectedRange.first;
}
find_camera_metadata_ro_entry(request,
ANDROID_SENSOR_FRAME_DURATION,
&e);
if (e.count > 0) {
- maxExpectedDuration = std::max(e.data.i64[0], maxExpectedDuration);
+ expectedRange.first = std::max(e.data.i64[0], expectedRange.first);
+ expectedRange.second = expectedRange.first;
}
break;
default:
@@ -3244,12 +3250,13 @@
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
&e);
if (e.count > 1) {
- maxExpectedDuration = 1e9 / e.data.u8[0];
+ expectedRange.first = 1e9 / e.data.i32[1];
+ expectedRange.second = 1e9 / e.data.i32[0];
}
break;
}
- return maxExpectedDuration;
+ return expectedRange;
}
bool Camera3Device::RequestThread::skipHFRTargetFPSUpdate(int32_t tag,
@@ -3864,11 +3871,13 @@
isZslCapture = true;
}
}
+ auto expectedDurationRange = calculateExpectedDurationRange(settings);
res = parent->registerInFlight(halRequest->frame_number,
totalNumBuffers, captureRequest->mResultExtras,
/*hasInput*/halRequest->input_buffer != NULL,
hasCallback,
- calculateMaxExpectedDuration(settings),
+ /*min*/expectedDurationRange.first,
+ /*max*/expectedDurationRange.second,
requestedPhysicalCameras, isStillCapture, isZslCapture,
captureRequest->mRotateAndCropAuto, mPrevCameraIdsWithZoom,
(mUseHalBufManager) ? uniqueSurfaceIdMap :
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index c1ba88a..1a240c3 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -302,7 +302,6 @@
static const nsecs_t kMinWarnInflightDuration = 5000000000; // 5 s
static const size_t kInFlightWarnLimit = 30;
static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
- static const nsecs_t kDefaultExpectedDuration = 100000000; // 100 ms
static const nsecs_t kMinInflightDuration = 5000000000; // 5 s
static const nsecs_t kBaseGetBufferWait = 3000000000; // 3 sec.
// SCHED_FIFO priority for request submission thread in HFR mode
@@ -956,8 +955,9 @@
// send request in mNextRequests to HAL in a batch. Return true = sucssess
bool sendRequestsBatch();
- // Calculate the expected maximum duration for a request
- nsecs_t calculateMaxExpectedDuration(const camera_metadata_t *request);
+ // Calculate the expected (minimum, maximum) duration range for a request
+ std::pair<nsecs_t, nsecs_t> calculateExpectedDurationRange(
+ const camera_metadata_t *request);
// Check and update latest session parameters based on the current request settings.
bool updateSessionParameters(const CameraMetadata& settings);
@@ -1072,7 +1072,7 @@
status_t registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
- bool callback, nsecs_t maxExpectedDuration,
+ bool callback, nsecs_t minExpectedDuration, nsecs_t maxExpectedDuration,
const std::set<std::set<String8>>& physicalCameraIds,
bool isStillCapture, bool isZslCapture, bool rotateAndCropAuto,
const std::set<std::string>& cameraIdsWithZoom, const SurfaceMap& outputSurfaces,
@@ -1323,6 +1323,9 @@
// performance class.
bool mOverrideForPerfClass;
+ // The current minimum expected frame duration based on AE_TARGET_FPS_RANGE
+ nsecs_t mMinExpectedDuration = 0;
+
// Injection camera related methods.
class Camera3DeviceInjectionMethods : public virtual RefBase {
public:
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.h b/services/camera/libcameraservice/device3/Camera3FakeStream.h
index 48e44dc..8cecabd 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.h
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.h
@@ -100,6 +100,7 @@
virtual status_t setBatchSize(size_t batchSize) override;
+ virtual void onMinDurationChanged(nsecs_t /*duration*/) {}
protected:
/**
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index 0f7d145..a799719 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -246,6 +246,9 @@
// For client methods such as disconnect/dump
std::mutex mInterfaceLock;
+ // The current minimum expected frame duration based on AE_TARGET_FPS_RANGE
+ nsecs_t mMinExpectedDuration = 0;
+
// SetErrorInterface
void setErrorState(const char *fmt, ...) override;
void setErrorStateLocked(const char *fmt, ...) override;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 0f61065..b822178 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -376,32 +376,26 @@
dumpImageToDisk(timestamp, anwBuffer, anwReleaseFence);
}
- nsecs_t t = mPreviewFrameScheduler != nullptr ? readoutTimestamp : timestamp;
- t -= mTimestampOffset;
- if (mPreviewFrameScheduler != nullptr) {
- res = mPreviewFrameScheduler->queuePreviewBuffer(t, transform,
- anwBuffer, anwReleaseFence);
- if (res != OK) {
- ALOGE("%s: Stream %d: Error queuing buffer to preview buffer scheduler: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
- }
- } else {
- setTransform(transform, true/*mayChangeMirror*/);
- res = native_window_set_buffers_timestamp(mConsumer.get(), t);
- if (res != OK) {
- ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
- }
+ nsecs_t captureTime = (mSyncToDisplay ? readoutTimestamp : timestamp) - mTimestampOffset;
+ nsecs_t presentTime = mSyncToDisplay ?
+ syncTimestampToDisplayLocked(captureTime) : captureTime;
+ mLastCaptureTime = captureTime;
+ mLastPresentTime = presentTime;
- queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
+ setTransform(transform, true/*mayChangeMirror*/);
+ res = native_window_set_buffers_timestamp(mConsumer.get(), presentTime);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
- res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
- if (shouldLogError(res, state)) {
- ALOGE("%s: Stream %d: Error queueing buffer to native window:"
- " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
- }
+ queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
+
+ res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
+ if (shouldLogError(res, state)) {
+ ALOGE("%s: Stream %d: Error queueing buffer to native window:"
+ " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
}
}
mLock.lock();
@@ -476,7 +470,7 @@
return res;
}
- if ((res = configureConsumerQueueLocked(true /*allowPreviewScheduler*/)) != OK) {
+ if ((res = configureConsumerQueueLocked(true /*allowDisplaySync*/)) != OK) {
return res;
}
@@ -500,7 +494,7 @@
return OK;
}
-status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowPreviewScheduler) {
+status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowDisplaySync) {
status_t res;
mTraceFirstBuffer = true;
@@ -590,16 +584,17 @@
int timestampBase = getTimestampBase();
bool isDefaultTimeBase = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_DEFAULT);
- if (allowPreviewScheduler) {
+ if (allowDisplaySync) {
// We cannot distinguish between a SurfaceView and an ImageReader of
- // preview buffer format. The PreviewFrameScheduler needs to handle both.
+ // preview buffer format. Frames are synchronized to display in both
+ // cases.
bool forceChoreographer = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
bool defaultToChoreographer = (isDefaultTimeBase && isConsumedByHWComposer() &&
!property_get_bool("camera.disable_preview_scheduler", false));
if (forceChoreographer || defaultToChoreographer) {
- mPreviewFrameScheduler = std::make_unique<PreviewFrameScheduler>(*this, mConsumer);
- mTotalBufferCount += PreviewFrameScheduler::kQueueDepthWatermark;
+ mSyncToDisplay = true;
+ mTotalBufferCount += kDisplaySyncExtraBuffer;
}
}
@@ -1244,6 +1239,11 @@
return OK;
}
+void Camera3OutputStream::onMinDurationChanged(nsecs_t duration) {
+ Mutex::Autolock l(mLock);
+ mMinExpectedDuration = duration;
+}
+
void Camera3OutputStream::returnPrefetchedBuffersLocked() {
std::vector<Surface::BatchBuffer> batchedBuffers;
@@ -1261,9 +1261,52 @@
}
}
-bool Camera3OutputStream::shouldLogError(status_t res) {
- Mutex::Autolock l(mLock);
- return shouldLogError(res, mState);
+nsecs_t Camera3OutputStream::syncTimestampToDisplayLocked(nsecs_t t) {
+ ParcelableVsyncEventData parcelableVsyncEventData;
+ auto res = mDisplayEventReceiver.getLatestVsyncEventData(&parcelableVsyncEventData);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error getting latest vsync event data: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return t;
+ }
+
+ const VsyncEventData& vsyncEventData = parcelableVsyncEventData.vsync;
+ nsecs_t currentTime = systemTime();
+
+ // Reset capture to present time offset if more than 1 second
+ // between frames.
+ if (t - mLastCaptureTime > kSpacingResetIntervalNs) {
+ for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ if (vsyncEventData.frameTimelines[i].deadlineTimestamp >= currentTime) {
+ mCaptureToPresentOffset =
+ vsyncEventData.frameTimelines[i].expectedPresentationTime - t;
+ break;
+ }
+ }
+ }
+
+ nsecs_t idealPresentT = t + mCaptureToPresentOffset;
+ nsecs_t expectedPresentT = 0;
+ nsecs_t minDiff = INT64_MAX;
+ // Derive minimum intervals between presentation times based on minimal
+ // expected duration.
+ size_t minVsyncs = (mMinExpectedDuration + vsyncEventData.frameInterval - 1) /
+ vsyncEventData.frameInterval - 1;
+ nsecs_t minInterval = minVsyncs * vsyncEventData.frameInterval + kTimelineThresholdNs;
+ // Find best timestamp in the vsync timeline:
+ // - closest to the ideal present time,
+ // - deadline timestamp is greater than the current time, and
+ // - the candidate present time is at least minInterval in the future
+ // compared to last present time.
+ for (const auto& vsyncTime : vsyncEventData.frameTimelines) {
+ if (std::abs(vsyncTime.expectedPresentationTime - idealPresentT) < minDiff &&
+ vsyncTime.deadlineTimestamp >= currentTime &&
+ vsyncTime.expectedPresentationTime > mLastPresentTime + minInterval) {
+ expectedPresentT = vsyncTime.expectedPresentationTime;
+ minDiff = std::abs(vsyncTime.expectedPresentationTime - idealPresentT);
+ }
+ }
+ return expectedPresentT;
}
}; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 7b12efc..6ea7ef7 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -21,13 +21,13 @@
#include <utils/RefBase.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
+#include <gui/DisplayEventReceiver.h>
#include "utils/LatencyHistogram.h"
#include "Camera3Stream.h"
#include "Camera3IOStreamBase.h"
#include "Camera3OutputStreamInterface.h"
#include "Camera3BufferManager.h"
-#include "PreviewFrameScheduler.h"
namespace android {
@@ -240,12 +240,16 @@
virtual status_t setBatchSize(size_t batchSize = 1) override;
/**
+ * Notify the stream on change of min frame durations.
+ */
+ virtual void onMinDurationChanged(nsecs_t duration) override;
+
+ /**
* Apply ZSL related consumer usage quirk.
*/
static void applyZSLUsageQuirk(int format, uint64_t *consumerUsage /*inout*/);
void setImageDumpMask(int mask) { mImageDumpMask = mask; }
- bool shouldLogError(status_t res);
protected:
Camera3OutputStream(int id, camera_stream_type_t type,
@@ -278,7 +282,7 @@
status_t getEndpointUsageForSurface(uint64_t *usage,
const sp<Surface>& surface) const;
- status_t configureConsumerQueueLocked(bool allowPreviewScheduler);
+ status_t configureConsumerQueueLocked(bool allowDisplaySync);
// Consumer as the output of camera HAL
sp<Surface> mConsumer;
@@ -392,13 +396,24 @@
void returnPrefetchedBuffersLocked();
+ // Synchronize camera timestamp to display, and the return value
+ // can be used as presentation timestamp
+ nsecs_t syncTimestampToDisplayLocked(nsecs_t t);
+
static const int32_t kDequeueLatencyBinSize = 5; // in ms
CameraLatencyHistogram mDequeueBufferLatency;
int mImageDumpMask = 0;
- // The preview stream scheduler for re-timing frames
- std::unique_ptr<PreviewFrameScheduler> mPreviewFrameScheduler;
+ nsecs_t mMinExpectedDuration = 0;
+ bool mSyncToDisplay = false;
+ DisplayEventReceiver mDisplayEventReceiver;
+ nsecs_t mLastCaptureTime = 0;
+ nsecs_t mLastPresentTime = 0;
+ nsecs_t mCaptureToPresentOffset = 0;
+ static constexpr size_t kDisplaySyncExtraBuffer = 2;
+ static constexpr nsecs_t kSpacingResetIntervalNs = 1000000000LL; // 1 second
+ static constexpr nsecs_t kTimelineThresholdNs = 1000000LL; // 1 millisecond
}; // class Camera3OutputStream
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index e44e795..a6d4b96 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -108,6 +108,14 @@
* instead.
*/
virtual status_t setBatchSize(size_t batchSize = 1) = 0;
+
+ /**
+ * Notify the output stream that the minimum frame duration has changed.
+ *
+ * The minimum frame duration is calculated based on the upper bound of
+ * AE_TARGET_FPS_RANGE in the capture request.
+ */
+ virtual void onMinDurationChanged(nsecs_t duration) = 0;
};
// Helper class to organize a synchronized mapping of stream IDs to stream instances
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index ab25322..ed66df0 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -853,6 +853,13 @@
r.shutterTimestamp = msg.timestamp;
r.shutterReadoutTimestamp = msg.readout_timestamp;
+ if (r.minExpectedDuration != states.minFrameDuration) {
+ for (size_t i = 0; i < states.outputStreams.size(); i++) {
+ auto outputStream = states.outputStreams[i];
+ outputStream->onMinDurationChanged(r.minExpectedDuration);
+ }
+ states.minFrameDuration = r.minExpectedDuration;
+ }
if (r.hasCallback) {
ALOGVV("Camera %s: %s: Shutter fired for frame %d (id %d) at %" PRId64,
states.cameraId.string(), __FUNCTION__,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 4d1eb75..dd01408 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -107,6 +107,7 @@
InflightRequestUpdateInterface& inflightIntf;
BufferRecordsInterface& bufferRecordsIntf;
bool legacyClient;
+ nsecs_t& minFrameDuration;
};
void processCaptureResult(CaptureOutputStates& states, const camera_capture_result *result);
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index c09a0b2..d24b527 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -251,7 +251,7 @@
return res;
}
- res = configureConsumerQueueLocked(false/*allowPreviewScheduler*/);
+ res = configureConsumerQueueLocked(false/*allowDisplaySync*/);
if (res != OK) {
ALOGE("Failed to configureConsumerQueueLocked: %s(%d)", strerror(-res), res);
return res;
diff --git a/services/camera/libcameraservice/device3/InFlightRequest.h b/services/camera/libcameraservice/device3/InFlightRequest.h
index 0c97f3e..493a9e2 100644
--- a/services/camera/libcameraservice/device3/InFlightRequest.h
+++ b/services/camera/libcameraservice/device3/InFlightRequest.h
@@ -143,6 +143,11 @@
// is not for constrained high speed recording, this flag will also be true.
bool hasCallback;
+ // Minimum expected frame duration for this request
+ // For manual captures, equal to the max of requested exposure time and frame duration
+ // For auto-exposure modes, equal to 1/(higher end of target FPS range)
+ nsecs_t minExpectedDuration;
+
// Maximum expected frame duration for this request.
// For manual captures, equal to the max of requested exposure time and frame duration
// For auto-exposure modes, equal to 1/(lower end of target FPS range)
@@ -187,8 +192,8 @@
// Current output transformation
int32_t transform;
- // TODO: dedupe
- static const nsecs_t kDefaultExpectedDuration = 100000000; // 100 ms
+ static const nsecs_t kDefaultMinExpectedDuration = 33333333; // 33 ms
+ static const nsecs_t kDefaultMaxExpectedDuration = 100000000; // 100 ms
// Default constructor needed by KeyedVector
InFlightRequest() :
@@ -199,7 +204,8 @@
numBuffersLeft(0),
hasInputBuffer(false),
hasCallback(true),
- maxExpectedDuration(kDefaultExpectedDuration),
+ minExpectedDuration(kDefaultMinExpectedDuration),
+ maxExpectedDuration(kDefaultMaxExpectedDuration),
skipResultMetadata(false),
errorBufStrategy(ERROR_BUF_CACHE),
stillCapture(false),
@@ -210,7 +216,7 @@
}
InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
- bool hasAppCallback, nsecs_t maxDuration,
+ bool hasAppCallback, nsecs_t minDuration, nsecs_t maxDuration,
const std::set<std::set<String8>>& physicalCameraIdSet, bool isStillCapture,
bool isZslCapture, bool rotateAndCropAuto, const std::set<std::string>& idsWithZoom,
nsecs_t requestNs, const SurfaceMap& outSurfaces = SurfaceMap{}) :
@@ -222,6 +228,7 @@
resultExtras(extras),
hasInputBuffer(hasInput),
hasCallback(hasAppCallback),
+ minExpectedDuration(minDuration),
maxExpectedDuration(maxDuration),
skipResultMetadata(false),
errorBufStrategy(ERROR_BUF_CACHE),
diff --git a/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp b/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
deleted file mode 100644
index 80f27ed..0000000
--- a/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Camera3-PreviewFrameScheduler"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include <android/looper.h>
-#include "PreviewFrameScheduler.h"
-#include "Camera3OutputStream.h"
-
-namespace android {
-
-namespace camera3 {
-
-/**
- * Internal Choreographer thread implementation for polling and handling callbacks
- */
-
-// Callback function for Choreographer
-static void frameCallback(const AChoreographerFrameCallbackData* callbackData, void* data) {
- PreviewFrameScheduler* parent = static_cast<PreviewFrameScheduler*>(data);
- if (parent == nullptr) {
- ALOGE("%s: Invalid data for Choreographer callback!", __FUNCTION__);
- return;
- }
-
- size_t length = AChoreographerFrameCallbackData_getFrameTimelinesLength(callbackData);
- std::vector<nsecs_t> timeline(length);
- for (size_t i = 0; i < length; i++) {
- nsecs_t timestamp = AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
- callbackData, i);
- timeline[i] = timestamp;
- }
-
- parent->onNewPresentationTime(timeline);
-
- AChoreographer_postVsyncCallback(AChoreographer_getInstance(), frameCallback, data);
-}
-
-struct ChoreographerThread : public Thread {
- ChoreographerThread();
- status_t start(PreviewFrameScheduler* parent);
- virtual status_t readyToRun() override;
- virtual bool threadLoop() override;
-
-protected:
- virtual ~ChoreographerThread() {}
-
-private:
- ChoreographerThread &operator=(const ChoreographerThread &);
-
- // This only impacts the shutdown time. It won't impact the choreographer
- // callback frequency.
- static constexpr nsecs_t kPollingTimeoutMs = 5;
- PreviewFrameScheduler* mParent = nullptr;
-};
-
-ChoreographerThread::ChoreographerThread() : Thread(false /*canCallJava*/) {
-}
-
-status_t ChoreographerThread::start(PreviewFrameScheduler* parent) {
- mParent = parent;
- return run("PreviewChoreographer");
-}
-
-status_t ChoreographerThread::readyToRun() {
- ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
- if (AChoreographer_getInstance() == NULL) {
- return NO_INIT;
- }
-
- AChoreographer_postVsyncCallback(
- AChoreographer_getInstance(), frameCallback, mParent);
- return OK;
-}
-
-bool ChoreographerThread::threadLoop() {
- if (exitPending()) {
- return false;
- }
- ALooper_pollOnce(kPollingTimeoutMs, nullptr, nullptr, nullptr);
- return true;
-}
-
-/**
- * PreviewFrameScheduler implementation
- */
-
-PreviewFrameScheduler::PreviewFrameScheduler(Camera3OutputStream& parent, sp<Surface> consumer) :
- mParent(parent),
- mConsumer(consumer),
- mChoreographerThread(new ChoreographerThread()) {
-}
-
-PreviewFrameScheduler::~PreviewFrameScheduler() {
- {
- Mutex::Autolock l(mLock);
- mChoreographerThread->requestExit();
- }
- mChoreographerThread->join();
-}
-
-status_t PreviewFrameScheduler::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
- ANativeWindowBuffer* anwBuffer, int releaseFence) {
- // Start choreographer thread if it's not already running.
- if (!mChoreographerThread->isRunning()) {
- status_t res = mChoreographerThread->start(this);
- if (res != OK) {
- ALOGE("%s: Failed to init choreographer thread!", __FUNCTION__);
- return res;
- }
- }
-
- {
- Mutex::Autolock l(mLock);
- mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
-
- // Queue buffer to client right away if pending buffers are more than
- // the queue depth watermark.
- if (mPendingBuffers.size() > kQueueDepthWatermark) {
- auto oldBuffer = mPendingBuffers.front();
- mPendingBuffers.pop();
-
- status_t res = queueBufferToClientLocked(oldBuffer, oldBuffer.timestamp);
- if (res != OK) {
- return res;
- }
-
- // Reset the last capture and presentation time
- mLastCameraCaptureTime = 0;
- mLastCameraPresentTime = 0;
- } else {
- ATRACE_INT(kPendingBufferTraceName, mPendingBuffers.size());
- }
- }
- return OK;
-}
-
-void PreviewFrameScheduler::onNewPresentationTime(const std::vector<nsecs_t>& timeline) {
- ATRACE_CALL();
- Mutex::Autolock l(mLock);
- if (mPendingBuffers.size() > 0) {
- auto nextBuffer = mPendingBuffers.front();
- mPendingBuffers.pop();
-
- // Find the best presentation time by finding the element in the
- // choreographer timeline that's closest to the ideal presentation time.
- // The ideal presentation time is the last presentation time + frame
- // interval.
- nsecs_t cameraInterval = nextBuffer.timestamp - mLastCameraCaptureTime;
- nsecs_t idealPresentTime = (cameraInterval < kSpacingResetIntervalNs) ?
- (mLastCameraPresentTime + cameraInterval) : nextBuffer.timestamp;
- nsecs_t presentTime = *std::min_element(timeline.begin(), timeline.end(),
- [idealPresentTime](nsecs_t p1, nsecs_t p2) {
- return std::abs(p1 - idealPresentTime) < std::abs(p2 - idealPresentTime);
- });
-
- status_t res = queueBufferToClientLocked(nextBuffer, presentTime);
- ATRACE_INT(kPendingBufferTraceName, mPendingBuffers.size());
-
- if (mParent.shouldLogError(res)) {
- ALOGE("%s: Preview Stream: Error queueing buffer to native window:"
- " %s (%d)", __FUNCTION__, strerror(-res), res);
- }
-
- mLastCameraCaptureTime = nextBuffer.timestamp;
- mLastCameraPresentTime = presentTime;
- }
-}
-
-status_t PreviewFrameScheduler::queueBufferToClientLocked(
- const BufferHolder& bufferHolder, nsecs_t timestamp) {
- mParent.setTransform(bufferHolder.transform, true/*mayChangeMirror*/);
-
- status_t res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
- if (res != OK) {
- ALOGE("%s: Preview Stream: Error setting timestamp: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- Camera3Stream::queueHDRMetadata(bufferHolder.anwBuffer.get()->handle, mConsumer,
- mParent.getDynamicRangeProfile());
-
- res = mConsumer->queueBuffer(mConsumer.get(), bufferHolder.anwBuffer.get(),
- bufferHolder.releaseFence);
- if (res != OK) {
- close(bufferHolder.releaseFence);
- }
-
- return res;
-}
-
-}; // namespace camera3
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/device3/PreviewFrameScheduler.h b/services/camera/libcameraservice/device3/PreviewFrameScheduler.h
deleted file mode 100644
index c0574fd..0000000
--- a/services/camera/libcameraservice/device3/PreviewFrameScheduler.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERA3_PREVIEWFRAMESCHEDULER_H
-#define ANDROID_SERVERS_CAMERA_CAMERA3_PREVIEWFRAMESCHEDULER_H
-
-#include <queue>
-
-#include <android/choreographer.h>
-#include <gui/Surface.h>
-#include <gui/ISurfaceComposer.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/Looper.h>
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-namespace camera3 {
-
-class Camera3OutputStream;
-struct ChoreographerThread;
-
-/***
- * Preview stream scheduler for better preview display synchronization
- *
- * The ideal viewfinder user experience is that frames are presented to the
- * user in the same cadence as outputed by the camera sensor. However, the
- * processing latency between frames could vary, due to factors such
- * as CPU load, differences in request settings, etc. This frame processing
- * latency results in variation in presentation of frames to the user.
- *
- * The PreviewFrameScheduler improves the viewfinder user experience by:
- * 1. Cache preview buffers in the scheduler
- * 2. For each choreographer callback, queue the oldest cached buffer with
- * the best matching presentation timestamp. Frame N's presentation timestamp
- * is the choreographer timeline timestamp closest to (Frame N-1's
- * presentation time + camera capture interval between frame N-1 and frame N).
- * 3. Maintain at most 2 queue-able buffers. If the 3rd preview buffer becomes
- * available, queue the oldest cached buffer to the buffer queue.
- */
-class PreviewFrameScheduler {
- public:
- explicit PreviewFrameScheduler(Camera3OutputStream& parent, sp<Surface> consumer);
- virtual ~PreviewFrameScheduler();
-
- // Queue preview buffer locally
- status_t queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
- ANativeWindowBuffer* anwBuffer, int releaseFence);
-
- // Callback function with a new presentation timeline from choreographer. This
- // will trigger a locally queued buffer be sent to the buffer queue.
- void onNewPresentationTime(const std::vector<nsecs_t>& presentationTimeline);
-
- // Maintain at most 2 queue-able buffers
- static constexpr int32_t kQueueDepthWatermark = 2;
-
- private:
- // structure holding cached preview buffer info
- struct BufferHolder {
- nsecs_t timestamp;
- int32_t transform;
- sp<ANativeWindowBuffer> anwBuffer;
- int releaseFence;
-
- BufferHolder(nsecs_t t, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
- timestamp(t), transform(tr), anwBuffer(anwb), releaseFence(rf) {}
- };
-
- status_t queueBufferToClientLocked(const BufferHolder& bufferHolder,
- nsecs_t presentTime);
-
- static constexpr char kPendingBufferTraceName[] = "pending_preview_buffers";
-
- // Camera capture interval for resetting frame spacing between preview sessions
- static constexpr nsecs_t kSpacingResetIntervalNs = 1000000000L; // 1 second
-
- Camera3OutputStream& mParent;
- sp<ANativeWindow> mConsumer;
- mutable Mutex mLock;
-
- std::queue<BufferHolder> mPendingBuffers;
- nsecs_t mLastCameraCaptureTime = 0;
- nsecs_t mLastCameraPresentTime = 0;
-
- // Choreographer related
- sp<Looper> mLooper;
- sp<ChoreographerThread> mChoreographerThread;
-};
-
-}; //namespace camera3
-}; //namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 1add032..f05520f 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -371,7 +371,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
- *this, *(mInterface), mLegacyClient}, mResultMetadataQueue
+ *this, *(mInterface), mLegacyClient, mMinExpectedDuration}, mResultMetadataQueue
};
for (const auto& result : results) {
@@ -412,7 +412,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
- *this, *(mInterface), mLegacyClient}, mResultMetadataQueue
+ *this, *(mInterface), mLegacyClient, mMinExpectedDuration}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
index 895ce56..336719d 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -123,7 +123,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
- *this, mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ *this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -168,7 +168,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
- *this, mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ *this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index 87d3ee8..cf6d462 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -369,7 +369,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient}, mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration}, mResultMetadataQueue
};
//HidlCaptureOutputStates hidlStates {
@@ -431,7 +431,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient}, mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration}, mResultMetadataQueue
};
for (const auto& result : results) {
@@ -483,7 +483,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient}, mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
index d517c8d..5c97f0e 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -105,7 +105,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -145,7 +145,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -180,7 +180,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/tests/PreviewSchedulerTest.cpp b/services/camera/libcameraservice/tests/PreviewSchedulerTest.cpp
deleted file mode 100644
index 025521a..0000000
--- a/services/camera/libcameraservice/tests/PreviewSchedulerTest.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "PreviewSchedulerTest"
-
-#include <chrono>
-#include <thread>
-#include <utility>
-
-#include <gtest/gtest.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/Mutex.h>
-
-#include <gui/BufferItemConsumer.h>
-#include <gui/BufferQueue.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <gui/Surface.h>
-
-#include "../device3/Camera3OutputStream.h"
-#include "../device3/PreviewFrameScheduler.h"
-
-using namespace android;
-using namespace android::camera3;
-
-// Consumer buffer available listener
-class SimpleListener : public BufferItemConsumer::FrameAvailableListener {
-public:
- SimpleListener(size_t frameCount): mFrameCount(frameCount) {}
-
- void waitForFrames() {
- Mutex::Autolock lock(mMutex);
- while (mFrameCount > 0) {
- mCondition.wait(mMutex);
- }
- }
-
- void onFrameAvailable(const BufferItem& /*item*/) override {
- Mutex::Autolock lock(mMutex);
- if (mFrameCount > 0) {
- mFrameCount--;
- mCondition.signal();
- }
- }
-
- void reset(size_t frameCount) {
- Mutex::Autolock lock(mMutex);
- mFrameCount = frameCount;
- }
-private:
- size_t mFrameCount;
- Mutex mMutex;
- Condition mCondition;
-};
-
-// Test the PreviewFrameScheduler functionatliy of re-timing buffers
-TEST(PreviewSchedulerTest, BasicPreviewSchedulerTest) {
- const int ID = 0;
- const int FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- const uint32_t WIDTH = 640;
- const uint32_t HEIGHT = 480;
- const int32_t TRANSFORM = 0;
- const nsecs_t T_OFFSET = 0;
- const android_dataspace DATASPACE = HAL_DATASPACE_UNKNOWN;
- const camera_stream_rotation_t ROTATION = CAMERA_STREAM_ROTATION_0;
- const String8 PHY_ID;
- const std::unordered_set<int32_t> PIX_MODES;
- const int BUFFER_COUNT = 4;
- const int TOTAL_BUFFER_COUNT = BUFFER_COUNT * 2;
-
- // Create buffer queue
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- ASSERT_NE(producer, nullptr);
- ASSERT_NE(consumer, nullptr);
- ASSERT_EQ(NO_ERROR, consumer->setDefaultBufferSize(WIDTH, HEIGHT));
-
- // Set up consumer
- sp<BufferItemConsumer> bufferConsumer = new BufferItemConsumer(consumer,
- GRALLOC_USAGE_HW_COMPOSER, BUFFER_COUNT);
- ASSERT_NE(bufferConsumer, nullptr);
- sp<SimpleListener> consumerListener = new SimpleListener(BUFFER_COUNT);
- bufferConsumer->setFrameAvailableListener(consumerListener);
-
- // Set up producer
- sp<Surface> surface = new Surface(producer);
- sp<StubProducerListener> listener = new StubProducerListener();
- ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, listener));
- sp<ANativeWindow> anw(surface);
- ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), TOTAL_BUFFER_COUNT));
-
- // Create Camera3OutputStream and PreviewFrameScheduler
- sp<Camera3OutputStream> stream = new Camera3OutputStream(ID, surface, WIDTH, HEIGHT,
- FORMAT, DATASPACE, ROTATION, T_OFFSET, PHY_ID, PIX_MODES);
- ASSERT_NE(stream, nullptr);
- std::unique_ptr<PreviewFrameScheduler> scheduler =
- std::make_unique<PreviewFrameScheduler>(*stream, surface);
- ASSERT_NE(scheduler, nullptr);
-
- // The pair of nsecs_t: camera timestamp delta (negative means in the past) and frame interval
- const std::pair<nsecs_t, nsecs_t> inputTimestamps[][BUFFER_COUNT] = {
- // 30fps, 33ms interval
- {{-100000000LL, 33333333LL}, {-66666667LL, 33333333LL},
- {-33333333LL, 33333333LL}, {0, 0}},
- // 30fps, variable interval
- {{-100000000LL, 16666667LL}, {-66666667LL, 33333333LL},
- {-33333333LL, 50000000LL}, {0, 0}},
- // 60fps, 16.7ms interval
- {{-50000000LL, 16666667LL}, {-33333333LL, 16666667LL},
- {-16666667LL, 16666667LL}, {0, 0}},
- // 60fps, variable interval
- {{-50000000LL, 8666667LL}, {-33333333LL, 19666667LL},
- {-16666667LL, 20666667LL}, {0, 0}},
- };
-
- // Go through different use cases, and check the buffer timestamp
- size_t iterations = sizeof(inputTimestamps)/sizeof(inputTimestamps[0]);
- for (size_t i = 0; i < iterations; i++) {
- // Space out different test sets to reset the frame scheduler
- nsecs_t timeBase = systemTime() - s2ns(1) * (iterations - i);
- nsecs_t lastQueueTime = 0;
- nsecs_t duration = 0;
- for (size_t j = 0; j < BUFFER_COUNT; j++) {
- ANativeWindowBuffer* buffer = nullptr;
- int fenceFd;
- ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buffer, &fenceFd));
-
- // Sleep to space out queuePreviewBuffer
- nsecs_t currentTime = systemTime();
- if (duration > 0 && duration > currentTime - lastQueueTime) {
- std::this_thread::sleep_for(
- std::chrono::nanoseconds(duration + lastQueueTime - currentTime));
- }
- nsecs_t timestamp = timeBase + inputTimestamps[i][j].first;
- ASSERT_EQ(NO_ERROR,
- scheduler->queuePreviewBuffer(timestamp, TRANSFORM, buffer, fenceFd));
-
- lastQueueTime = systemTime();
- duration = inputTimestamps[i][j].second;
- }
-
- // Collect output timestamps, making sure they are either set by
- // producer, or set by the scheduler.
- consumerListener->waitForFrames();
- nsecs_t outputTimestamps[BUFFER_COUNT];
- for (size_t j = 0; j < BUFFER_COUNT; j++) {
- BufferItem bufferItem;
- ASSERT_EQ(NO_ERROR, bufferConsumer->acquireBuffer(&bufferItem, 0/*presentWhen*/));
-
- outputTimestamps[j] = bufferItem.mTimestamp;
- ALOGV("%s: [%zu][%zu]: input: %" PRId64 ", output: %" PRId64, __FUNCTION__,
- i, j, timeBase + inputTimestamps[i][j].first, bufferItem.mTimestamp);
- ASSERT_GT(bufferItem.mTimestamp, inputTimestamps[i][j].first);
-
- ASSERT_EQ(NO_ERROR, bufferConsumer->releaseBuffer(bufferItem));
- }
-
- // Check the output timestamp intervals are aligned with input intervals
- const nsecs_t SHIFT_THRESHOLD = ms2ns(2);
- for (size_t j = 0; j < BUFFER_COUNT - 1; j ++) {
- nsecs_t interval_shift = outputTimestamps[j+1] - outputTimestamps[j] -
- (inputTimestamps[i][j+1].first - inputTimestamps[i][j].first);
- ASSERT_LE(std::abs(interval_shift), SHIFT_THRESHOLD);
- }
-
- consumerListener->reset(BUFFER_COUNT);
- }
-
- // Disconnect the surface
- ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU));
-}
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index aacc2be..99e3691 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -297,33 +297,35 @@
ALOGD("%s", __func__);
// Add action to save AnalyticsState if audioserver is restarted.
- // This triggers on an item of "audio.flinger"
- // with a property "event" set to "AudioFlinger" (the constructor).
+ // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
+ // as well as TimeCheck events.
mActions.addAction(
AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
std::make_shared<AnalyticsActions::Function>(
[this](const std::shared_ptr<const android::mediametrics::Item> &item){
- ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
- mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
- *mAnalyticsState.get()));
- // Note: get returns shared_ptr temp, whose lifetime is extended
- // to end of full expression.
- mAnalyticsState->clear(); // TODO: filter the analytics state.
- // Perhaps report this.
-
- // Set up a timer to expire the previous audio state to save space.
- // Use the transaction log size as a cookie to see if it is the
- // same as before. A benign race is possible where a state is cleared early.
- const size_t size = mPreviousAnalyticsState->transactionLog().size();
- mTimedAction.postIn(
- std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
- if (mPreviousAnalyticsState->transactionLog().size() == size) {
- ALOGD("expiring previous audio state after %d seconds.",
- PREVIOUS_STATE_EXPIRE_SEC);
- mPreviousAnalyticsState->clear(); // removes data from the state.
- }
- });
+ mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
+ }));
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
+ }));
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
+ }));
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
}));
// Handle legacy aaudio playback stream statistics
@@ -1390,4 +1392,138 @@
}
}
+// Create new state, typically occurs after an AudioFlinger ctor event.
+void AudioAnalytics::newState()
+{
+ mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
+ *mAnalyticsState.get()));
+ // Note: get returns shared_ptr temp, whose lifetime is extended
+ // to end of full expression.
+ mAnalyticsState->clear(); // TODO: filter the analytics state.
+ // Perhaps report this.
+
+ // Set up a timer to expire the previous audio state to save space.
+ // Use the transaction log size as a cookie to see if it is the
+ // same as before. A benign race is possible where a state is cleared early.
+ const size_t size = mPreviousAnalyticsState->transactionLog().size();
+ mTimedAction.postIn(
+ std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
+ if (mPreviousAnalyticsState->transactionLog().size() == size) {
+ ALOGD("expiring previous audio state after %d seconds.",
+ PREVIOUS_STATE_EXPIRE_SEC);
+ mPreviousAnalyticsState->clear(); // removes data from the state.
+ }
+ });
+}
+
+void AudioAnalytics::Health::onAudioServerStart(Module module,
+ const std::shared_ptr<const android::mediametrics::Item> &item)
+{
+ const auto nowTime = std::chrono::system_clock::now();
+ if (module == Module::AUDIOFLINGER) {
+ {
+ std::lock_guard lg(mLock);
+ // reset state on AudioFlinger construction.
+ // AudioPolicy is created after AudioFlinger.
+ mAudioFlingerCtorTime = nowTime;
+ mSimpleLog.log("AudioFlinger ctor");
+ }
+ mAudioAnalytics.newState();
+ return;
+ }
+ if (module == Module::AUDIOPOLICY) {
+ // A start event occurs when audioserver
+ //
+ // (1) Starts the first time
+ // (2) Restarts because of the TimeCheck watchdog
+ // (3) Restarts not because of the TimeCheck watchdog.
+ int64_t executionTimeNs = 0;
+ (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
+ const float loadTimeMs = executionTimeNs * 1e-6f;
+ std::lock_guard lg(mLock);
+ const int64_t restarts = mStartCount;
+ if (mStopCount == mStartCount) {
+ mAudioPolicyCtorTime = nowTime;
+ ++mStartCount;
+ if (mStopCount == 0) {
+ // (1) First time initialization.
+ ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
+ __func__, item->getKey().c_str(), loadTimeMs);
+ mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
+ } else {
+ // (2) Previous failure caught due to TimeCheck. We know how long restart takes.
+ const float restartMs =
+ std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
+ mAudioFlingerCtorTime - mStopTime).count();
+ ALOGW("%s: (key=%s) AudioPolicy ctor, "
+ "restarts:%lld restartMs:%f loadTimeMs:%f",
+ __func__, item->getKey().c_str(),
+ (long long)restarts, restartMs, loadTimeMs);
+ mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
+ (long long)restarts, restartMs, loadTimeMs);
+ }
+ } else {
+ // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
+ // However we can estimate the uptime from the delta time from previous ctor.
+ const float uptimeMs =
+ std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
+ nowTime - mAudioFlingerCtorTime).count();
+ mStopCount = mStartCount;
+ mAudioPolicyCtorTime = nowTime;
+ ++mStartCount;
+
+ ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
+ "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
+ __func__, item->getKey().c_str(),
+ (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
+ mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
+ "restarts:%lld uptimeMs:%f loadTimeMs:%f",
+ (long long)restarts, uptimeMs, loadTimeMs);
+ }
+ }
+}
+
+void AudioAnalytics::Health::onAudioServerTimeout(Module module,
+ const std::shared_ptr<const android::mediametrics::Item> &item)
+{
+ std::string moduleName = getModuleName(module);
+ int64_t methodCode{};
+ std::string methodName;
+ (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
+ (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
+
+ std::lock_guard lg(mLock);
+ if (mStopCount >= mStartCount) {
+ ALOGD("%s: (key=%s) %s timeout %s(%lld) "
+ "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
+ __func__, item->getKey().c_str(), moduleName.c_str(),
+ methodName.c_str(), (long long)methodCode,
+ (long long)mStopCount, (long long)mStartCount);
+ return;
+ }
+
+ const int64_t restarts = mStartCount - 1;
+ ++mStopCount;
+ mStopTime = std::chrono::system_clock::now();
+ const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
+ mStopTime - mAudioFlingerCtorTime).count();
+ ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
+ __func__, item->getKey().c_str(), moduleName.c_str(),
+ methodName.c_str(), (long long)methodCode,
+ (long long)restarts, uptimeMs);
+ mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
+ moduleName.c_str(), methodName.c_str(), (long long)methodCode,
+ (long long)restarts, uptimeMs);
+}
+
+std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
+ int32_t lines, const char *prefix) const
+{
+ std::lock_guard lg(mLock);
+ std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
+ size_t n = std::count(s.begin(), s.end(), '\n');
+ return { s, n };
+}
+
+
} // namespace android::mediametrics
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 636b343..ff16b9e 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -327,6 +327,15 @@
result << "-- some lines may be truncated --\n";
}
+ const int32_t healthLinesToDump = all ? INT32_MAX : 15;
+ result << "\nHealth Message Log:";
+ const auto [ healthDumpString, healthLines ] =
+ mAudioAnalytics.dumpHealth(healthLinesToDump);
+ result << "\n" << healthDumpString;
+ if (healthLines == healthLinesToDump) {
+ result << "-- some lines may be truncated --\n";
+ }
+
result << "\nLogSessionId:\n"
<< mediametrics::ValidateId::get()->dump();
diff --git a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
index a44fcc1..5ee8c30 100644
--- a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
+++ b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
@@ -83,6 +83,15 @@
return mHeatMap.dump(lines);
}
+ /**
+ * Returns a pair consisting of the dump string and the number of lines in the string.
+ *
+ * Health dump.
+ */
+ std::pair<std::string, int32_t> dumpHealth(int32_t lines = INT32_MAX) const {
+ return mHealth.dump(lines);
+ }
+
void clear() {
// underlying state is locked.
mPreviousAnalyticsState->clear();
@@ -247,6 +256,67 @@
AudioAnalytics &mAudioAnalytics;
} mAAudioStreamInfo{*this};
+ // Create new state, typically occurs after an AudioFlinger ctor event.
+ void newState();
+
+ // Health is a nested class that tracks audioserver health properties
+ class Health {
+ public:
+ explicit Health(AudioAnalytics &audioAnalytics)
+ : mAudioAnalytics(audioAnalytics) {}
+
+ enum class Module {
+ AUDIOFLINGER,
+ AUDIOPOLICY,
+ };
+
+ const char *getModuleName(Module module) {
+ switch (module) {
+ case Module::AUDIOFLINGER: return "AudioFlinger";
+ case Module::AUDIOPOLICY: return "AudioPolicy";
+ }
+ return "Unknown";
+ }
+
+ // Called when we believe audioserver starts (AudioFlinger ctor)
+ void onAudioServerStart(Module module,
+ const std::shared_ptr<const android::mediametrics::Item> &item);
+
+ // Called when we believe audioserver crashes (TimeCheck timeouts).
+ void onAudioServerTimeout(Module module,
+ const std::shared_ptr<const android::mediametrics::Item> &item);
+
+ std::pair<std::string, int32_t> dump(
+ int32_t lines = INT32_MAX, const char *prefix = nullptr) const;
+
+ private:
+ AudioAnalytics& mAudioAnalytics;
+
+ mutable std::mutex mLock;
+
+ // Life cycle of AudioServer
+ // mAudioFlingerCtorTime
+ // mAudioPolicyCtorTime
+ // mAudioPolicyCtorDoneTime
+ // ...
+ // possibly mStopTime (if TimeCheck thread)
+ //
+ // UpTime is measured from mStopTime - mAudioFlingerCtorTime.
+ //
+ // The stop events come from TimeCheck timeout aborts. There may be other
+ // uncaught signals, e.g. SIGSEGV, that cause missing stop events.
+ std::chrono::system_clock::time_point mAudioFlingerCtorTime GUARDED_BY(mLock);
+ std::chrono::system_clock::time_point mAudioPolicyCtorTime GUARDED_BY(mLock);
+ std::chrono::system_clock::time_point mAudioPolicyCtorDoneTime GUARDED_BY(mLock);
+ std::chrono::system_clock::time_point mStopTime GUARDED_BY(mLock);
+
+ // mStartCount and mStopCount track the audioserver start and stop events.
+ int64_t mStartCount GUARDED_BY(mLock) = 0;
+ int64_t mStopCount GUARDED_BY(mLock) = 0;
+
+ SimpleLog mSimpleLog GUARDED_BY(mLock) {64};
+ } mHealth{*this};
+
AudioPowerUsage mAudioPowerUsage;
};
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 57be435..1c09544 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -696,11 +696,11 @@
if (clients.size() == 0) {
// if we are here, run the fourth pass to free one codec with the different type.
if (secureCodec != NULL) {
- MediaResource temp(MediaResource::Type::kNonSecureCodec, 1);
+ MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
getClientForResource_l(callingPid, &temp, &clients);
}
if (nonSecureCodec != NULL) {
- MediaResource temp(MediaResource::Type::kSecureCodec, 1);
+ MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
getClientForResource_l(callingPid, &temp, &clients);
}
}