From 9459fb087c97c3cad66221821eb32755fdb9c9f5 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 12 Aug 2015 18:36:32 -0700 Subject: audio policy: refine TTS stream mute management Do not mute the TTS stream if a dedicated output for TTS is available. Bug: 22100304. Change-Id: Ic126100ce1144f765bc0ae42c8ea87fa47cfb822 --- .../audiopolicy/managerdefault/AudioPolicyManager.cpp | 17 +++++++++++++++-- .../audiopolicy/managerdefault/AudioPolicyManager.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'services') diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index fc27789..3e6df38 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1066,7 +1066,7 @@ status_t AudioPolicyManager::startSource(sp outputDesc, *delayMs = 0; if (stream == AUDIO_STREAM_TTS) { ALOGV("\t found BEACON stream"); - if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { + if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { return INVALID_OPERATION; } else { beaconMuteLatency = handleEventForBeacon(STARTING_BEACON); @@ -1998,6 +1998,9 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO)); result.append(buffer); + snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available"); + result.append(buffer); + write(fd, result.string(), result.size()); mAvailableOutputDevices.dump(fd, String8("output")); @@ -2678,7 +2681,8 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mAudioPortGeneration(1), mBeaconMuteRefCount(0), mBeaconPlayingRefCount(0), - mBeaconMuted(false) + mBeaconMuted(false), + mTtsOutputAvailable(false) { audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance(); if (!engineInstance) { @@ -2735,6 +2739,9 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName); continue; } + if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) { + mTtsOutputAvailable = true; + } if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { continue; @@ -4034,6 +4041,12 @@ void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t } uint32_t AudioPolicyManager::handleEventForBeacon(int event) { + + // skip beacon mute management if a dedicated TTS output is available + if (mTtsOutputAvailable) { + return 0; + } + switch(event) { case STARTING_OUTPUT: mBeaconMuteRefCount++; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index bf3ae4a..bbdf396 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -548,6 +548,7 @@ protected: uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams bool mBeaconMuted; // has STREAM_TTS been muted + bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available AudioPolicyMixCollection mPolicyMixes; // list of registered mixes -- cgit v1.1 From c78ac26e3a65328fc0118f16ee76a800d0687eb7 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Thu, 13 Aug 2015 17:58:46 -0700 Subject: Add experimental camera session prepare API. Bug: 18949148 Change-Id: I8f73e68ea2e3acc60d98954106f364d13f439a82 --- .../libcameraservice/api2/CameraDeviceClient.cpp | 37 ++++++++++++++++++++++ .../libcameraservice/api2/CameraDeviceClient.h | 3 ++ .../libcameraservice/common/CameraDeviceBase.h | 6 ++++ .../libcameraservice/device2/Camera2Device.cpp | 6 ++++ .../libcameraservice/device2/Camera2Device.h | 1 + .../libcameraservice/device3/Camera3Device.cpp | 10 ++++-- .../libcameraservice/device3/Camera3Device.h | 10 ++++-- .../libcameraservice/device3/Camera3Stream.cpp | 23 ++++++++++++-- .../libcameraservice/device3/Camera3Stream.h | 9 ++++-- .../device3/Camera3StreamInterface.h | 11 +++++-- 10 files changed, 103 insertions(+), 13 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index c717a56..f6a0221 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -719,6 +719,43 @@ status_t CameraDeviceClient::prepare(int streamId) { return res; } +status_t CameraDeviceClient::prepare2(int maxCount, int streamId) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + status_t res = OK; + if ( (res = checkPid(__FUNCTION__) ) != OK) return res; + + Mutex::Autolock icl(mBinderSerializationLock); + + // Guard against trying to prepare non-created streams + ssize_t index = NAME_NOT_FOUND; + for (size_t i = 0; i < mStreamMap.size(); ++i) { + if (streamId == mStreamMap.valueAt(i)) { + index = i; + break; + } + } + + if (index == NAME_NOT_FOUND) { + ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream created yet", + __FUNCTION__, mCameraId, streamId); + return BAD_VALUE; + } + + if (maxCount <= 0) { + ALOGE("%s: Camera %d: Invalid maxCount (%d) specified, must be greater than 0.", + __FUNCTION__, mCameraId, maxCount); + return BAD_VALUE; + } + + // Also returns BAD_VALUE if stream ID was not valid, or stream already + // has been used + res = mDevice->prepare(maxCount, streamId); + + return res; +} + status_t CameraDeviceClient::tearDown(int streamId) { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 1f8b39d..0b73f6c 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -114,6 +114,9 @@ public: // Tear down stream resources by freeing its unused buffers virtual status_t tearDown(int streamId); + // Prepare stream by preallocating up to maxCount of its buffers + virtual status_t prepare2(int maxCount, int streamId); + /** * Interface used by CameraService */ diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index cd25949..7b083a3 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -294,6 +294,12 @@ class CameraDeviceBase : public virtual RefBase { virtual status_t tearDown(int streamId) = 0; /** + * Prepare stream by preallocating up to maxCount buffers for it asynchronously. + * Calls notifyPrepared() once allocation is complete. + */ + virtual status_t prepare(int maxCount, int streamId) = 0; + + /** * Get the HAL device version. */ virtual uint32_t getDeviceVersion() = 0; diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp index c9c990c..d74f976 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.cpp +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -632,6 +632,12 @@ status_t Camera2Device::tearDown(int streamId) { return NO_INIT; } +status_t Camera2Device::prepare(int maxCount, int streamId) { + ATRACE_CALL(); + ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId); + return NO_INIT; +} + uint32_t Camera2Device::getDeviceVersion() { ATRACE_CALL(); return mDeviceVersion; diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h index 34c1ded..b4d343c 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.h +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -88,6 +88,7 @@ class Camera2Device: public CameraDeviceBase { // Prepare and tearDown are no-ops virtual status_t prepare(int streamId); virtual status_t tearDown(int streamId); + virtual status_t prepare(int maxCount, int streamId); virtual uint32_t getDeviceVersion(); virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 0a4440f..cf47bc8 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -1380,6 +1380,10 @@ status_t Camera3Device::flush(int64_t *frameNumber) { } status_t Camera3Device::prepare(int streamId) { + return prepare(camera3::Camera3StreamInterface::ALLOCATE_PIPELINE_MAX, streamId); +} + +status_t Camera3Device::prepare(int maxCount, int streamId) { ATRACE_CALL(); ALOGV("%s: Camera %d: Preparing stream %d", __FUNCTION__, mId, streamId); Mutex::Autolock il(mInterfaceLock); @@ -1404,7 +1408,7 @@ status_t Camera3Device::prepare(int streamId) { return BAD_VALUE; } - return mPreparerThread->prepare(stream); + return mPreparerThread->prepare(maxCount, stream); } status_t Camera3Device::tearDown(int streamId) { @@ -3455,12 +3459,12 @@ Camera3Device::PreparerThread::~PreparerThread() { clear(); } -status_t Camera3Device::PreparerThread::prepare(sp& stream) { +status_t Camera3Device::PreparerThread::prepare(int maxCount, sp& stream) { status_t res; Mutex::Autolock l(mLock); - res = stream->startPrepare(); + res = stream->startPrepare(maxCount); if (res == OK) { // No preparation needed, fire listener right off ALOGV("%s: Stream %d already prepared", __FUNCTION__, stream->getId()); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 8bd0f8e..3ce6b0d 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -62,6 +62,7 @@ class Camera3Device : public CameraDeviceBase, private camera3_callback_ops { public: + Camera3Device(int id); virtual ~Camera3Device(); @@ -143,6 +144,8 @@ class Camera3Device : virtual status_t tearDown(int streamId); + virtual status_t prepare(int maxCount, int streamId); + virtual uint32_t getDeviceVersion(); virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; @@ -687,10 +690,11 @@ class Camera3Device : void setNotificationListener(NotificationListener *listener); /** - * Queue up a stream to be prepared. Streams are processed by - * a background thread in FIFO order + * Queue up a stream to be prepared. Streams are processed by a background thread in FIFO + * order. Pre-allocate up to maxCount buffers for the stream, or the maximum number needed + * for the pipeline if maxCount is ALLOCATE_PIPELINE_MAX. */ - status_t prepare(sp& stream); + status_t prepare(int maxCount, sp& stream); /** * Cancel all current and pending stream preparation diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 2527fd6..7163d62 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -53,7 +53,8 @@ Camera3Stream::Camera3Stream(int id, mName(String8::format("Camera3Stream[%d]", id)), mMaxSize(maxSize), mState(STATE_CONSTRUCTED), - mStatusId(StatusTracker::NO_STATUS_ID) { + mStatusId(StatusTracker::NO_STATUS_ID), + mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) { camera3_stream::stream_type = type; camera3_stream::width = width; @@ -252,12 +253,18 @@ bool Camera3Stream::isUnpreparable() { return mStreamUnpreparable; } -status_t Camera3Stream::startPrepare() { +status_t Camera3Stream::startPrepare(int maxCount) { ATRACE_CALL(); Mutex::Autolock l(mLock); status_t res = OK; + if (maxCount < 0) { + ALOGE("%s: Stream %d: Can't prepare stream if max buffer count (%d) is < 0", + __FUNCTION__, mId, maxCount); + return BAD_VALUE; + } + // This function should be only called when the stream is configured already. if (mState != STATE_CONFIGURED) { ALOGE("%s: Stream %d: Can't prepare stream if stream is not in CONFIGURED " @@ -279,9 +286,19 @@ status_t Camera3Stream::startPrepare() { return INVALID_OPERATION; } + + + size_t pipelineMax = getBufferCountLocked(); + size_t clampedCount = (pipelineMax < static_cast(maxCount)) ? + pipelineMax : static_cast(maxCount); + size_t bufferCount = (maxCount == Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) ? + pipelineMax : clampedCount; + + mPrepared = bufferCount <= mLastMaxCount; + if (mPrepared) return OK; - size_t bufferCount = getBufferCountLocked(); + mLastMaxCount = bufferCount; mPreparedBuffers.insertAt(camera3_stream_buffer_t(), /*index*/0, bufferCount); mPreparedBufferIdx = 0; diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index bab2177..753280b 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -188,7 +188,9 @@ class Camera3Stream : /** * Start stream preparation. May only be called in the CONFIGURED state, - * when no valid buffers have yet been returned to this stream. + * when no valid buffers have yet been returned to this stream. Prepares + * up to maxCount buffers, or the maximum number of buffers needed by the + * pipeline if maxCount is ALLOCATE_PIPELINE_MAX. * * If no prepartion is necessary, returns OK and does not transition to * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions @@ -204,7 +206,7 @@ class Camera3Stream : * INVALID_OPERATION if called when not in CONFIGURED state, or a * valid buffer has already been returned to this stream. */ - status_t startPrepare(); + status_t startPrepare(int maxCount); /** * Check if the stream is mid-preparing. @@ -444,6 +446,9 @@ class Camera3Stream : Vector mPreparedBuffers; size_t mPreparedBufferIdx; + // Number of buffers allocated on last prepare call. + int mLastMaxCount; + }; // class Camera3Stream }; // namespace camera3 diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index c086eaf..54009ae 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h @@ -34,6 +34,11 @@ class StatusTracker; */ class Camera3StreamInterface : public virtual RefBase { public: + + enum { + ALLOCATE_PIPELINE_MAX = 0, // Allocate max buffers used by a given surface + }; + /** * Get the stream's ID */ @@ -98,7 +103,9 @@ class Camera3StreamInterface : public virtual RefBase { /** * Start stream preparation. May only be called in the CONFIGURED state, - * when no valid buffers have yet been returned to this stream. + * when no valid buffers have yet been returned to this stream. Prepares + * up to maxCount buffers, or the maximum number of buffers needed by the + * pipeline if maxCount is ALLOCATE_PIPELINE_MAX. * * If no prepartion is necessary, returns OK and does not transition to * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions @@ -112,7 +119,7 @@ class Camera3StreamInterface : public virtual RefBase { * INVALID_OPERATION if called when not in CONFIGURED state, or a * valid buffer has already been returned to this stream. */ - virtual status_t startPrepare() = 0; + virtual status_t startPrepare(int maxCount) = 0; /** * Check if the stream is mid-preparing. -- cgit v1.1 From 412fe56cd7cf7d73bc5d2bcc3f635bc650d18de9 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Thu, 20 Aug 2015 17:08:32 -0700 Subject: CameraService: Notify camera service proxy of device status Send the camera proxy service in system server updates to camera device state: opened/closed/active/idle. Bug: 23393557 Change-Id: Id7c70f134821efa34af8f6e7b4caa4c2ab128ebc --- services/camera/libcameraservice/CameraService.cpp | 27 +++++++++++++++++++--- services/camera/libcameraservice/CameraService.h | 10 ++++++++ .../camera/libcameraservice/api1/Camera2Client.cpp | 2 ++ .../camera/libcameraservice/api1/CameraClient.cpp | 19 +++++++++++++-- .../libcameraservice/api2/CameraDeviceClient.cpp | 2 ++ .../libcameraservice/api2/CameraDeviceClient.h | 1 + .../libcameraservice/common/Camera2ClientBase.cpp | 17 +++++++++++++- .../libcameraservice/common/Camera2ClientBase.h | 2 ++ 8 files changed, 74 insertions(+), 6 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 43a8ec4..7128df7 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -250,13 +249,19 @@ void CameraService::onFirstRef() CameraService::pingCameraServiceProxy(); } -void CameraService::pingCameraServiceProxy() { +sp CameraService::getCameraServiceProxy() { sp sm = defaultServiceManager(); sp binder = sm->getService(String16("media.camera.proxy")); if (binder == nullptr) { - return; + return nullptr; } sp proxyBinder = interface_cast(binder); + return proxyBinder; +} + +void CameraService::pingCameraServiceProxy() { + sp proxyBinder = getCameraServiceProxy(); + if (proxyBinder == nullptr) return; proxyBinder->pingForUserUpdate(); } @@ -1948,6 +1953,10 @@ status_t CameraService::BasicClient::startCameraOps() { mCameraService->updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE, String8::format("%d", mCameraId)); + // Transition device state to OPEN + mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN, + String8::format("%d", mCameraId)); + return OK; } @@ -1966,6 +1975,10 @@ status_t CameraService::BasicClient::finishCameraOps() { mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT, String8::format("%d", mCameraId), rejected); + // Transition device state to CLOSED + mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED, + String8::format("%d", mCameraId)); + // Notify flashlight that a camera device is closed. mCameraService->mFlashlight->deviceClosed( String8::format("%d", mCameraId)); @@ -2466,6 +2479,14 @@ void CameraService::updateStatus(ICameraServiceListener::Status status, const St }); } +void CameraService::updateProxyDeviceState(ICameraServiceProxy::CameraState newState, + const String8& cameraId) { + sp proxyBinder = getCameraServiceProxy(); + if (proxyBinder == nullptr) return; + String16 id(cameraId); + proxyBinder->notifyCameraState(id, newState); +} + status_t CameraService::getTorchStatusLocked( const String8& cameraId, ICameraServiceListener::TorchStatus *status) const { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 7f4d43f..894767a 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -164,6 +165,14 @@ public: void playSound(sound_kind kind); void releaseSound(); + /** + * Update the state of a given camera device (open/close/active/idle) with + * the camera proxy service in the system service + */ + static void updateProxyDeviceState( + ICameraServiceProxy::CameraState newState, + const String8& cameraId); + ///////////////////////////////////////////////////////////////////// // CameraDeviceFactory functionality int getDeviceVersion(int cameraId, int* facing = NULL); @@ -728,6 +737,7 @@ private: static String8 toString(std::set intSet); + static sp getCameraServiceProxy(); static void pingCameraServiceProxy(); }; diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 36e99dd..48b5a26 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -1912,6 +1912,8 @@ void Camera2Client::notifyShutter(const CaptureResultExtras& resultExtras, ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64, __FUNCTION__, resultExtras.requestId, timestamp); mCaptureSequencer->notifyShutter(resultExtras, timestamp); + + Camera2ClientBase::notifyShutter(resultExtras, timestamp); } camera2::SharedParameters& Camera2Client::getParameters() { diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp index e552633..38e35cd 100644 --- a/services/camera/libcameraservice/api1/CameraClient.cpp +++ b/services/camera/libcameraservice/api1/CameraClient.cpp @@ -251,6 +251,9 @@ void CameraClient::disconnect() { // Turn off all messages. disableMsgType(CAMERA_MSG_ALL_MSGS); mHardware->stopPreview(); + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", mCameraId)); mHardware->cancelPicture(); // Release the hardware resources. mHardware->release(); @@ -409,7 +412,11 @@ status_t CameraClient::startPreviewMode() { } mHardware->setPreviewWindow(mPreviewWindow); result = mHardware->startPreview(); - + if (result == NO_ERROR) { + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_ACTIVE, + String8::format("%d", mCameraId)); + } return result; } @@ -449,7 +456,9 @@ void CameraClient::stopPreview() { disableMsgType(CAMERA_MSG_PREVIEW_FRAME); mHardware->stopPreview(); - + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", mCameraId)); mPreviewBuffer.clear(); } @@ -790,6 +799,12 @@ void CameraClient::handleShutter(void) { } disableMsgType(CAMERA_MSG_SHUTTER); + // Shutters only happen in response to takePicture, so mark device as + // idle now, until preview is restarted + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", mCameraId)); + mLock.unlock(); } diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index f6a0221..0c531c3 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -836,6 +836,7 @@ void CameraDeviceClient::notifyIdle() { if (remoteCb != 0) { remoteCb->onDeviceIdle(); } + Camera2ClientBase::notifyIdle(); } void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras, @@ -845,6 +846,7 @@ void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras, if (remoteCb != 0) { remoteCb->onCaptureStarted(resultExtras, timestamp); } + Camera2ClientBase::notifyShutter(resultExtras, timestamp); } void CameraDeviceClient::notifyPrepared(int streamId) { diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 0b73f6c..d1e692c 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -192,6 +192,7 @@ private: Vector mStreamingRequestList; int32_t mRequestIdCounter; + }; }; // namespace android diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp index ba0b264..5732f80 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp @@ -55,7 +55,8 @@ Camera2ClientBase::Camera2ClientBase( TClientBase(cameraService, remoteCallback, clientPackageName, cameraId, cameraFacing, clientPid, clientUid, servicePid), mSharedCameraCallbacks(remoteCallback), - mDeviceVersion(cameraService->getDeviceVersion(cameraId)) + mDeviceVersion(cameraService->getDeviceVersion(cameraId)), + mDeviceActive(false) { ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId, String8(clientPackageName).string(), clientPid, clientUid); @@ -235,6 +236,13 @@ void Camera2ClientBase::notifyError( template void Camera2ClientBase::notifyIdle() { + if (mDeviceActive) { + getCameraService()->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", TClientBase::mCameraId)); + } + mDeviceActive = false; + ALOGV("Camera device is now idle"); } @@ -244,6 +252,13 @@ void Camera2ClientBase::notifyShutter(const CaptureResultExtras& re (void)resultExtras; (void)timestamp; + if (!mDeviceActive) { + getCameraService()->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_ACTIVE, + String8::format("%d", TClientBase::mCameraId)); + } + mDeviceActive = true; + ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64, __FUNCTION__, resultExtras.requestId, timestamp); } diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h index f1cacdf..220c5ad 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.h +++ b/services/camera/libcameraservice/common/Camera2ClientBase.h @@ -136,6 +136,8 @@ protected: status_t checkPid(const char *checkLocation) const; virtual void detachDevice(); + + bool mDeviceActive; }; }; // namespace android -- cgit v1.1 From cafe86a9cb6625bb1ec6383e16e28e4c9e455f87 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 14 Aug 2015 09:34:50 -0700 Subject: Do not acknowledge flush() on start() for static tracks Bug: 22938515 Change-Id: I1de653de169a3fbbaa693da6057897ea57772447 --- services/audioflinger/Tracks.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'services') diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index f7da209..d058255 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -712,9 +712,12 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev // But in this case we know the mixer thread (whether normal mixer or fast mixer) // isn't looking at this track yet: we still hold the normal mixer thread lock, // and for fast tracks the track is not yet in the fast mixer thread's active set. - ServerProxy::Buffer buffer; - buffer.mFrameCount = 1; - (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); + // TODO: remove race condition on stop() followed by start(). + if (mSharedBuffer == 0) { // only streaming tracks use flush(). + ServerProxy::Buffer buffer; + buffer.mFrameCount = 1; + (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); + } } } else { status = BAD_VALUE; -- cgit v1.1 From efff1c4ba2bf195d97de2fd5718b708e4b942901 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 28 Aug 2015 16:27:27 -0700 Subject: Camera3Device: Don't hold mutex during HAL device close. The HAL device shutdown will likely need to wait on various events and queues to drain, and holding the mutex will prevent, for example, error notifications from being processed. This can lead to deadlocks. Bug: 23501571 Change-Id: I873ac23ef30545adf533e7839445448573ab5048 --- .../libcameraservice/device3/Camera3Device.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index e4d75cb..ec3591f 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -285,19 +285,27 @@ status_t Camera3Device::disconnect() { mStatusTracker->join(); } + camera3_device_t *hal3Device; { Mutex::Autolock l(mLock); mRequestThread.clear(); mStatusTracker.clear(); - if (mHal3Device != NULL) { - ATRACE_BEGIN("camera3->close"); - mHal3Device->common.close(&mHal3Device->common); - ATRACE_END(); - mHal3Device = NULL; - } + hal3Device = mHal3Device; + } + + // Call close without internal mutex held, as the HAL close may need to + // wait on assorted callbacks,etc, to complete before it can return. + if (hal3Device != NULL) { + ATRACE_BEGIN("camera3->close"); + hal3Device->common.close(&hal3Device->common); + ATRACE_END(); + } + { + Mutex::Autolock l(mLock); + mHal3Device = NULL; internalUpdateStatusLocked(STATUS_UNINITIALIZED); } -- cgit v1.1 From fe751bea0d3eedd6e817aebf4e457425b82e7117 Mon Sep 17 00:00:00 2001 From: Chien-Yu Chen Date: Tue, 1 Sep 2015 14:16:44 -0700 Subject: Camera: Fix flashlight deadlock Use a dedicated mutex for torch UID map so it won't cause a deadlock after flashlight app gets killed while the torch is on. Bug: 23722318 Change-Id: I228377aa0412052d56b6b948361d9abaecbbc686 --- services/camera/libcameraservice/CameraService.cpp | 4 ++-- services/camera/libcameraservice/CameraService.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 43a8ec4..9a1101a 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -363,7 +363,7 @@ void CameraService::onTorchStatusChangedLocked(const String8& cameraId, { // Update battery life logging for flashlight - Mutex::Autolock al(mTorchClientMapMutex); + Mutex::Autolock al(mTorchUidMapMutex); auto iter = mTorchUidMap.find(cameraId); if (iter != mTorchUidMap.end()) { int oldUid = iter->second.second; @@ -1262,7 +1262,7 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, { // Update UID map - this is used in the torch status changed callbacks, so must be done // before setTorchMode - Mutex::Autolock al(mTorchClientMapMutex); + Mutex::Autolock al(mTorchUidMapMutex); if (mTorchUidMap.find(id) == mTorchUidMap.end()) { mTorchUidMap[id].first = uid; mTorchUidMap[id].second = uid; diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 7f4d43f..b56c161 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -648,8 +648,10 @@ private: sp mFlashlight; // guard mTorchStatusMap Mutex mTorchStatusMutex; - // guard mTorchClientMap, mTorchUidMap + // guard mTorchClientMap Mutex mTorchClientMapMutex; + // guard mTorchUidMap + Mutex mTorchUidMapMutex; // camera id -> torch status KeyedVector mTorchStatusMap; // camera id -> torch client binder -- cgit v1.1 From 52aad85627f5216e7a3d9db425d2cc409f998a01 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Thu, 3 Sep 2015 12:24:24 -0700 Subject: CameraService: Treat TOP_SLEEPING same as TOP for priority. When arbitrating between camera clients, treat processes in the TOP_SLEEPING state with the same high priority as processes in the TOP state. This resolves race conditions during lock screen handoffs between clients such as face unlock (a bound foreground process) and a secure camera app (the topmost activity, but transitioning from TOP_SLEEPING to TOP asynchronously from the activity lifecycle callbacks). Bug: 23731720 Change-Id: I92c3f8f561c7725627826c0ba3dc926e99af746c --- services/camera/libcameraservice/CameraService.cpp | 5 +++++ services/camera/libcameraservice/CameraService.h | 2 ++ 2 files changed, 7 insertions(+) (limited to 'services') diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index d289704..f5a0887 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -602,6 +602,11 @@ int CameraService::getCameraPriorityFromProcState(int procState) { procState); return -1; } + // Treat sleeping TOP processes the same as regular TOP processes, for + // access priority. This is important for lock-screen camera launch scenarios + if (procState == PROCESS_STATE_TOP_SLEEPING) { + procState = PROCESS_STATE_TOP; + } return INT_MAX - procState; } diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index a8c6b6c..330a19d 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -75,6 +75,8 @@ public: // Process state (mirrors frameworks/base/core/java/android/app/ActivityManager.java) static const int PROCESS_STATE_NONEXISTENT = -1; + static const int PROCESS_STATE_TOP = 2; + static const int PROCESS_STATE_TOP_SLEEPING = 5; // 3 second busy timeout when other clients are connecting static const nsecs_t DEFAULT_CONNECT_TIMEOUT_NS = 3000000000; -- cgit v1.1 From 85a6455f269d79adf9bf48d757a4b1b3c81cf760 Mon Sep 17 00:00:00 2001 From: Chien-Yu Chen Date: Fri, 28 Aug 2015 15:46:12 -0700 Subject: Camera3Device: Support batch requests Refactor request threadLoop to three parts: waiting for next batch of requests, preparing HAL requests and output buffers for next batch of requests, and submitting the batch of requests to HAL. Set the batch size to the size of the request list if it's a video recording request in a high speed video configuration. Add a flush lock so that HAL's flush() won't be called while submitting a batch of requests. Bug: 23360060 Change-Id: Icd395b1f955a9b336eec6fa5aff6b17741ce08c7 --- .../libcameraservice/device3/Camera3Device.cpp | 504 +++++++++++++-------- .../libcameraservice/device3/Camera3Device.h | 47 +- .../device3/Camera3DummyStream.cpp | 4 + .../libcameraservice/device3/Camera3DummyStream.h | 5 + .../device3/Camera3OutputStream.cpp | 11 + .../libcameraservice/device3/Camera3OutputStream.h | 5 + .../device3/Camera3OutputStreamInterface.h | 5 + .../libcameraservice/device3/Camera3Stream.cpp | 5 +- 8 files changed, 387 insertions(+), 199 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index ec3591f..98d0a41 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -565,6 +565,18 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); } + + // Setup batch size if this is a high speed video recording request. + if (mIsConstrainedHighSpeedConfiguration && requestList->size() > 0) { + auto firstRequest = requestList->begin(); + for (auto& outputStream : (*firstRequest)->mOutputStreams) { + if (outputStream->isVideoStream()) { + (*firstRequest)->mBatchSize = requestList->size(); + break; + } + } + } + return OK; } @@ -1406,7 +1418,7 @@ status_t Camera3Device::flush(int64_t *frameNumber) { status_t res; if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { - res = mHal3Device->ops->flush(mHal3Device); + res = mRequestThread->flush(); } else { Mutex::Autolock l(mLock); res = waitUntilDrainedLocked(); @@ -1595,6 +1607,7 @@ sp Camera3Device::createCaptureRequest( newRequest->mOutputStreams.push(stream); } newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); + newRequest->mBatchSize = 1; return newRequest; } @@ -2766,6 +2779,17 @@ status_t Camera3Device::RequestThread::clear( return OK; } +status_t Camera3Device::RequestThread::flush() { + ATRACE_CALL(); + Mutex::Autolock l(mFlushLock); + + if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { + return mHal3Device->ops->flush(mHal3Device); + } + + return -ENOTSUP; +} + void Camera3Device::RequestThread::setPaused(bool paused) { Mutex::Autolock l(mPauseLock); mDoPause = paused; @@ -2856,7 +2880,7 @@ void Camera3Device::overrideResultForPrecaptureCancel( } bool Camera3Device::RequestThread::threadLoop() { - + ATRACE_CALL(); status_t res; // Handle paused state. @@ -2864,203 +2888,246 @@ bool Camera3Device::RequestThread::threadLoop() { return true; } - // Get work to do - - sp nextRequest = waitForNextRequest(); - if (nextRequest == NULL) { + // Get next batch of requests. + Vector nextRequests; + waitForNextRequestBatch(&nextRequests); + const size_t numRequests = nextRequests.size(); + if (numRequests == 0) { return true; } - // Create request to HAL - camera3_capture_request_t request = camera3_capture_request_t(); - request.frame_number = nextRequest->mResultExtras.frameNumber; - Vector outputBuffers; - - // Get the request ID, if any - int requestId; - camera_metadata_entry_t requestIdEntry = - nextRequest->mSettings.find(ANDROID_REQUEST_ID); + // Get the latest request ID, if any + int latestRequestId; + camera_metadata_entry_t requestIdEntry = nextRequests[nextRequests.size() - 1]. + captureRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { - requestId = requestIdEntry.data.i32[0]; + latestRequestId = requestIdEntry.data.i32[0]; } else { - ALOGW("%s: Did not have android.request.id set in the request", - __FUNCTION__); - requestId = NAME_NOT_FOUND; + ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__); + latestRequestId = NAME_NOT_FOUND; } - // Insert any queued triggers (before metadata is locked) - int32_t triggerCount; - res = insertTriggers(nextRequest); - if (res < 0) { - SET_ERR("RequestThread: Unable to insert triggers " - "(capture request %d, HAL device: %s (%d)", - request.frame_number, strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); + // Prepare a batch of HAL requests and output buffers. + res = prepareHalRequests(&nextRequests); + if (res == TIMED_OUT) { + // Not a fatal error if getting output buffers time out. + cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ true); + return true; + } else if (res != OK) { + cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); return false; } - triggerCount = res; - bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); + // Inform waitUntilRequestProcessed thread of a new request ID + { + Mutex::Autolock al(mLatestRequestMutex); + + mLatestRequestId = latestRequestId; + mLatestRequestSignal.signal(); + } + + // Submit a batch of requests to HAL. + // Use flush lock only when submitting multilple requests in a batch. + // TODO: The problem with flush lock is flush() will be blocked by process_capture_request() + // which may take a long time to finish so synchronizing flush() and + // process_capture_request() defeats the purpose of cancelling requests ASAP with flush(). + // For now, only synchronize for high speed recording and we should figure something out for + // removing the synchronization. + bool useFlushLock = nextRequests.size() > 1; + + if (useFlushLock) { + mFlushLock.lock(); + } + + ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__, + nextRequests.size()); + for (auto& nextRequest : nextRequests) { + // Submit request and block until ready for next one + ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number); + ATRACE_BEGIN("camera3->process_capture_request"); + res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest); + ATRACE_END(); - // If the request is the same as last, or we had triggers last time - if (mPrevRequest != nextRequest || triggersMixedIn) { - /** - * HAL workaround: - * Insert a dummy trigger ID if a trigger is set but no trigger ID is - */ - res = addDummyTriggerIds(nextRequest); if (res != OK) { - SET_ERR("RequestThread: Unable to insert dummy trigger IDs " - "(capture request %d, HAL device: %s (%d)", - request.frame_number, strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); + // Should only get a failure here for malformed requests or device-level + // errors, so consider all errors fatal. Bad metadata failures should + // come through notify. + SET_ERR("RequestThread: Unable to submit capture request %d to HAL" + " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), + res); + cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); + if (useFlushLock) { + mFlushLock.unlock(); + } return false; } - /** - * The request should be presorted so accesses in HAL - * are O(logn). Sidenote, sorting a sorted metadata is nop. - */ - nextRequest->mSettings.sort(); - request.settings = nextRequest->mSettings.getAndLock(); - mPrevRequest = nextRequest; - ALOGVV("%s: Request settings are NEW", __FUNCTION__); - - IF_ALOGV() { - camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); - find_camera_metadata_ro_entry( - request.settings, - ANDROID_CONTROL_AF_TRIGGER, - &e - ); - if (e.count > 0) { - ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", - __FUNCTION__, - request.frame_number, - e.data.u8[0]); - } - } - } else { - // leave request.settings NULL to indicate 'reuse latest given' - ALOGVV("%s: Request settings are REUSED", - __FUNCTION__); - } + // Mark that the request has be submitted successfully. + nextRequest.submitted = true; - uint32_t totalNumBuffers = 0; + // Update the latest request sent to HAL + if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged + Mutex::Autolock al(mLatestRequestMutex); - // Fill in buffers - if (nextRequest->mInputStream != NULL) { - request.input_buffer = &nextRequest->mInputBuffer; - totalNumBuffers += 1; - } else { - request.input_buffer = NULL; - } + camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings); + mLatestRequest.acquire(cloned); + } + + if (nextRequest.halRequest.settings != NULL) { + nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings); + } - outputBuffers.insertAt(camera3_stream_buffer_t(), 0, - nextRequest->mOutputStreams.size()); - request.output_buffers = outputBuffers.array(); - for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) { - res = nextRequest->mOutputStreams.editItemAt(i)-> - getBuffer(&outputBuffers.editItemAt(i)); + // Remove any previously queued triggers (after unlock) + res = removeTriggers(mPrevRequest); if (res != OK) { - // Can't get output buffer from gralloc queue - this could be due to - // abandoned queue or other consumer misbehavior, so not a fatal - // error - ALOGE("RequestThread: Can't get output buffer, skipping request:" - " %s (%d)", strerror(-res), res); - { - Mutex::Autolock l(mRequestLock); - if (mListener != NULL) { - mListener->notifyError( - ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, - nextRequest->mResultExtras); - } + SET_ERR("RequestThread: Unable to remove triggers " + "(capture request %d, HAL device: %s (%d)", + nextRequest.halRequest.frame_number, strerror(-res), res); + cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); + if (useFlushLock) { + mFlushLock.unlock(); } - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return true; + return false; } - request.num_output_buffers++; } - totalNumBuffers += request.num_output_buffers; - // Log request in the in-flight queue - sp parent = mParent.promote(); - if (parent == NULL) { - // Should not happen, and nowhere to send errors to, so just log it - CLOGE("RequestThread: Parent is gone"); - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return false; + if (useFlushLock) { + mFlushLock.unlock(); } - res = parent->registerInFlight(request.frame_number, - totalNumBuffers, nextRequest->mResultExtras, - /*hasInput*/request.input_buffer != NULL, - nextRequest->mAeTriggerCancelOverride); - ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 - ", burstId = %" PRId32 ".", - __FUNCTION__, - nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, - nextRequest->mResultExtras.burstId); - if (res != OK) { - SET_ERR("RequestThread: Unable to register new in-flight request:" - " %s (%d)", strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return false; + // Unset as current request + { + Mutex::Autolock l(mRequestLock); + mNextRequests.clear(); } - // Inform waitUntilRequestProcessed thread of a new request ID - { - Mutex::Autolock al(mLatestRequestMutex); + return true; +} - mLatestRequestId = requestId; - mLatestRequestSignal.signal(); +status_t Camera3Device::RequestThread::prepareHalRequests(Vector *nextRequests) { + ATRACE_CALL(); + + if (nextRequests == nullptr) { + return BAD_VALUE; } - // Submit request and block until ready for next one - ATRACE_ASYNC_BEGIN("frame capture", request.frame_number); - ATRACE_BEGIN("camera3->process_capture_request"); - res = mHal3Device->ops->process_capture_request(mHal3Device, &request); - ATRACE_END(); + for (auto& nextRequest : *nextRequests) { + sp captureRequest = nextRequest.captureRequest; + camera3_capture_request_t* halRequest = &nextRequest.halRequest; + Vector* outputBuffers = &nextRequest.outputBuffers; - if (res != OK) { - // Should only get a failure here for malformed requests or device-level - // errors, so consider all errors fatal. Bad metadata failures should - // come through notify. - SET_ERR("RequestThread: Unable to submit capture request %d to HAL" - " device: %s (%d)", request.frame_number, strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return false; - } + // Prepare a request to HAL + halRequest->frame_number = captureRequest->mResultExtras.frameNumber; - // Update the latest request sent to HAL - if (request.settings != NULL) { // Don't update them if they were unchanged - Mutex::Autolock al(mLatestRequestMutex); + // Insert any queued triggers (before metadata is locked) + status_t res = insertTriggers(captureRequest); - camera_metadata_t* cloned = clone_camera_metadata(request.settings); - mLatestRequest.acquire(cloned); - } + if (res < 0) { + SET_ERR("RequestThread: Unable to insert triggers " + "(capture request %d, HAL device: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } + int triggerCount = res; + bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); + mPrevTriggers = triggerCount; - if (request.settings != NULL) { - nextRequest->mSettings.unlock(request.settings); - } + // If the request is the same as last, or we had triggers last time + if (mPrevRequest != captureRequest || triggersMixedIn) { + /** + * HAL workaround: + * Insert a dummy trigger ID if a trigger is set but no trigger ID is + */ + res = addDummyTriggerIds(captureRequest); + if (res != OK) { + SET_ERR("RequestThread: Unable to insert dummy trigger IDs " + "(capture request %d, HAL device: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } - // Unset as current request - { - Mutex::Autolock l(mRequestLock); - mNextRequest.clear(); - } + /** + * The request should be presorted so accesses in HAL + * are O(logn). Sidenote, sorting a sorted metadata is nop. + */ + captureRequest->mSettings.sort(); + halRequest->settings = captureRequest->mSettings.getAndLock(); + mPrevRequest = captureRequest; + ALOGVV("%s: Request settings are NEW", __FUNCTION__); + + IF_ALOGV() { + camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); + find_camera_metadata_ro_entry( + halRequest->settings, + ANDROID_CONTROL_AF_TRIGGER, + &e + ); + if (e.count > 0) { + ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", + __FUNCTION__, + halRequest->frame_number, + e.data.u8[0]); + } + } + } else { + // leave request.settings NULL to indicate 'reuse latest given' + ALOGVV("%s: Request settings are REUSED", + __FUNCTION__); + } - // Remove any previously queued triggers (after unlock) - res = removeTriggers(mPrevRequest); - if (res != OK) { - SET_ERR("RequestThread: Unable to remove triggers " - "(capture request %d, HAL device: %s (%d)", - request.frame_number, strerror(-res), res); - return false; + uint32_t totalNumBuffers = 0; + + // Fill in buffers + if (captureRequest->mInputStream != NULL) { + halRequest->input_buffer = &captureRequest->mInputBuffer; + totalNumBuffers += 1; + } else { + halRequest->input_buffer = NULL; + } + + outputBuffers->insertAt(camera3_stream_buffer_t(), 0, + captureRequest->mOutputStreams.size()); + halRequest->output_buffers = outputBuffers->array(); + for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) { + res = captureRequest->mOutputStreams.editItemAt(i)-> + getBuffer(&outputBuffers->editItemAt(i)); + if (res != OK) { + // Can't get output buffer from gralloc queue - this could be due to + // abandoned queue or other consumer misbehavior, so not a fatal + // error + ALOGE("RequestThread: Can't get output buffer, skipping request:" + " %s (%d)", strerror(-res), res); + + return TIMED_OUT; + } + halRequest->num_output_buffers++; + } + totalNumBuffers += halRequest->num_output_buffers; + + // Log request in the in-flight queue + sp parent = mParent.promote(); + if (parent == NULL) { + // Should not happen, and nowhere to send errors to, so just log it + CLOGE("RequestThread: Parent is gone"); + return INVALID_OPERATION; + } + res = parent->registerInFlight(halRequest->frame_number, + totalNumBuffers, captureRequest->mResultExtras, + /*hasInput*/halRequest->input_buffer != NULL, + captureRequest->mAeTriggerCancelOverride); + ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 + ", burstId = %" PRId32 ".", + __FUNCTION__, + captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber, + captureRequest->mResultExtras.burstId); + if (res != OK) { + SET_ERR("RequestThread: Unable to register new in-flight request:" + " %s (%d)", strerror(-res), res); + return INVALID_OPERATION; + } } - mPrevTriggers = triggerCount; - return true; + return OK; } CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { @@ -3075,11 +3142,11 @@ bool Camera3Device::RequestThread::isStreamPending( sp& stream) { Mutex::Autolock l(mRequestLock); - if (mNextRequest != nullptr) { - for (const auto& s : mNextRequest->mOutputStreams) { + for (const auto& nextRequest : mNextRequests) { + for (const auto& s : nextRequest->mOutputStreams) { if (stream == s) return true; } - if (stream == mNextRequest->mInputStream) return true; + if (stream == nextRequest->mInputStream) return true; } for (const auto& request : mRequestQueue) { @@ -3099,37 +3166,104 @@ bool Camera3Device::RequestThread::isStreamPending( return false; } -void Camera3Device::RequestThread::cleanUpFailedRequest( - camera3_capture_request_t &request, - sp &nextRequest, - Vector &outputBuffers) { - - if (request.settings != NULL) { - nextRequest->mSettings.unlock(request.settings); - } - if (nextRequest->mInputStream != NULL) { - nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; - nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); +void Camera3Device::RequestThread::cleanUpFailedRequests(Vector *nextRequests, + bool sendRequestError) { + if (nextRequests == nullptr) { + return; } - for (size_t i = 0; i < request.num_output_buffers; i++) { - outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; - nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( - outputBuffers[i], 0); + + for (auto& nextRequest : *nextRequests) { + // Skip the ones that have been submitted successfully. + if (nextRequest.submitted) { + continue; + } + + sp captureRequest = nextRequest.captureRequest; + camera3_capture_request_t* halRequest = &nextRequest.halRequest; + Vector* outputBuffers = &nextRequest.outputBuffers; + + if (halRequest->settings != NULL) { + captureRequest->mSettings.unlock(halRequest->settings); + } + + if (captureRequest->mInputStream != NULL) { + captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; + captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer); + } + + for (size_t i = 0; i < halRequest->num_output_buffers; i++) { + outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; + captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0); + } + + if (sendRequestError) { + Mutex::Autolock l(mRequestLock); + if (mListener != NULL) { + mListener->notifyError( + ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, + captureRequest->mResultExtras); + } + } } Mutex::Autolock l(mRequestLock); - mNextRequest.clear(); + mNextRequests.clear(); + nextRequests->clear(); } -sp - Camera3Device::RequestThread::waitForNextRequest() { - status_t res; - sp nextRequest; +void Camera3Device::RequestThread::waitForNextRequestBatch(Vector *nextRequests) { + if (nextRequests == nullptr) { + return; + } // Optimized a bit for the simple steady-state case (single repeating // request), to avoid putting that request in the queue temporarily. Mutex::Autolock l(mRequestLock); + nextRequests->clear(); + assert(mNextRequests.empty()); + + NextRequest nextRequest; + nextRequest.captureRequest = waitForNextRequestLocked(); + if (nextRequest.captureRequest == nullptr) { + return; + } + + nextRequest.halRequest = camera3_capture_request_t(); + nextRequest.submitted = false; + nextRequests->add(nextRequest); + mNextRequests.push_back(nextRequest.captureRequest); + + // Wait for additional requests + const size_t batchSize = nextRequest.captureRequest->mBatchSize; + + for (size_t i = 1; i < batchSize; i++) { + NextRequest additionalRequest; + additionalRequest.captureRequest = waitForNextRequestLocked(); + if (additionalRequest.captureRequest == nullptr) { + break; + } + + additionalRequest.halRequest = camera3_capture_request_t(); + additionalRequest.submitted = false; + nextRequests->add(additionalRequest); + mNextRequests.push_back(additionalRequest.captureRequest); + } + + if (nextRequests->size() < batchSize) { + ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.", + nextRequests->size(), batchSize); + cleanUpFailedRequests(nextRequests, /*sendRequestError*/true); + } + + return; +} + +sp + Camera3Device::RequestThread::waitForNextRequestLocked() { + status_t res; + sp nextRequest; + while (mRequestQueue.empty()) { if (!mRepeatingRequests.empty()) { // Always atomically enqueue all requests in a repeating request @@ -3224,8 +3358,6 @@ sp handleAePrecaptureCancelRequest(nextRequest); - mNextRequest = nextRequest; - return nextRequest; } diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 1f39940..a3abbaf 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -264,6 +264,11 @@ class Camera3Device : // Used to cancel AE precapture trigger for devices doesn't support // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL AeTriggerCancelOverride_t mAeTriggerCancelOverride; + // The number of requests that should be submitted to HAL at a time. + // For example, if batch size is 8, this request and the following 7 + // requests will be submitted to HAL at a time. The batch size for + // the following 7 requests will be ignored by the request thread. + int mBatchSize; }; typedef List > RequestList; @@ -441,6 +446,11 @@ class Camera3Device : int64_t *lastFrameNumber = NULL); /** + * Flush all pending requests in HAL. + */ + status_t flush(); + + /** * Queue a trigger to be dispatched with the next outgoing * process_capture_request. The settings for that request only * will be temporarily rewritten to add the trigger tag/value. @@ -501,16 +511,28 @@ class Camera3Device : static const nsecs_t kRequestTimeout = 50e6; // 50 ms - // Waits for a request, or returns NULL if times out. - sp waitForNextRequest(); + // Used to prepare a batch of requests. + struct NextRequest { + sp captureRequest; + camera3_capture_request_t halRequest; + Vector outputBuffers; + bool submitted; + }; + + // Wait for the next batch of requests. + void waitForNextRequestBatch(Vector *nextRequests); - // Return buffers, etc, for a request that couldn't be fully - // constructed. The buffers will be returned in the ERROR state - // to mark them as not having valid data. - // All arguments will be modified. - void cleanUpFailedRequest(camera3_capture_request_t &request, - sp &nextRequest, - Vector &outputBuffers); + // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold. + sp waitForNextRequestLocked(); + + // Prepare a HAL request and output buffers. Return TIMED_OUT if getting any output buffer + // timed out. If an error is returned, the caller should clean up the pending request batch. + status_t prepareHalRequests(Vector *nextRequests); + + // Return buffers, etc, for a request that couldn't be fully constructed and send request + // errors if sendRequestError is true. The buffers will be returned in the ERROR state + // to mark them as not having valid data. nextRequests will be modified. + void cleanUpFailedRequests(Vector *nextRequests, bool sendRequestError); // Pause handling bool waitIfPaused(); @@ -539,10 +561,13 @@ class Camera3Device : Condition mRequestSignal; RequestList mRequestQueue; RequestList mRepeatingRequests; - // The next request being prepped for submission to the HAL, no longer + // The next requests being prepped for submission to the HAL, no longer // on the request queue. Read-only even with mRequestLock held, outside // of threadLoop - sp mNextRequest; + RequestList mNextRequests; + + // To protect flush() and sending a request batch to HAL. + Mutex mFlushLock; bool mReconfigured; diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp index ecb8ac8..1d9d04f 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp @@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const { return OK; } +bool Camera3DummyStream::isVideoStream() const { + return false; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h index 3a3dbf4..97c0c96 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.h +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h @@ -54,6 +54,11 @@ class Camera3DummyStream : status_t setTransform(int transform); + /** + * Return if this output stream is for video encoding. + */ + bool isVideoStream() const; + protected: /** diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 8c611d5..3f0a736 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -426,6 +426,17 @@ status_t Camera3OutputStream::getEndpointUsage(uint32_t *usage) const { return res; } +bool Camera3OutputStream::isVideoStream() const { + uint32_t usage = 0; + status_t res = getEndpointUsage(&usage); + if (res != OK) { + ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res); + return false; + } + + return (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h index 941d693..3c083ec 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h @@ -64,6 +64,11 @@ class Camera3OutputStream : */ status_t setTransform(int transform); + /** + * Return if this output stream is for video encoding. + */ + bool isVideoStream() const; + protected: Camera3OutputStream(int id, camera3_stream_type_t type, uint32_t width, uint32_t height, int format, diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h index aae72cf..df89b34 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h @@ -34,6 +34,11 @@ class Camera3OutputStreamInterface : public virtual Camera3StreamInterface { * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. */ virtual status_t setTransform(int transform) = 0; + + /** + * Return if this output stream is for video encoding. + */ + virtual bool isVideoStream() const = 0; }; } // namespace camera3 diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 7163d62..691764f 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -455,8 +455,9 @@ status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration); if (res != OK) { if (res == TIMED_OUT) { - ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__, - kWaitForBufferDuration / 1000000LL); + ALOGE("%s: wait for output buffer return timed out after %lldms (max_buffers %d)", + __FUNCTION__, kWaitForBufferDuration / 1000000LL, + camera3_stream::max_buffers); } return res; } -- cgit v1.1 From 57ea29251d93c9423030de387573142064366a30 Mon Sep 17 00:00:00 2001 From: Chien-Yu Chen Date: Fri, 4 Sep 2015 12:58:56 -0700 Subject: Camera3Device: Clean up next request batch variable Make the Vector of next requests a RequestThread member variable to avoid memory allocation in every threadloop. Bug: 23360060 Change-Id: I4f33e5c49f0f4deb1f9f45bada0909da748849e4 --- .../libcameraservice/device3/Camera3Device.cpp | 69 +++++++++------------- .../libcameraservice/device3/Camera3Device.h | 24 ++++---- 2 files changed, 41 insertions(+), 52 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 98d0a41..433a745 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -2888,17 +2888,15 @@ bool Camera3Device::RequestThread::threadLoop() { return true; } - // Get next batch of requests. - Vector nextRequests; - waitForNextRequestBatch(&nextRequests); - const size_t numRequests = nextRequests.size(); - if (numRequests == 0) { + // Wait for the next batch of requests. + waitForNextRequestBatch(); + if (mNextRequests.size() == 0) { return true; } // Get the latest request ID, if any int latestRequestId; - camera_metadata_entry_t requestIdEntry = nextRequests[nextRequests.size() - 1]. + camera_metadata_entry_t requestIdEntry = mNextRequests[mNextRequests.size() - 1]. captureRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { latestRequestId = requestIdEntry.data.i32[0]; @@ -2908,13 +2906,13 @@ bool Camera3Device::RequestThread::threadLoop() { } // Prepare a batch of HAL requests and output buffers. - res = prepareHalRequests(&nextRequests); + res = prepareHalRequests(); if (res == TIMED_OUT) { // Not a fatal error if getting output buffers time out. - cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ true); + cleanUpFailedRequests(/*sendRequestError*/ true); return true; } else if (res != OK) { - cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); + cleanUpFailedRequests(/*sendRequestError*/ false); return false; } @@ -2933,15 +2931,15 @@ bool Camera3Device::RequestThread::threadLoop() { // process_capture_request() defeats the purpose of cancelling requests ASAP with flush(). // For now, only synchronize for high speed recording and we should figure something out for // removing the synchronization. - bool useFlushLock = nextRequests.size() > 1; + bool useFlushLock = mNextRequests.size() > 1; if (useFlushLock) { mFlushLock.lock(); } ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__, - nextRequests.size()); - for (auto& nextRequest : nextRequests) { + mNextRequests.size()); + for (auto& nextRequest : mNextRequests) { // Submit request and block until ready for next one ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number); ATRACE_BEGIN("camera3->process_capture_request"); @@ -2955,7 +2953,7 @@ bool Camera3Device::RequestThread::threadLoop() { SET_ERR("RequestThread: Unable to submit capture request %d to HAL" " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), res); - cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); + cleanUpFailedRequests(/*sendRequestError*/ false); if (useFlushLock) { mFlushLock.unlock(); } @@ -2983,7 +2981,7 @@ bool Camera3Device::RequestThread::threadLoop() { SET_ERR("RequestThread: Unable to remove triggers " "(capture request %d, HAL device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), res); - cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false); + cleanUpFailedRequests(/*sendRequestError*/ false); if (useFlushLock) { mFlushLock.unlock(); } @@ -3004,14 +3002,10 @@ bool Camera3Device::RequestThread::threadLoop() { return true; } -status_t Camera3Device::RequestThread::prepareHalRequests(Vector *nextRequests) { +status_t Camera3Device::RequestThread::prepareHalRequests() { ATRACE_CALL(); - if (nextRequests == nullptr) { - return BAD_VALUE; - } - - for (auto& nextRequest : *nextRequests) { + for (auto& nextRequest : mNextRequests) { sp captureRequest = nextRequest.captureRequest; camera3_capture_request_t* halRequest = &nextRequest.halRequest; Vector* outputBuffers = &nextRequest.outputBuffers; @@ -3143,10 +3137,12 @@ bool Camera3Device::RequestThread::isStreamPending( Mutex::Autolock l(mRequestLock); for (const auto& nextRequest : mNextRequests) { - for (const auto& s : nextRequest->mOutputStreams) { - if (stream == s) return true; + if (!nextRequest.submitted) { + for (const auto& s : nextRequest.captureRequest->mOutputStreams) { + if (stream == s) return true; + } + if (stream == nextRequest.captureRequest->mInputStream) return true; } - if (stream == nextRequest->mInputStream) return true; } for (const auto& request : mRequestQueue) { @@ -3166,13 +3162,12 @@ bool Camera3Device::RequestThread::isStreamPending( return false; } -void Camera3Device::RequestThread::cleanUpFailedRequests(Vector *nextRequests, - bool sendRequestError) { - if (nextRequests == nullptr) { +void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) { + if (mNextRequests.empty()) { return; } - for (auto& nextRequest : *nextRequests) { + for (auto& nextRequest : mNextRequests) { // Skip the ones that have been submitted successfully. if (nextRequest.submitted) { continue; @@ -3208,19 +3203,13 @@ void Camera3Device::RequestThread::cleanUpFailedRequests(Vector *ne Mutex::Autolock l(mRequestLock); mNextRequests.clear(); - nextRequests->clear(); } -void Camera3Device::RequestThread::waitForNextRequestBatch(Vector *nextRequests) { - if (nextRequests == nullptr) { - return; - } - +void Camera3Device::RequestThread::waitForNextRequestBatch() { // Optimized a bit for the simple steady-state case (single repeating // request), to avoid putting that request in the queue temporarily. Mutex::Autolock l(mRequestLock); - nextRequests->clear(); assert(mNextRequests.empty()); NextRequest nextRequest; @@ -3231,8 +3220,7 @@ void Camera3Device::RequestThread::waitForNextRequestBatch(Vector * nextRequest.halRequest = camera3_capture_request_t(); nextRequest.submitted = false; - nextRequests->add(nextRequest); - mNextRequests.push_back(nextRequest.captureRequest); + mNextRequests.add(nextRequest); // Wait for additional requests const size_t batchSize = nextRequest.captureRequest->mBatchSize; @@ -3246,14 +3234,13 @@ void Camera3Device::RequestThread::waitForNextRequestBatch(Vector * additionalRequest.halRequest = camera3_capture_request_t(); additionalRequest.submitted = false; - nextRequests->add(additionalRequest); - mNextRequests.push_back(additionalRequest.captureRequest); + mNextRequests.add(additionalRequest); } - if (nextRequests->size() < batchSize) { + if (mNextRequests.size() < batchSize) { ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.", - nextRequests->size(), batchSize); - cleanUpFailedRequests(nextRequests, /*sendRequestError*/true); + mNextRequests.size(), batchSize); + cleanUpFailedRequests(/*sendRequestError*/true); } return; diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index a3abbaf..9d3c533 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -519,20 +519,22 @@ class Camera3Device : bool submitted; }; - // Wait for the next batch of requests. - void waitForNextRequestBatch(Vector *nextRequests); + // Wait for the next batch of requests and put them in mNextRequests. mNextRequests will + // be empty if it times out. + void waitForNextRequestBatch(); // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold. sp waitForNextRequestLocked(); - // Prepare a HAL request and output buffers. Return TIMED_OUT if getting any output buffer - // timed out. If an error is returned, the caller should clean up the pending request batch. - status_t prepareHalRequests(Vector *nextRequests); + // Prepare HAL requests and output buffers in mNextRequests. Return TIMED_OUT if getting any + // output buffer timed out. If an error is returned, the caller should clean up the pending + // request batch. + status_t prepareHalRequests(); - // Return buffers, etc, for a request that couldn't be fully constructed and send request - // errors if sendRequestError is true. The buffers will be returned in the ERROR state - // to mark them as not having valid data. nextRequests will be modified. - void cleanUpFailedRequests(Vector *nextRequests, bool sendRequestError); + // Return buffers, etc, for requests in mNextRequests that couldn't be fully constructed and + // send request errors if sendRequestError is true. The buffers will be returned in the + // ERROR state to mark them as not having valid data. mNextRequests will be cleared. + void cleanUpFailedRequests(bool sendRequestError); // Pause handling bool waitIfPaused(); @@ -561,10 +563,10 @@ class Camera3Device : Condition mRequestSignal; RequestList mRequestQueue; RequestList mRepeatingRequests; - // The next requests being prepped for submission to the HAL, no longer + // The next batch of requests being prepped for submission to the HAL, no longer // on the request queue. Read-only even with mRequestLock held, outside // of threadLoop - RequestList mNextRequests; + Vector mNextRequests; // To protect flush() and sending a request batch to HAL. Mutex mFlushLock; -- cgit v1.1 From 24901c86e10a0923fe10f5e9bce5e6dba061a289 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 4 Sep 2015 14:15:58 -0700 Subject: CameraService: Link to client binder death at end of connect If, within a binder Looper thread, a Binder object death notifier is registered, and then a nested Binder transaction is begun, that transaction may process a death notification callback for the just-registered object, if it was dead at the time of registration. This can lead to an unexpected nested call into the service, and cause deadlock. To avoid this, move the death notifier registration to the end of handling the connect transaction. Also remove one extra bit of disconnect logging. Bug: 23525545 Change-Id: If01cbaf42704f55134118afefc9a8f7bdb014e09 --- services/camera/libcameraservice/CameraService.cpp | 14 +++++++++++--- services/camera/libcameraservice/CameraService.h | 5 ----- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index f5a0887..9230994 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -945,6 +945,16 @@ void CameraService::finishConnectLocked(const sp& client, LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, clients not evicted properly", __FUNCTION__); } + + // And register a death notification for the client callback. Do + // this last to avoid Binder policy where a nested Binder + // transaction might be pre-empted to service the client death + // notification if the client process dies before linkToDeath is + // invoked. + sp remoteCallback = client->getRemote(); + if (remoteCallback != nullptr) { + remoteCallback->linkToDeath(this); + } } status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid, @@ -1884,11 +1894,9 @@ CameraService::BasicClient::~BasicClient() { void CameraService::BasicClient::disconnect() { if (mDisconnected) { - ALOGE("%s: Disconnect called on already disconnected client for device %d", __FUNCTION__, - mCameraId); return; } - mDisconnected = true;; + mDisconnected = true; mCameraService->removeByClient(this); mCameraService->logDisconnected(String8::format("%d", mCameraId), mClientPid, diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 330a19d..cd97b08 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -873,11 +873,6 @@ status_t CameraService::connectHelper(const sp& cameraCb, const String return ret; } - sp remoteCallback = client->getRemote(); - if (remoteCallback != nullptr) { - remoteCallback->linkToDeath(this); - } - // Update shim paremeters for legacy clients if (effectiveApiLevel == API_1) { // Assume we have always received a Client subclass for API1 -- cgit v1.1 From a84bbe6b59721b1b963d65d270aa98d6513bbb78 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 8 Sep 2015 17:59:17 -0700 Subject: CameraService: Add more systracing, fix module init order Improve debugging of performance of concurrent calls to the service. - Add ATRACE calls to camera service entry points - Add ATRACE calls for camera HAL module calls - Ensure that camera module init method is called before all others Bug: 23718257 Bug: 23933447 Change-Id: I2a025866ab39eda3962877120cab13a063c7727e --- services/camera/libcameraservice/CameraService.cpp | 42 ++++++++++++++-- .../libcameraservice/common/CameraModule.cpp | 56 ++++++++++++++++++---- 2 files changed, 84 insertions(+), 14 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 9230994..7e33e0c 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "CameraService" +#define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 #include @@ -156,7 +157,6 @@ void CameraService::onFirstRef() } mModule = new CameraModule(rawModule); - ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); err = mModule->init(); if (err != OK) { ALOGE("Could not initialize camera HAL module: %d (%s)", err, @@ -168,6 +168,7 @@ void CameraService::onFirstRef() mModule = nullptr; return; } + ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); mNumberOfCameras = mModule->getNumberOfCameras(); mNumberOfNormalCameras = mNumberOfCameras; @@ -403,10 +404,12 @@ void CameraService::onTorchStatusChangedLocked(const String8& cameraId, } int32_t CameraService::getNumberOfCameras() { + ATRACE_CALL(); return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE); } int32_t CameraService::getNumberOfCameras(int type) { + ATRACE_CALL(); switch (type) { case CAMERA_TYPE_BACKWARD_COMPATIBLE: return mNumberOfNormalCameras; @@ -421,6 +424,7 @@ int32_t CameraService::getNumberOfCameras(int type) { status_t CameraService::getCameraInfo(int cameraId, struct CameraInfo* cameraInfo) { + ATRACE_CALL(); if (!mModule) { return -ENODEV; } @@ -448,6 +452,7 @@ int CameraService::cameraIdToInt(const String8& cameraId) { } status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo) { + ATRACE_CALL(); status_t ret = OK; struct CameraInfo info; if ((ret = getCameraInfo(cameraId, &info)) != OK) { @@ -534,6 +539,7 @@ status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata status_t CameraService::getCameraCharacteristics(int cameraId, CameraMetadata* cameraInfo) { + ATRACE_CALL(); if (!cameraInfo) { ALOGE("%s: cameraInfo is NULL", __FUNCTION__); return BAD_VALUE; @@ -611,6 +617,7 @@ int CameraService::getCameraPriorityFromProcState(int procState) { } status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp& desc) { + ATRACE_CALL(); if (!mModule) { ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__); return -ENODEV; @@ -621,6 +628,7 @@ status_t CameraService::getCameraVendorTagDescriptor(/*out*/spgetCameraInfo(cameraId, &info) != OK) { return -1; @@ -652,6 +660,7 @@ status_t CameraService::filterGetInfoErrorCode(status_t err) { } bool CameraService::setUpVendorTags() { + ATRACE_CALL(); vendor_tag_ops_t vOps = vendor_tag_ops_t(); // Check if vendor operations have been implemented @@ -660,9 +669,7 @@ bool CameraService::setUpVendorTags() { return false; } - ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops"); mModule->getVendorTagOps(&vOps); - ATRACE_END(); // Ensure all vendor operations are present if (vOps.get_tag_count == NULL || vOps.get_all_tags == NULL || @@ -962,7 +969,7 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien /*out*/ sp* client, std::shared_ptr>>* partial) { - + ATRACE_CALL(); status_t ret = NO_ERROR; std::vector evictedClients; DescriptorPtr clientDescriptor; @@ -1151,6 +1158,7 @@ status_t CameraService::connect( /*out*/ sp& device) { + ATRACE_CALL(); status_t ret = NO_ERROR; String8 id = String8::format("%d", cameraId); sp client = nullptr; @@ -1175,6 +1183,7 @@ status_t CameraService::connectLegacy( /*out*/ sp& device) { + ATRACE_CALL(); String8 id = String8::format("%d", cameraId); int apiVersion = mModule->getModuleApiVersion(); if (halVersion != CAMERA_HAL_API_VERSION_UNSPECIFIED && @@ -1215,6 +1224,7 @@ status_t CameraService::connectDevice( /*out*/ sp& device) { + ATRACE_CALL(); status_t ret = NO_ERROR; String8 id = String8::format("%d", cameraId); sp client = nullptr; @@ -1234,6 +1244,8 @@ status_t CameraService::connectDevice( status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, const sp& clientBinder) { + + ATRACE_CALL(); if (enabled && clientBinder == nullptr) { ALOGE("%s: torch client binder is NULL", __FUNCTION__); return -EINVAL; @@ -1322,6 +1334,8 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, } void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) { + ATRACE_CALL(); + switch(eventId) { case ICameraService::USER_SWITCHED: { doUserSwitch(/*newUserIds*/args, /*length*/length); @@ -1337,6 +1351,8 @@ void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size } status_t CameraService::addListener(const sp& listener) { + ATRACE_CALL(); + ALOGV("%s: Add listener %p", __FUNCTION__, listener.get()); if (listener == nullptr) { @@ -1385,6 +1401,8 @@ status_t CameraService::addListener(const sp& listener) } status_t CameraService::removeListener(const sp& listener) { + ATRACE_CALL(); + ALOGV("%s: Remove listener %p", __FUNCTION__, listener.get()); if (listener == 0) { @@ -1411,6 +1429,8 @@ status_t CameraService::removeListener(const sp& listene } status_t CameraService::getLegacyParameters(int cameraId, /*out*/String16* parameters) { + + ATRACE_CALL(); ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId); if (parameters == NULL) { @@ -1435,6 +1455,8 @@ status_t CameraService::getLegacyParameters(int cameraId, /*out*/String16* param } status_t CameraService::supportsCameraApi(int cameraId, int apiVersion) { + ATRACE_CALL(); + ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId); switch (apiVersion) { @@ -1802,6 +1824,8 @@ MediaPlayer* CameraService::newMediaPlayer(const char *file) { } void CameraService::loadSound() { + ATRACE_CALL(); + Mutex::Autolock lock(mSoundLock); LOG1("CameraService::loadSound ref=%d", mSoundRef); if (mSoundRef++) return; @@ -1824,6 +1848,8 @@ void CameraService::releaseSound() { } void CameraService::playSound(sound_kind kind) { + ATRACE_CALL(); + LOG1("playSound(%d)", kind); Mutex::Autolock lock(mSoundLock); sp player = mSoundPlayer[kind]; @@ -1933,6 +1959,8 @@ bool CameraService::BasicClient::canCastToApiClient(apiLevel level) const { } status_t CameraService::BasicClient::startCameraOps() { + ATRACE_CALL(); + int32_t res; // Notify app ops that the camera is not available mOpsCallback = new OpsCallback(this); @@ -1974,6 +2002,8 @@ status_t CameraService::BasicClient::startCameraOps() { } status_t CameraService::BasicClient::finishCameraOps() { + ATRACE_CALL(); + // Check if startCameraOps succeeded, and if so, finish the camera op if (mOpsActive) { // Notify app ops that the camera is available again @@ -2006,6 +2036,8 @@ status_t CameraService::BasicClient::finishCameraOps() { } void CameraService::BasicClient::opChanged(int32_t op, const String16& packageName) { + ATRACE_CALL(); + String8 name(packageName); String8 myName(mClientPackageName); @@ -2229,6 +2261,8 @@ static bool tryLock(Mutex& mutex) } status_t CameraService::dump(int fd, const Vector& args) { + ATRACE_CALL(); + String8 result("Dump of the Camera Service:\n"); if (checkCallingPermission(String16("android.permission.DUMP")) == false) { result.appendFormat("Permission Denial: " diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp index 6a4dfe0..16b8aba 100644 --- a/services/camera/libcameraservice/common/CameraModule.cpp +++ b/services/camera/libcameraservice/common/CameraModule.cpp @@ -15,14 +15,18 @@ */ #define LOG_TAG "CameraModule" +#define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 +#include + #include "CameraModule.h" namespace android { void CameraModule::deriveCameraCharacteristicsKeys( uint32_t deviceVersion, CameraMetadata &chars) { + ATRACE_CALL(); // HAL1 devices should not reach here if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) { ALOGV("%s: Cannot derive keys for HAL version < 2.0"); @@ -150,9 +154,7 @@ CameraModule::CameraModule(camera_module_t *module) { ALOGE("%s: camera hardware module must not be null", __FUNCTION__); assert(0); } - mModule = module; - mCameraInfoMap.setCapacity(getNumberOfCameras()); } CameraModule::~CameraModule() @@ -168,14 +170,20 @@ CameraModule::~CameraModule() } int CameraModule::init() { + ATRACE_CALL(); + int res = OK; if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && mModule->init != NULL) { - return mModule->init(); + ATRACE_BEGIN("camera_module->init"); + res = mModule->init(); + ATRACE_END(); } - return OK; + mCameraInfoMap.setCapacity(getNumberOfCameras()); + return res; } int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { + ATRACE_CALL(); Mutex::Autolock lock(mCameraInfoLock); if (cameraId < 0) { ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId); @@ -185,14 +193,20 @@ int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { // Only override static_camera_characteristics for API2 devices int apiVersion = mModule->common.module_api_version; if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) { - return mModule->get_camera_info(cameraId, info); + int ret; + ATRACE_BEGIN("camera_module->get_camera_info"); + ret = mModule->get_camera_info(cameraId, info); + ATRACE_END(); + return ret; } ssize_t index = mCameraInfoMap.indexOfKey(cameraId); if (index == NAME_NOT_FOUND) { // Get camera info from raw module and cache it camera_info rawInfo, cameraInfo; + ATRACE_BEGIN("camera_module->get_camera_info"); int ret = mModule->get_camera_info(cameraId, &rawInfo); + ATRACE_END(); if (ret != 0) { return ret; } @@ -217,20 +231,36 @@ int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { } int CameraModule::open(const char* id, struct hw_device_t** device) { - return filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device)); + int res; + ATRACE_BEGIN("camera_module->open"); + res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device)); + ATRACE_END(); + return res; } int CameraModule::openLegacy( const char* id, uint32_t halVersion, struct hw_device_t** device) { - return mModule->open_legacy(&mModule->common, id, halVersion, device); + int res; + ATRACE_BEGIN("camera_module->open_legacy"); + res = mModule->open_legacy(&mModule->common, id, halVersion, device); + ATRACE_END(); + return res; } int CameraModule::getNumberOfCameras() { - return mModule->get_number_of_cameras(); + int numCameras; + ATRACE_BEGIN("camera_module->get_number_of_cameras"); + numCameras = mModule->get_number_of_cameras(); + ATRACE_END(); + return numCameras; } int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) { - return mModule->set_callbacks(callbacks); + int res; + ATRACE_BEGIN("camera_module->set_callbacks"); + res = mModule->set_callbacks(callbacks); + ATRACE_END(); + return res; } bool CameraModule::isVendorTagDefined() { @@ -239,12 +269,18 @@ bool CameraModule::isVendorTagDefined() { void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) { if (mModule->get_vendor_tag_ops) { + ATRACE_BEGIN("camera_module->get_vendor_tag_ops"); mModule->get_vendor_tag_ops(ops); + ATRACE_END(); } } int CameraModule::setTorchMode(const char* camera_id, bool enable) { - return mModule->set_torch_mode(camera_id, enable); + int res; + ATRACE_BEGIN("camera_module->set_torch_mode"); + res = mModule->set_torch_mode(camera_id, enable); + ATRACE_END(); + return res; } status_t CameraModule::filterOpenErrorCode(status_t err) { -- cgit v1.1 From 564d144fc28917d42e3a67718ac51d61bfc36315 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 9 Sep 2015 12:26:52 -0700 Subject: Revert "Do not acknowledge flush() on start() for static tracks" This reverts commit cafe86a9cb6625bb1ec6383e16e28e4c9e455f87. Bug: 23924093. Change-Id: I186d1013b06a286eca93c30bb9b3545dc36695ff --- services/audioflinger/Tracks.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'services') diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index d058255..f7da209 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -712,12 +712,9 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev // But in this case we know the mixer thread (whether normal mixer or fast mixer) // isn't looking at this track yet: we still hold the normal mixer thread lock, // and for fast tracks the track is not yet in the fast mixer thread's active set. - // TODO: remove race condition on stop() followed by start(). - if (mSharedBuffer == 0) { // only streaming tracks use flush(). - ServerProxy::Buffer buffer; - buffer.mFrameCount = 1; - (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); - } + ServerProxy::Buffer buffer; + buffer.mFrameCount = 1; + (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); } } else { status = BAD_VALUE; -- cgit v1.1 From a2ab4505c807f42afe34809409c4e85d91618a8c Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 9 Sep 2015 12:25:51 -0700 Subject: audio flinger: force audio path start from normal mixer The audio HAL wakes up and configures the audio path when receiving the first write() in standby state. This causes a certain amount of process to take place in the mixer threads which is problematic for fast mixer running at FIFO priority. We now force a fake write() of 0 bytes from normal mixer to trigger the audio path configuration before starting the fast mixer. Bug: 23791972. Change-Id: I54311b337fda956444846f5d2f53a3263d54e04b --- services/audioflinger/Threads.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'services') diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 0a7d4a2..5bd9149 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -3479,6 +3479,12 @@ ssize_t AudioFlinger::MixerThread::threadLoop_write() if (state->mCommand != FastMixerState::MIX_WRITE && (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)) { if (state->mCommand == FastMixerState::COLD_IDLE) { + + // FIXME workaround for first HAL write being CPU bound on some devices + ATRACE_BEGIN("write"); + mOutput->write((char *)mSinkBuffer, 0); + ATRACE_END(); + int32_t old = android_atomic_inc(&mFastMixerFutex); if (old == -1) { (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1); -- cgit v1.1 From fefa614f92346e929921bfd47e3643861850bc2a Mon Sep 17 00:00:00 2001 From: dcashman Date: Wed, 9 Sep 2015 13:43:01 -0700 Subject: Reduce DUMP permission denial output to one line. Bug: 23940813 Change-Id: I0060dbaff5cd0c3d028ac5cd7aba7da3f0371150 --- services/camera/libcameraservice/CameraService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'services') diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 7e33e0c..2aaefe9 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -2265,7 +2265,7 @@ status_t CameraService::dump(int fd, const Vector& args) { String8 result("Dump of the Camera Service:\n"); if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - result.appendFormat("Permission Denial: " + result = result.format("Permission Denial: " "can't dump CameraService from pid=%d, uid=%d\n", getCallingPid(), getCallingUid()); -- cgit v1.1 From 652f7d7ebd9a8cec067588c2a232e49710d5cd83 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Fri, 11 Sep 2015 13:01:30 -0700 Subject: Camera: API1 shim: select better default FPS range Bug: 23992350 Change-Id: Ie86b24d9e5ea753c6dfc2e5526d371b339be96a1 --- services/camera/libcameraservice/api1/client2/Parameters.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index 442eb75..44447b4 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -214,8 +214,8 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) { supportedPreviewFormats); } - previewFpsRange[0] = availableFpsRanges.data.i32[0]; - previewFpsRange[1] = availableFpsRanges.data.i32[1]; + previewFpsRange[0] = fastInfo.bestStillCaptureFpsRange[0]; + previewFpsRange[1] = fastInfo.bestStillCaptureFpsRange[1]; // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but // still have to do something sane for them -- cgit v1.1 From b83c1fe4e793da269b9340c64f7032a9cc27809c Mon Sep 17 00:00:00 2001 From: Chien-Yu Chen Date: Thu, 10 Sep 2015 16:15:21 -0700 Subject: Camera3Device: Signal buffer returned after it failed Signal buffer returned even after it failed so the thread waiting for it can wake up sooner. Bug: 23981045 Change-Id: Iccbcc7ece2e0f6204da9c54f2bdd96ff6843a8f5 --- services/camera/libcameraservice/device3/Camera3Stream.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'services') diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 691764f..96299b3 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -487,9 +487,12 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, status_t res = returnBufferLocked(buffer, timestamp); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true); - mOutputBufferReturnedSignal.signal(); } + // Even if returning the buffer failed, we still want to signal whoever is waiting for the + // buffer to be returned. + mOutputBufferReturnedSignal.signal(); + return res; } -- cgit v1.1 From b9017af21e097ef12867e0d4b72c432579f29674 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 10 Sep 2015 18:38:08 -0700 Subject: Force fixed volume for TTS stream Always play Transmitted Through Speaker stream at max volume instead of tracking media stream volume. Bug: 23729461. Change-Id: I61021f59617bb851a4cd7da80924e587029e96a3 --- services/audiopolicy/enginedefault/src/Gains.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'services') diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp index 78f2909..d06365c 100644 --- a/services/audiopolicy/enginedefault/src/Gains.cpp +++ b/services/audiopolicy/enginedefault/src/Gains.cpp @@ -171,10 +171,10 @@ const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT] }, { // AUDIO_STREAM_TTS // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER - Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET - Gains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER - Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE - Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA + Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET + Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER + Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE + Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_ACCESSIBILITY Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET -- cgit v1.1 From 014e91e471edba3f9b2c71ff6025274716b0f587 Mon Sep 17 00:00:00 2001 From: dcashman Date: Fri, 11 Sep 2015 09:33:01 -0700 Subject: Add DUMP permission check to ResourceManagerService. Bug: 23999740 Change-Id: I3165404add455528b22951ba47b682a075b50087 --- services/mediaresourcemanager/ResourceManagerService.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'services') diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp index e54cc5a..4790754 100644 --- a/services/mediaresourcemanager/ResourceManagerService.cpp +++ b/services/mediaresourcemanager/ResourceManagerService.cpp @@ -96,6 +96,15 @@ status_t ResourceManagerService::dump(int fd, const Vector& /* args */ const size_t SIZE = 256; char buffer[SIZE]; + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + result.format("Permission Denial: " + "can't dump ResourceManagerService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + write(fd, result.string(), result.size()); + return PERMISSION_DENIED; + } + snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this); result.append(buffer); result.append(" Policies:\n"); -- cgit v1.1 From a542782d0045588e55e075a763cedcd2d504ad22 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Fri, 11 Sep 2015 16:15:35 -0700 Subject: Workaround static fast track start-after-stop issue Bug: 23291988 Bug: 23614327 Bug: 23924081 Change-Id: Id1a519ed4bb2a6f4cb197da8450f7069b55c0d48 --- services/audioflinger/Tracks.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'services') diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index f7da209..b3fac0b 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -432,7 +432,10 @@ AudioFlinger::PlaybackThread::Track::Track( } // only allocate a fast track index if we were able to allocate a normal track name if (flags & IAudioFlinger::TRACK_FAST) { - mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); + // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential + // race with setSyncEvent(). However, if we call it, we cannot properly start + // static fast tracks (SoundPool) immediately after stopping. + //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); ALOG_ASSERT(thread->mFastTrackAvailMask != 0); int i = __builtin_ctz(thread->mFastTrackAvailMask); ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks); -- cgit v1.1 From af20bc26704458eac0ddc23f12b637939b0df7a4 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Mon, 14 Sep 2015 16:37:07 -0700 Subject: AudioPolicy: don't always change ACCESSIBILITY volume Only change the volume for AUDIO_STREAM_ACCESSIBILITY when changing the media volume. Bug 23366575 Change-Id: Ic42c726ec4d47615c20500c20e4d43cef159b3c6 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'services') diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index b1d7b13..dfb477d 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1718,7 +1718,9 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, status = volStatus; } } - if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) { + if ((accessibilityDevice != AUDIO_DEVICE_NONE) && + ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0))) + { status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY, index, desc, curDevice); } -- cgit v1.1 From beb07febdc0cae2f43a2008d3bd06b7bb933b19a Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 16 Sep 2015 15:49:30 -0700 Subject: audio policy: bind setMode() and setPhoneState() operations No routing operation should be allowed between setMode() and setPhoneState() when starting a call as the audio HAL relies on a precise sequence of mode change and routing change to select the initial audio device for the call. Bug: 24083591. Change-Id: I2d5ef62c11cf7aedc2ec7ca5e5fadd7ac875afbc --- services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'services') diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 793c26a..ca365a5 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -76,10 +76,14 @@ status_t AudioPolicyService::setPhoneState(audio_mode_t state) ALOGV("setPhoneState()"); + // acquire lock before calling setMode() so that setMode() + setPhoneState() are an atomic + // operation from policy manager standpoint (no other operation (e.g track start or stop) + // can be interleaved). + Mutex::Autolock _l(mLock); + // TODO: check if it is more appropriate to do it in platform specific policy manager AudioSystem::setMode(state); - Mutex::Autolock _l(mLock); mAudioPolicyManager->setPhoneState(state); mPhoneState = state; return NO_ERROR; -- cgit v1.1 From 64265b2fb8f5be63b6c2ad4fcbec9acf74705bc4 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 18 Sep 2015 18:32:07 -0700 Subject: audio policy: fix preemtible capture race Because a preemtible capture session can preempt another one, we end up in an endless loop situation were each session is allowed to restart after being preempted, thus preempting the other one which restarts and so on. To avoid this situation, we store which audio session was preempted when a particular input started and prevent preemption of this active input by this session. We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc... Bug: 24007220. Change-Id: I0eab5299440ef3ab9e987635dc9a300cf42f2c79 --- .../include/AudioInputDescriptor.h | 12 ++++++++++++ .../managerdefinitions/src/AudioInputDescriptor.cpp | 20 ++++++++++++++++++++ .../managerdefault/AudioPolicyManager.cpp | 12 +++++++++--- 3 files changed, 41 insertions(+), 3 deletions(-) (limited to 'services') diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h index 18bcfdb..48d09ed 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h @@ -56,9 +56,21 @@ public: const struct audio_port_config *srcConfig = NULL) const; virtual sp getAudioPort() const { return mProfile; } void toAudioPort(struct audio_port *port) const; + void setPreemptedSessions(const SortedVector& sessions); + SortedVector getPreemptedSessions() const; + bool hasPreemptedSession(audio_session_t session) const; + void clearPreemptedSessions(); private: audio_port_handle_t mId; + // Because a preemtible capture session can preempt another one, we end up in an endless loop + // situation were each session is allowed to restart after being preempted, + // thus preempting the other one which restarts and so on. + // To avoid this situation, we store which audio session was preempted when + // a particular input started and prevent preemption of this active input by this session. + // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc... + SortedVector mPreemptedSessions; + }; class AudioInputCollection : diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp index 937160b..626fdae 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp @@ -93,6 +93,26 @@ void AudioInputDescriptor::toAudioPort(struct audio_port *port) const port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL; } +void AudioInputDescriptor::setPreemptedSessions(const SortedVector& sessions) +{ + mPreemptedSessions = sessions; +} + +SortedVector AudioInputDescriptor::getPreemptedSessions() const +{ + return mPreemptedSessions; +} + +bool AudioInputDescriptor::hasPreemptedSession(audio_session_t session) const +{ + return (mPreemptedSessions.indexOf(session) >= 0); +} + +void AudioInputDescriptor::clearPreemptedSessions() +{ + mPreemptedSessions.clear(); +} + status_t AudioInputDescriptor::dump(int fd) { const size_t SIZE = 256; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index dfb477d..8419ed5 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1485,10 +1485,15 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed, // otherwise the active input continues and the new input cannot be started. sp activeDesc = mInputs.valueFor(activeInput); - if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) { + if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) && + !activeDesc->hasPreemptedSession(session)) { ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput); - stopInput(activeInput, activeDesc->mSessions.itemAt(0)); - releaseInput(activeInput, activeDesc->mSessions.itemAt(0)); + audio_session_t activeSession = activeDesc->mSessions.itemAt(0); + SortedVector sessions = activeDesc->getPreemptedSessions(); + sessions.add(activeSession); + inputDesc->setPreemptedSessions(sessions); + stopInput(activeInput, activeSession); + releaseInput(activeInput, activeSession); } else { ALOGE("startInput(%d) failed: other input %d already started", input, activeInput); return INVALID_OPERATION; @@ -1592,6 +1597,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, if (mInputs.activeInputsCount() == 0) { SoundTrigger::setCaptureState(false); } + inputDesc->clearPreemptedSessions(); } return NO_ERROR; } -- cgit v1.1 From 047d97b2d046374e2a25c81a984d9cde23f5d781 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 23 Sep 2015 10:25:31 -0700 Subject: AudioPolicyService: fix race in AudioCommandThread Fixe race condition in AudioCommandThread::threadLoop() where a command can be inserted in first position in the queue after the sleep time has been calculated causing a longer delay than expected. Also fix a failure to hold a wake lock while commands are still in the queue. Bug: 22707905. Change-Id: I813626986677bf00106acb37ee20d3dd75d5cf33 --- .../audiopolicy/service/AudioPolicyService.cpp | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'services') diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index eefff3d..c77cc45 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -577,22 +577,28 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() } } waitTime = INT64_MAX; + // release mLock before releasing strong reference on the service as + // AudioPolicyService destructor calls AudioCommandThread::exit() which + // acquires mLock. + mLock.unlock(); + svc.clear(); + mLock.lock(); } else { waitTime = mAudioCommands[0]->mTime - curTime; break; } } - // release mLock before releasing strong reference on the service as - // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock. - mLock.unlock(); - svc.clear(); - mLock.lock(); - if (!exitPending() && (mAudioCommands.isEmpty() || waitTime != INT64_MAX)) { - // release delayed commands wake lock + + // release delayed commands wake lock if the queue is empty + if (mAudioCommands.isEmpty()) { release_wake_lock(mName.string()); + } + + // At this stage we have either an empty command queue or the first command in the queue + // has a finite delay. So unless we are exiting it is safe to wait. + if (!exitPending()) { ALOGV("AudioCommandThread() going to sleep"); mWaitWorkCV.waitRelative(mLock, waitTime); - ALOGV("AudioCommandThread() waking up"); } } // release delayed commands wake lock before quitting @@ -1003,6 +1009,8 @@ void AudioPolicyService::AudioCommandThread::exit() requestExit(); mWaitWorkCV.signal(); } + // Note that we can call it from the thread loop if all other references have been released + // but it will safely return WOULD_BLOCK in this case requestExitAndWait(); } -- cgit v1.1 From f99498ee4de7123e2fd71778c6877be44fbd1506 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 25 Sep 2015 16:52:55 -0700 Subject: CameraService: Use SCHED_FIFO for request queue thread in HFR - Move SchedulingPolicyService from audioservice to mediautils - When starting up a high speed stream config, set request queue thread to SCHED_FIFO using SchedulingPolicyService Bug: 24227252 Change-Id: I224b59142bd111caf563779f55cddd62385b9bac --- services/audioflinger/Android.mk | 15 +--- services/audioflinger/ISchedulingPolicyService.cpp | 80 ---------------------- services/audioflinger/ISchedulingPolicyService.h | 45 ------------ services/audioflinger/SchedulingPolicyService.cpp | 62 ----------------- services/audioflinger/SchedulingPolicyService.h | 31 --------- services/audioflinger/Threads.cpp | 2 +- services/camera/libcameraservice/Android.mk | 2 +- .../libcameraservice/device3/Camera3Device.cpp | 16 +++++ .../libcameraservice/device3/Camera3Device.h | 2 + 9 files changed, 22 insertions(+), 233 deletions(-) delete mode 100644 services/audioflinger/ISchedulingPolicyService.cpp delete mode 100644 services/audioflinger/ISchedulingPolicyService.h delete mode 100644 services/audioflinger/SchedulingPolicyService.cpp delete mode 100644 services/audioflinger/SchedulingPolicyService.h (limited to 'services') diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index debcdf9..9b4ba79 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -3,17 +3,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - ISchedulingPolicyService.cpp \ - SchedulingPolicyService.cpp - -# FIXME Move this library to frameworks/native -LOCAL_MODULE := libscheduling_policy - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ ServiceUtilities.cpp # FIXME Move this library to frameworks/native @@ -64,10 +53,10 @@ LOCAL_SHARED_LIBRARIES := \ libeffects \ libpowermanager \ libserviceutility \ - libsonic + libsonic \ + libmediautils LOCAL_STATIC_LIBRARIES := \ - libscheduling_policy \ libcpustats \ libmedia_helper diff --git a/services/audioflinger/ISchedulingPolicyService.cpp b/services/audioflinger/ISchedulingPolicyService.cpp deleted file mode 100644 index f55bc02..0000000 --- a/services/audioflinger/ISchedulingPolicyService.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2012 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 "ISchedulingPolicyService" -//#define LOG_NDEBUG 0 - -#include -#include "ISchedulingPolicyService.h" - -namespace android { - -// Keep in sync with frameworks/base/core/java/android/os/ISchedulingPolicyService.aidl -enum { - REQUEST_PRIORITY_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, -}; - -// ---------------------------------------------------------------------- - -class BpSchedulingPolicyService : public BpInterface -{ -public: - BpSchedulingPolicyService(const sp& impl) - : BpInterface(impl) - { - } - - virtual int requestPriority(int32_t pid, int32_t tid, int32_t prio, bool asynchronous) - { - Parcel data, reply; - data.writeInterfaceToken(ISchedulingPolicyService::getInterfaceDescriptor()); - data.writeInt32(pid); - data.writeInt32(tid); - data.writeInt32(prio); - uint32_t flags = asynchronous ? IBinder::FLAG_ONEWAY : 0; - status_t status = remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags); - if (status != NO_ERROR) { - return status; - } - if (asynchronous) { - return NO_ERROR; - } - // fail on exception: force binder reconnection - if (reply.readExceptionCode() != 0) { - return DEAD_OBJECT; - } - return reply.readInt32(); - } -}; - -IMPLEMENT_META_INTERFACE(SchedulingPolicyService, "android.os.ISchedulingPolicyService"); - -// ---------------------------------------------------------------------- - -status_t BnSchedulingPolicyService::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch (code) { - case REQUEST_PRIORITY_TRANSACTION: - // Not reached - return NO_ERROR; - break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -} // namespace android diff --git a/services/audioflinger/ISchedulingPolicyService.h b/services/audioflinger/ISchedulingPolicyService.h deleted file mode 100644 index b94b191..0000000 --- a/services/audioflinger/ISchedulingPolicyService.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2012 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_ISCHEDULING_POLICY_SERVICE_H -#define ANDROID_ISCHEDULING_POLICY_SERVICE_H - -#include - -namespace android { - -class ISchedulingPolicyService : public IInterface -{ -public: - DECLARE_META_INTERFACE(SchedulingPolicyService); - - virtual int requestPriority(/*pid_t*/int32_t pid, /*pid_t*/int32_t tid, - int32_t prio, bool asynchronous) = 0; - -}; - -class BnSchedulingPolicyService : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -} // namespace android - -#endif // ANDROID_ISCHEDULING_POLICY_SERVICE_H diff --git a/services/audioflinger/SchedulingPolicyService.cpp b/services/audioflinger/SchedulingPolicyService.cpp deleted file mode 100644 index 70a3f1a..0000000 --- a/services/audioflinger/SchedulingPolicyService.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2012 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 "SchedulingPolicyService" -//#define LOG_NDEBUG 0 - -#include -#include -#include "ISchedulingPolicyService.h" -#include "SchedulingPolicyService.h" - -namespace android { - -static sp sSchedulingPolicyService; -static const String16 _scheduling_policy("scheduling_policy"); -static Mutex sMutex; - -int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous) -{ - // FIXME merge duplicated code related to service lookup, caching, and error recovery - int ret; - for (;;) { - sMutex.lock(); - sp sps = sSchedulingPolicyService; - sMutex.unlock(); - if (sps == 0) { - sp binder = defaultServiceManager()->checkService(_scheduling_policy); - if (binder == 0) { - sleep(1); - continue; - } - sps = interface_cast(binder); - sMutex.lock(); - sSchedulingPolicyService = sps; - sMutex.unlock(); - } - ret = sps->requestPriority(pid, tid, prio, asynchronous); - if (ret != DEAD_OBJECT) { - break; - } - ALOGW("SchedulingPolicyService died"); - sMutex.lock(); - sSchedulingPolicyService.clear(); - sMutex.unlock(); - } - return ret; -} - -} // namespace android diff --git a/services/audioflinger/SchedulingPolicyService.h b/services/audioflinger/SchedulingPolicyService.h deleted file mode 100644 index a9870d4..0000000 --- a/services/audioflinger/SchedulingPolicyService.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2012 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_SCHEDULING_POLICY_SERVICE_H -#define _ANDROID_SCHEDULING_POLICY_SERVICE_H - -namespace android { - -// Request elevated priority for thread tid, whose thread group leader must be pid. -// The priority parameter is currently restricted to either 1 or 2. -// The asynchronous parameter should be 'true' to return immediately, -// after the request is enqueued but not necessarily executed. -// The default value 'false' means to return after request has been enqueued and executed. -int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous = false); - -} // namespace android - -#endif // _ANDROID_SCHEDULING_POLICY_SERVICE_H diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 5bd9149..f586291 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -60,7 +60,7 @@ #include "FastMixer.h" #include "FastCapture.h" #include "ServiceUtilities.h" -#include "SchedulingPolicyService.h" +#include "mediautils/SchedulingPolicyService.h" #ifdef ADD_BATTERY_DATA #include diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index e8ef24e..45900c4 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -53,7 +53,7 @@ LOCAL_SRC_FILES:= \ device3/StatusTracker.cpp \ gui/RingBufferConsumer.cpp \ utils/CameraTraces.cpp \ - utils/AutoConditionLock.cpp \ + utils/AutoConditionLock.cpp LOCAL_SHARED_LIBRARIES:= \ libui \ diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 433a745..1a3a770 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -44,6 +44,7 @@ #include #include "utils/CameraTraces.h" +#include "mediautils/SchedulingPolicyService.h" #include "device3/Camera3Device.h" #include "device3/Camera3OutputStream.h" #include "device3/Camera3InputStream.h" @@ -1766,6 +1767,21 @@ status_t Camera3Device::configureStreamsLocked() { // across configure_streams() calls mRequestThread->configurationComplete(); + // Boost priority of request thread for high speed recording to SCHED_FIFO + if (mIsConstrainedHighSpeedConfiguration) { + pid_t requestThreadTid = mRequestThread->getTid(); + res = requestPriority(getpid(), requestThreadTid, + kConstrainedHighSpeedThreadPriority, true); + if (res != OK) { + ALOGW("Can't set realtime priority for request processing thread: %s (%d)", + strerror(-res), res); + } else { + ALOGD("Set real time priority for request queue thread (tid %d)", requestThreadTid); + } + } else { + // TODO: Set/restore normal priority for normal use cases + } + // Update device state mNeedConfig = false; diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 9d3c533..402cb1d 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -161,6 +161,8 @@ class Camera3Device : static const nsecs_t kActiveTimeout = 500000000; // 500 ms static const size_t kInFlightWarnLimit = 20; static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8 + // SCHED_FIFO priority for request submission thread in HFR mode + static const int kConstrainedHighSpeedThreadPriority = 3; struct RequestTrigger; // minimal jpeg buffer size: 256KB + blob header -- cgit v1.1 From 3df11ce7240d0ce5d957c626be467832c1c7fde9 Mon Sep 17 00:00:00 2001 From: Chien-Yu Chen Date: Wed, 30 Sep 2015 14:13:30 -0700 Subject: Camera3Device: Bookkeeping reprocess shutters separately Bookkeeping reprocess shutters separately so regular and reprocess shutters together don't need to come in order. Bug: 24497512 Change-Id: I4aaf22045131e9e2e26bf163f7df9ff4c5cd6259 --- .../libcameraservice/device3/Camera3Device.cpp | 36 ++++++++++++++-------- .../libcameraservice/device3/Camera3Device.h | 3 ++ 2 files changed, 27 insertions(+), 12 deletions(-) (limited to 'services') diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 1a3a770..50d9d75 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -67,6 +67,7 @@ Camera3Device::Camera3Device(int id): mNextResultFrameNumber(0), mNextReprocessResultFrameNumber(0), mNextShutterFrameNumber(0), + mNextReprocessShutterFrameNumber(0), mListener(NULL) { ATRACE_CALL(); @@ -2534,18 +2535,6 @@ void Camera3Device::notifyError(const camera3_error_msg_t &msg, void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg, NotificationListener *listener) { ssize_t idx; - // Verify ordering of shutter notifications - { - Mutex::Autolock l(mOutputLock); - // TODO: need to track errors for tighter bounds on expected frame number. - if (msg.frame_number < mNextShutterFrameNumber) { - SET_ERR("Shutter notification out-of-order. Expected " - "notification for frame %d, got frame %d", - mNextShutterFrameNumber, msg.frame_number); - return; - } - mNextShutterFrameNumber = msg.frame_number + 1; - } // Set timestamp for the request in the in-flight tracking // and get the request ID to send upstream @@ -2555,6 +2544,29 @@ void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg, if (idx >= 0) { InFlightRequest &r = mInFlightMap.editValueAt(idx); + // Verify ordering of shutter notifications + { + Mutex::Autolock l(mOutputLock); + // TODO: need to track errors for tighter bounds on expected frame number. + if (r.hasInputBuffer) { + if (msg.frame_number < mNextReprocessShutterFrameNumber) { + SET_ERR("Shutter notification out-of-order. Expected " + "notification for frame %d, got frame %d", + mNextReprocessShutterFrameNumber, msg.frame_number); + return; + } + mNextReprocessShutterFrameNumber = msg.frame_number + 1; + } else { + if (msg.frame_number < mNextShutterFrameNumber) { + SET_ERR("Shutter notification out-of-order. Expected " + "notification for frame %d, got frame %d", + mNextShutterFrameNumber, msg.frame_number); + return; + } + mNextShutterFrameNumber = msg.frame_number + 1; + } + } + ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %" PRId64, mId, __FUNCTION__, msg.frame_number, r.resultExtras.requestId, msg.timestamp); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 402cb1d..c96553a 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -771,7 +771,10 @@ class Camera3Device : uint32_t mNextResultFrameNumber; // the minimal frame number of the next reprocess result uint32_t mNextReprocessResultFrameNumber; + // the minimal frame number of the next non-reprocess shutter uint32_t mNextShutterFrameNumber; + // the minimal frame number of the next reprocess shutter + uint32_t mNextReprocessShutterFrameNumber; List mResultQueue; Condition mResultSignal; NotificationListener *mListener; -- cgit v1.1 From 4a8f4a3f567d8b3134b1c7ab21ca774f279ab9c2 Mon Sep 17 00:00:00 2001 From: Chien-Yu Chen Date: Thu, 1 Oct 2015 15:23:22 -0700 Subject: Camera3Device: Change HFR request thread priority to 1 Based on periods of the request thread and audio threads with SCHED_FIFO policy, 1 is a more reasonable priority for HFR request thread. Bug: 24427480 Change-Id: I91f0066a0e114fc83abcc6a604ecbaa72c6a34e8 --- services/camera/libcameraservice/device3/Camera3Device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'services') diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index c96553a..2cd5af3 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -162,7 +162,7 @@ class Camera3Device : static const size_t kInFlightWarnLimit = 20; static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8 // SCHED_FIFO priority for request submission thread in HFR mode - static const int kConstrainedHighSpeedThreadPriority = 3; + static const int kConstrainedHighSpeedThreadPriority = 1; struct RequestTrigger; // minimal jpeg buffer size: 256KB + blob header -- cgit v1.1