summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorChien-Yu Chen <cychen@google.com>2015-02-17 13:56:46 -0800
committerChien-Yu Chen <cychen@google.com>2015-03-03 14:07:47 -0800
commit88da526d97442c80731e01bfc94c6b47c4b0c3c7 (patch)
treed62e3b5051bd55ac6f2bb0e4762a15be28650c5a /services
parent7841f704fee0e5acd45fa6e47a336120c3cad42c (diff)
downloadframeworks_av-88da526d97442c80731e01bfc94c6b47c4b0c3c7.zip
frameworks_av-88da526d97442c80731e01bfc94c6b47c4b0c3c7.tar.gz
frameworks_av-88da526d97442c80731e01bfc94c6b47c4b0c3c7.tar.bz2
camera: fix flashlight implementation for HAL v2
Update torch availability when the camera device availability changes. For device HAL v2 and v3 implementation, notify torch unavailable for all camera devices with a flash unit when a camera device is opened. Notify torch available for all camera devices with flash unit when all camera devices are closed. Don't invoke torch status callback in camera service. Invoke torch status callback in HAL or FlashControlBase implementations to avoid race condition. Clean up previous CL. Bug: 2682206 Change-Id: I24f5478f467b2c680565fe98f112eef33e2547a1
Diffstat (limited to 'services')
-rw-r--r--services/camera/libcameraservice/CameraFlashlight.cpp330
-rw-r--r--services/camera/libcameraservice/CameraFlashlight.h72
-rw-r--r--services/camera/libcameraservice/CameraService.cpp201
-rw-r--r--services/camera/libcameraservice/CameraService.h21
4 files changed, 423 insertions, 201 deletions
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 00a70eb..a00a49f 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "CameraFlashlight"
#define ATRACE_TAG ATRACE_TAG_CAMERA
-#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -32,16 +32,21 @@
namespace android {
+/////////////////////////////////////////////////////////////////////
+// CameraFlashlight implementation begins
+// used by camera service to control flashflight.
+/////////////////////////////////////////////////////////////////////
CameraFlashlight::CameraFlashlight(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
mCameraModule(&cameraModule),
- mCallbacks(&callbacks) {
+ mCallbacks(&callbacks),
+ mFlashlightMapInitialized(false) {
}
CameraFlashlight::~CameraFlashlight() {
}
-status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
+status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) {
ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
cameraId.string());
if (mFlashControl != NULL) {
@@ -52,7 +57,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
if (mCameraModule->getRawModule()->module_api_version >=
CAMERA_MODULE_API_VERSION_2_4) {
- mFlashControl = new FlashControl(*mCameraModule, *mCallbacks);
+ mFlashControl = new ModuleFlashControl(*mCameraModule, *mCallbacks);
if (mFlashControl == NULL) {
ALOGV("%s: cannot create flash control for module api v2.4+",
__FUNCTION__);
@@ -67,7 +72,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
res = mCameraModule->getCameraInfo(
atoi(String8(cameraId).string()), &info);
if (res) {
- ALOGV("%s: failed to get camera info for camera %s",
+ ALOGE("%s: failed to get camera info for camera %s",
__FUNCTION__, cameraId.string());
return res;
}
@@ -83,8 +88,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
}
mFlashControl = flashControl;
- }
- else {
+ } else {
// todo: implement for device api 1
return INVALID_OPERATION;
}
@@ -93,8 +97,9 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
return OK;
}
-status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled) {
- if (!mCameraModule) {
+status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) {
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
return NO_INIT;
}
@@ -105,6 +110,10 @@ status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled)
Mutex::Autolock l(mLock);
if (mFlashControl == NULL) {
+ if (enabled == false) {
+ return OK;
+ }
+
res = createFlashlightControl(cameraId);
if (res) {
return res;
@@ -130,88 +139,169 @@ status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled)
return res;
}
-bool CameraFlashlight::hasFlashUnit(const String16& cameraId) {
+status_t CameraFlashlight::findFlashUnits() {
+ Mutex::Autolock l(mLock);
status_t res;
+ int32_t numCameras = mCameraModule->getNumberOfCameras();
- Mutex::Autolock l(mLock);
+ mHasFlashlightMap.clear();
+ mFlashlightMapInitialized = false;
- if (mFlashControl == NULL) {
- res = createFlashlightControl(cameraId);
+ for (int32_t i = 0; i < numCameras; i++) {
+ bool hasFlash = false;
+ String8 id = String8::format("%d", i);
+
+ res = createFlashlightControl(id);
if (res) {
- ALOGE("%s: failed to create flash control for %s ",
- __FUNCTION__, cameraId.string());
- return false;
+ ALOGE("%s: failed to create flash control for %s", __FUNCTION__,
+ id.string());
+ } else {
+ res = mFlashControl->hasFlashUnit(id, &hasFlash);
+ if (res == -EUSERS || res == -EBUSY) {
+ ALOGE("%s: failed to check if camera %s has a flash unit. Some "
+ "camera devices may be opened", __FUNCTION__,
+ id.string());
+ return res;
+ } else if (res) {
+ ALOGE("%s: failed to check if camera %s has a flash unit. %s"
+ " (%d)", __FUNCTION__, id.string(), strerror(-res),
+ res);
+ }
+
+ mFlashControl.clear();
}
+ mHasFlashlightMap.add(id, hasFlash);
}
- bool flashUnit = false;
+ mFlashlightMapInitialized = true;
+ return OK;
+}
- // if flash control already exists, querying if a camera device has a flash
- // unit may fail if it's module v1
- res = mFlashControl->hasFlashUnit(cameraId, &flashUnit);
- if (res == BAD_INDEX) {
- // need to close the flash control before query.
- mFlashControl.clear();
- res = createFlashlightControl(cameraId);
- if (res) {
- ALOGE("%s: failed to create flash control for %s ", __FUNCTION__,
- cameraId.string());
- return false;
- }
- res = mFlashControl->hasFlashUnit(cameraId, &flashUnit);
- if (res) {
- flashUnit = false;
- }
+bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
+ status_t res;
+
+ Mutex::Autolock l(mLock);
+ return hasFlashUnitLocked(cameraId);
+}
+
+bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) {
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return false;
}
- return flashUnit;
+ ssize_t index = mHasFlashlightMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: camera %s not present when findFlashUnits() was called",
+ __FUNCTION__, cameraId.string());
+ return false;
+ }
+
+ return mHasFlashlightMap.valueAt(index);
}
-status_t CameraFlashlight::prepareDeviceOpen() {
+status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) {
ALOGV("%s: prepare for device open", __FUNCTION__);
Mutex::Autolock l(mLock);
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return NO_INIT;
+ }
- if (mCameraModule && mCameraModule->getRawModule()->module_api_version <
+ if (mCameraModule->getRawModule()->module_api_version <
CAMERA_MODULE_API_VERSION_2_4) {
// framework is going to open a camera device, all flash light control
// should be closed for backward compatible support.
- if (mFlashControl != NULL) {
- mFlashControl.clear();
+ mFlashControl.clear();
+
+ if (mOpenedCameraIds.size() == 0) {
+ // notify torch unavailable for all cameras with a flash
+ int numCameras = mCameraModule->getNumberOfCameras();
+ for (int i = 0; i < numCameras; i++) {
+ if (hasFlashUnitLocked(String8::format("%d", i))) {
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ String8::format("%d", i).string(),
+ TORCH_MODE_STATUS_NOT_AVAILABLE);
+ }
+ }
}
+
+ // close flash control that may be opened by calling hasFlashUnitLocked.
+ mFlashControl.clear();
+ }
+
+ if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
+ mOpenedCameraIds.add(cameraId);
}
return OK;
}
+status_t CameraFlashlight::deviceClosed(const String8& cameraId) {
+ ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string());
-FlashControlBase::~FlashControlBase() {
+ Mutex::Autolock l(mLock);
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return NO_INIT;
+ }
+
+ ssize_t index = mOpenedCameraIds.indexOf(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__,
+ cameraId.string());
+ } else {
+ mOpenedCameraIds.removeAt(index);
+ }
+
+ // Cannot do anything until all cameras are closed.
+ if (mOpenedCameraIds.size() != 0)
+ return OK;
+
+ if (mCameraModule->getRawModule()->module_api_version <
+ CAMERA_MODULE_API_VERSION_2_4) {
+ // notify torch available for all cameras with a flash
+ int numCameras = mCameraModule->getNumberOfCameras();
+ for (int i = 0; i < numCameras; i++) {
+ if (hasFlashUnitLocked(String8::format("%d", i))) {
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ String8::format("%d", i).string(),
+ TORCH_MODE_STATUS_AVAILABLE_OFF);
+ }
+ }
+ }
+
+ return OK;
}
+// CameraFlashlight implementation ends
-FlashControl::FlashControl(CameraModule& cameraModule,
+FlashControlBase::~FlashControlBase() {
+}
+
+/////////////////////////////////////////////////////////////////////
+// ModuleFlashControl implementation begins
+// Flash control for camera module v2.4 and above.
+/////////////////////////////////////////////////////////////////////
+ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
mCameraModule(&cameraModule) {
}
-FlashControl::~FlashControl() {
+ModuleFlashControl::~ModuleFlashControl() {
}
-status_t FlashControl::hasFlashUnit(const String16& cameraId, bool *hasFlash) {
+status_t ModuleFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) {
if (!hasFlash) {
return BAD_VALUE;
}
*hasFlash = false;
-
Mutex::Autolock l(mLock);
- if (!mCameraModule) {
- return NO_INIT;
- }
-
camera_info info;
- status_t res = mCameraModule->getCameraInfo(atoi(String8(cameraId).string()),
+ status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()),
&info);
if (res != 0) {
return res;
@@ -228,33 +318,31 @@ status_t FlashControl::hasFlashUnit(const String16& cameraId, bool *hasFlash) {
return OK;
}
-status_t FlashControl::setTorchMode(const String16& cameraId, bool enabled) {
+status_t ModuleFlashControl::setTorchMode(const String8& cameraId, bool enabled) {
ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
cameraId.string(), enabled);
Mutex::Autolock l(mLock);
- if (!mCameraModule) {
- return NO_INIT;
- }
-
- return mCameraModule->setTorchMode(String8(cameraId).string(), enabled);
+ return mCameraModule->setTorchMode(cameraId.string(), enabled);
}
+// ModuleFlashControl implementation ends
+/////////////////////////////////////////////////////////////////////
+// CameraDeviceClientFlashControl implementation begins
+// Flash control for camera module <= v2.3 and camera HAL v2-v3
+/////////////////////////////////////////////////////////////////////
CameraDeviceClientFlashControl::CameraDeviceClientFlashControl(
CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
mCameraModule(&cameraModule),
mCallbacks(&callbacks),
mTorchEnabled(false),
- mMetadata(NULL) {
+ mMetadata(NULL),
+ mStreaming(false) {
}
CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
- if (mDevice != NULL) {
- mDevice->flush();
- mDevice->deleteStream(mStreamId);
- mDevice.clear();
- }
+ disconnectCameraDevice();
if (mMetadata) {
delete mMetadata;
}
@@ -269,13 +357,13 @@ CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
ALOGV("%s: notify the framework that torch was turned off",
__FUNCTION__);
mCallbacks->torch_mode_status_change(mCallbacks,
- String8(mCameraId).string(), TORCH_MODE_STATUS_OFF);
+ mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
}
}
}
-status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width,
- int32_t height) {
+status_t CameraDeviceClientFlashControl::initializeSurface(
+ sp<CameraDeviceBase> &device, int32_t width, int32_t height) {
status_t res;
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
@@ -295,27 +383,16 @@ status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width,
return res;
}
- bool useAsync = false;
- int32_t consumerUsage;
- res = mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
- if (res) {
- return res;
- }
-
- if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
- useAsync = true;
- }
-
- mAnw = new Surface(mProducer, useAsync);
+ mAnw = new Surface(mProducer, /*useAsync*/ true);
if (mAnw == NULL) {
return NO_MEMORY;
}
- res = mDevice->createStream(mAnw, width, height, format, &mStreamId);
+ res = device->createStream(mAnw, width, height, format, &mStreamId);
if (res) {
return res;
}
- res = mDevice->configureStreams();
+ res = device->configureStreams();
if (res) {
return res;
}
@@ -342,7 +419,21 @@ status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
int32_t ww = streamConfigs.data.i32[i + 1];
int32_t hh = streamConfigs.data.i32[i + 2];
- if (w* h > ww * hh) {
+ if (w * h > ww * hh) {
+ w = ww;
+ h = hh;
+ }
+ }
+ }
+
+ // if stream configuration is not found, try available processed sizes.
+ if (streamConfigs.count == 0) {
+ camera_metadata_entry availableProcessedSizes =
+ metadata.find(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+ for (size_t i = 0; i < availableProcessedSizes.count; i += 2) {
+ int32_t ww = availableProcessedSizes.data.i32[i];
+ int32_t hh = availableProcessedSizes.data.i32[i + 1];
+ if (w * h > ww * hh) {
w = ww;
h = hh;
}
@@ -360,24 +451,24 @@ status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
}
status_t CameraDeviceClientFlashControl::connectCameraDevice(
- const String16& cameraId) {
- String8 id = String8(cameraId);
+ const String8& cameraId) {
camera_info info;
- status_t res = mCameraModule->getCameraInfo(atoi(id.string()), &info);
+ status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), &info);
if (res != 0) {
ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
- mCameraId.string());
+ cameraId.string());
return res;
}
- mDevice = CameraDeviceFactory::createDevice(atoi(id.string()));
- if (mDevice == NULL) {
+ sp<CameraDeviceBase> device =
+ CameraDeviceFactory::createDevice(atoi(cameraId.string()));
+ if (device == NULL) {
return NO_MEMORY;
}
- res = mDevice->initialize(mCameraModule);
+ res = device->initialize(mCameraModule);
if (res) {
- goto fail;
+ return res;
}
int32_t width, height;
@@ -385,22 +476,30 @@ status_t CameraDeviceClientFlashControl::connectCameraDevice(
if (res) {
return res;
}
- res = initializeSurface(width, height);
+ res = initializeSurface(device, width, height);
if (res) {
- goto fail;
+ return res;
}
mCameraId = cameraId;
+ mStreaming = (info.device_version <= CAMERA_DEVICE_API_VERSION_3_1);
+ mDevice = device;
return OK;
+}
-fail:
- mDevice.clear();
- return res;
+status_t CameraDeviceClientFlashControl::disconnectCameraDevice() {
+ if (mDevice != NULL) {
+ mDevice->disconnect();
+ mDevice.clear();
+ }
+
+ return OK;
}
-status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId,
+
+status_t CameraDeviceClientFlashControl::hasFlashUnit(const String8& cameraId,
bool *hasFlash) {
ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__,
cameraId.string());
@@ -411,19 +510,14 @@ status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId,
}
status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
- const String16& cameraId, bool *hasFlash) {
- if (!mCameraModule) {
- ALOGE("%s: camera module is NULL", __FUNCTION__);
- return NO_INIT;
- }
-
+ const String8& cameraId, bool *hasFlash) {
if (!hasFlash) {
return BAD_VALUE;
}
camera_info info;
status_t res = mCameraModule->getCameraInfo(
- atoi(String8(cameraId).string()), &info);
+ atoi(cameraId.string()), &info);
if (res != 0) {
ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
cameraId.string());
@@ -441,7 +535,7 @@ status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
return OK;
}
-status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) {
+status_t CameraDeviceClientFlashControl::submitTorchEnabledRequest() {
status_t res;
if (mMetadata == NULL) {
@@ -456,27 +550,29 @@ status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) {
}
}
- uint8_t torchOn = enabled ? ANDROID_FLASH_MODE_TORCH :
- ANDROID_FLASH_MODE_OFF;
-
+ uint8_t torchOn = ANDROID_FLASH_MODE_TORCH;
mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1);
mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 1);
+ uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
+ mMetadata->update(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+
int32_t requestId = 0;
mMetadata->update(ANDROID_REQUEST_ID, &requestId, 1);
- List<const CameraMetadata> metadataRequestList;
- metadataRequestList.push_back(*mMetadata);
-
- int64_t lastFrameNumber = 0;
- res = mDevice->captureList(metadataRequestList, &lastFrameNumber);
-
+ if (mStreaming) {
+ res = mDevice->setStreamingRequest(*mMetadata);
+ } else {
+ res = mDevice->capture(*mMetadata);
+ }
return res;
}
+
+
status_t CameraDeviceClientFlashControl::setTorchMode(
- const String16& cameraId, bool enabled) {
+ const String8& cameraId, bool enabled) {
bool hasFlash = false;
Mutex::Autolock l(mLock);
@@ -499,6 +595,13 @@ status_t CameraDeviceClientFlashControl::setTorchMode(
} else if (mDevice == NULL || cameraId != mCameraId) {
// disabling the torch mode of an un-opened or different device.
return OK;
+ } else {
+ // disabling the torch mode of currently opened device
+ disconnectCameraDevice();
+ mTorchEnabled = false;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ return OK;
}
if (mDevice == NULL) {
@@ -508,13 +611,16 @@ status_t CameraDeviceClientFlashControl::setTorchMode(
}
}
- res = submitTorchRequest(enabled);
+ res = submitTorchEnabledRequest();
if (res) {
return res;
}
- mTorchEnabled = enabled;
+ mTorchEnabled = true;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
return OK;
}
+// CameraDeviceClientFlashControl implementation ends
}
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
index a0de0b0..ae502b9 100644
--- a/services/camera/libcameraservice/CameraFlashlight.h
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -19,6 +19,7 @@
#include "hardware/camera_common.h"
#include "utils/KeyedVector.h"
+#include "utils/SortedVector.h"
#include "gui/GLConsumer.h"
#include "gui/Surface.h"
#include "common/CameraDeviceBase.h"
@@ -37,11 +38,11 @@ class FlashControlBase : public virtual VirtualLightRefBase {
// cause the torch mode to be turned off in HAL v1 devices. If
// previously-on torch mode is turned off,
// callbacks.torch_mode_status_change() should be invoked.
- virtual status_t hasFlashUnit(const String16& cameraId,
+ virtual status_t hasFlashUnit(const String8& cameraId,
bool *hasFlash) = 0;
// set the torch mode to on or off.
- virtual status_t setTorchMode(const String16& cameraId,
+ virtual status_t setTorchMode(const String8& cameraId,
bool enabled) = 0;
};
@@ -54,43 +55,61 @@ class CameraFlashlight : public virtual VirtualLightRefBase {
const camera_module_callbacks_t& callbacks);
virtual ~CameraFlashlight();
- // set the torch mode to on or off.
- status_t setTorchMode(const String16& cameraId, bool enabled);
+ // Find all flash units. This must be called before other methods. All
+ // camera devices must be closed when it's called because HAL v1 devices
+ // need to be opened to query available flash modes.
+ status_t findFlashUnits();
- // Whether a camera device has a flash unit. Calling this function may
- // cause the torch mode to be turned off in HAL v1 devices.
- bool hasFlashUnit(const String16& cameraId);
+ // Whether a camera device has a flash unit. Before findFlashUnits() is
+ // called, this function always returns false.
+ bool hasFlashUnit(const String8& cameraId);
+
+ // set the torch mode to on or off.
+ status_t setTorchMode(const String8& cameraId, bool enabled);
// Notify CameraFlashlight that camera service is going to open a camera
// device. CameraFlashlight will free the resources that may cause the
// camera open to fail. Camera service must call this function before
// opening a camera device.
- status_t prepareDeviceOpen();
+ status_t prepareDeviceOpen(const String8& cameraId);
+
+ // Notify CameraFlashlight that camera service has closed a camera
+ // device. CameraFlashlight may invoke callbacks for torch mode
+ // available depending on the implementation.
+ status_t deviceClosed(const String8& cameraId);
private:
// create flashlight control based on camera module API and camera
// device API versions.
- status_t createFlashlightControl(const String16& cameraId);
+ status_t createFlashlightControl(const String8& cameraId);
+
+ // mLock should be locked.
+ bool hasFlashUnitLocked(const String8& cameraId);
sp<FlashControlBase> mFlashControl;
CameraModule *mCameraModule;
const camera_module_callbacks_t *mCallbacks;
+ SortedVector<String8> mOpenedCameraIds;
- Mutex mLock;
+ // camera id -> if it has a flash unit
+ KeyedVector<String8, bool> mHasFlashlightMap;
+ bool mFlashlightMapInitialized;
+
+ Mutex mLock; // protect CameraFlashlight API
};
/**
* Flash control for camera module v2.4 and above.
*/
-class FlashControl : public FlashControlBase {
+class ModuleFlashControl : public FlashControlBase {
public:
- FlashControl(CameraModule& cameraModule,
+ ModuleFlashControl(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks);
- virtual ~FlashControl();
+ virtual ~ModuleFlashControl();
// FlashControlBase
- status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
- status_t setTorchMode(const String16& cameraId, bool enabled);
+ status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
+ status_t setTorchMode(const String8& cameraId, bool enabled);
private:
CameraModule *mCameraModule;
@@ -108,30 +127,37 @@ class CameraDeviceClientFlashControl : public FlashControlBase {
virtual ~CameraDeviceClientFlashControl();
// FlashControlBase
- status_t setTorchMode(const String16& cameraId, bool enabled);
- status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
+ status_t setTorchMode(const String8& cameraId, bool enabled);
+ status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
private:
// connect to a camera device
- status_t connectCameraDevice(const String16& cameraId);
+ status_t connectCameraDevice(const String8& cameraId);
+ // disconnect and free mDevice
+ status_t disconnectCameraDevice();
// initialize a surface
- status_t initializeSurface(int32_t width, int32_t height);
+ status_t initializeSurface(sp<CameraDeviceBase>& device, int32_t width,
+ int32_t height);
- // submit a request with the given torch mode
- status_t submitTorchRequest(bool enabled);
+ // submit a request to enable the torch mode
+ status_t submitTorchEnabledRequest();
// get the smallest surface size of IMPLEMENTATION_DEFINED
status_t getSmallestSurfaceSize(const camera_info& info, int32_t *width,
int32_t *height);
- status_t hasFlashUnitLocked(const String16& cameraId, bool *hasFlash);
+ status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash);
CameraModule *mCameraModule;
const camera_module_callbacks_t *mCallbacks;
- String16 mCameraId;
+ String8 mCameraId;
bool mTorchEnabled;
CameraMetadata *mMetadata;
+ // WORKAROUND: will be set to true for HAL v2 devices where
+ // setStreamingRequest() needs to be call for torch mode settings to
+ // take effect.
+ bool mStreaming;
sp<CameraDeviceBase> mDevice;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index d65ac21..8fdfaa8 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -101,14 +101,14 @@ static void torch_mode_status_change(
ICameraServiceListener::TorchStatus status;
switch (new_status) {
- case TORCH_MODE_STATUS_AVAILABLE:
- status = ICameraServiceListener::TORCH_STATUS_AVAILABLE;
- break;
- case TORCH_MODE_STATUS_RESOURCE_BUSY:
+ case TORCH_MODE_STATUS_NOT_AVAILABLE:
status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
break;
- case TORCH_MODE_STATUS_OFF:
- status = ICameraServiceListener::TORCH_STATUS_OFF;
+ case TORCH_MODE_STATUS_AVAILABLE_OFF:
+ status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF;
+ break;
+ case TORCH_MODE_STATUS_AVAILABLE_ON:
+ status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON;
break;
default:
ALOGE("Unknown torch status %d", new_status);
@@ -116,7 +116,7 @@ static void torch_mode_status_change(
}
cs->onTorchStatusChanged(
- String16(camera_id),
+ String8(camera_id),
status);
}
} // extern "C"
@@ -156,23 +156,29 @@ void CameraService::onFirstRef()
}
else {
mModule = new CameraModule(rawModule);
- mFlashlight = new CameraFlashlight(*mModule, *this);
-
const hw_module_t *common = mModule->getRawModule();
- ALOGI("Loaded \"%s\" camera module", common->name);
+ ALOGI("Loaded \"%s\" cameraCa module", common->name);
mNumberOfCameras = mModule->getNumberOfCameras();
if (mNumberOfCameras > MAX_CAMERAS) {
ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
+
+ mFlashlight = new CameraFlashlight(*mModule, *this);
+ status_t res = mFlashlight->findFlashUnits();
+ if (res) {
+ // impossible because we haven't open any camera devices.
+ ALOGE("failed to find flash units.");
+ }
+
for (int i = 0; i < mNumberOfCameras; i++) {
setCameraFree(i);
- String16 cameraName = String16(String8::format("%d", i));
+ String8 cameraName = String8::format("%d", i);
if (mFlashlight->hasFlashUnit(cameraName)) {
mTorchStatusMap.add(cameraName,
- ICameraServiceListener::TORCH_STATUS_AVAILABLE);
+ ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
}
}
@@ -207,7 +213,7 @@ CameraService::~CameraService() {
void CameraService::onDeviceStatusChanged(int cameraId,
int newStatus)
{
- ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
+ ALOGV("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
cameraId, newStatus);
if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
@@ -268,24 +274,30 @@ void CameraService::onDeviceStatusChanged(int cameraId,
}
-void CameraService::onTorchStatusChanged(const String16& cameraId,
+void CameraService::onTorchStatusChanged(const String8& cameraId,
ICameraServiceListener::TorchStatus newStatus) {
Mutex::Autolock al(mTorchStatusMutex);
onTorchStatusChangedLocked(cameraId, newStatus);
}
-void CameraService::onTorchStatusChangedLocked(const String16& cameraId,
+void CameraService::onTorchStatusChangedLocked(const String8& cameraId,
ICameraServiceListener::TorchStatus newStatus) {
ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
__FUNCTION__, cameraId.string(), newStatus);
- if (getTorchStatusLocked(cameraId) == newStatus) {
+ ICameraServiceListener::TorchStatus status;
+ status_t res = getTorchStatusLocked(cameraId, &status);
+ if (res) {
+ ALOGE("%s: cannot get torch status of camera %s", cameraId.string());
+ return;
+ }
+ if (status == newStatus) {
ALOGE("%s: Torch state transition to the same status 0x%x not allowed",
__FUNCTION__, (uint32_t)newStatus);
return;
}
- status_t res = setTorchStatusLocked(cameraId, newStatus);
+ res = setTorchStatusLocked(cameraId, newStatus);
if (res) {
ALOGE("%s: Failed to set the torch status", __FUNCTION__,
(uint32_t)newStatus);
@@ -294,7 +306,7 @@ void CameraService::onTorchStatusChangedLocked(const String16& cameraId,
Vector<sp<ICameraServiceListener> >::const_iterator it;
for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
- (*it)->onTorchStatusChanged(newStatus, cameraId);
+ (*it)->onTorchStatusChanged(newStatus, String16(cameraId.string()));
}
}
@@ -754,7 +766,7 @@ status_t CameraService::connectHelperLocked(
bool legacyMode) {
// give flashlight a chance to close devices if necessary.
- mFlashlight->prepareDeviceOpen();
+ mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId));
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
@@ -932,44 +944,94 @@ status_t CameraService::connectLegacy(
return OK;
}
+bool CameraService::validCameraIdForSetTorchMode(const String8& cameraId) {
+ // invalid string for int
+ if (cameraId.string() == NULL) {
+ return false;
+ }
+ errno = 0;
+ char *endptr;
+ long id = strtol(cameraId.string(), &endptr, 10); // base 10
+ if (errno || id > INT_MAX || id < INT_MIN || *endptr != 0) {
+ return false;
+ }
+
+ // id matches one of the plugged-in devices?
+ ICameraServiceListener::Status deviceStatus = getStatus(id);
+ if (deviceStatus != ICameraServiceListener::STATUS_PRESENT &&
+ deviceStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ return false;
+ }
+
+ return true;
+}
+
status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) {
if (enabled && clientBinder == NULL) {
ALOGE("%s: torch client binder is NULL", __FUNCTION__);
- return -ENOSYS;
+ return -EINVAL;
}
- Mutex::Autolock al(mTorchStatusMutex);
- status_t res = mFlashlight->setTorchMode(cameraId, enabled);
+ String8 id = String8(cameraId.string());
+
+ // verify id is valid.
+ if (validCameraIdForSetTorchMode(id) == false) {
+ ALOGE("%s: camera id is invalid %s", id.string());
+ return -EINVAL;
+ }
+
+ {
+ Mutex::Autolock al(mTorchStatusMutex);
+ ICameraServiceListener::TorchStatus status;
+ status_t res = getTorchStatusLocked(id, &status);
+ if (res) {
+ ALOGE("%s: getting current torch status failed for camera %s",
+ __FUNCTION__, id.string());
+ return -EINVAL;
+ }
+
+ if (status == ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE) {
+ if (getStatus(atoi(id.string())) ==
+ ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ ALOGE("%s: torch mode of camera %s is not available because "
+ "camera is in use", __FUNCTION__, id.string());
+ return -EBUSY;
+ } else {
+ ALOGE("%s: torch mode of camera %s is not available due to "
+ "insufficient resources", __FUNCTION__, id.string());
+ return -EUSERS;
+ }
+ }
+ }
+
+ status_t res = mFlashlight->setTorchMode(id, enabled);
if (res) {
- ALOGE("%s: setting torch mode of camera %s to %d failed", __FUNCTION__,
- cameraId.string(), enabled);
+ ALOGE("%s: setting torch mode of camera %s to %d failed. %s (%d)",
+ __FUNCTION__, id.string(), enabled, strerror(-res), res);
return res;
}
- // update the link to client's death
- ssize_t index = mTorchClientMap.indexOfKey(cameraId);
- if (enabled) {
- if (index == NAME_NOT_FOUND) {
- mTorchClientMap.add(cameraId, clientBinder);
- } else {
- const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
- oldBinder->unlinkToDeath(this);
+ {
+ // update the link to client's death
+ Mutex::Autolock al(mTorchClientMapMutex);
+ ssize_t index = mTorchClientMap.indexOfKey(id);
+ if (enabled) {
+ if (index == NAME_NOT_FOUND) {
+ mTorchClientMap.add(id, clientBinder);
+ } else {
+ const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+ oldBinder->unlinkToDeath(this);
- mTorchClientMap.replaceValueAt(index, clientBinder);
+ mTorchClientMap.replaceValueAt(index, clientBinder);
+ }
+ clientBinder->linkToDeath(this);
+ } else if (index != NAME_NOT_FOUND) {
+ sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+ oldBinder->unlinkToDeath(this);
}
- clientBinder->linkToDeath(this);
- } else if (index != NAME_NOT_FOUND) {
- sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
- oldBinder->unlinkToDeath(this);
}
- // notify the listeners the change.
- ICameraServiceListener::TorchStatus status = enabled ?
- ICameraServiceListener::TORCH_STATUS_ON :
- ICameraServiceListener::TORCH_STATUS_OFF;
- onTorchStatusChangedLocked(cameraId, status);
-
return OK;
}
@@ -1099,7 +1161,7 @@ status_t CameraService::connectDevice(
int deviceVersion = getDeviceVersion(cameraId, &facing);
// give flashlight a chance to close devices if necessary.
- mFlashlight->prepareDeviceOpen();
+ mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId));
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
@@ -1176,8 +1238,8 @@ status_t CameraService::addListener(
{
Mutex::Autolock al(mTorchStatusMutex);
for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) {
- listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i),
- mTorchStatusMap.keyAt(i));
+ String16 id = String16(mTorchStatusMap.keyAt(i).string());
+ listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i), id);
}
}
@@ -1616,6 +1678,9 @@ status_t CameraService::BasicClient::finishCameraOps() {
mCameraId,
&rejectSourceStates);
+ // Notify flashlight that a camera device is closed.
+ mCameraService->mFlashlight->deviceClosed(
+ String8::format("%d", mCameraId));
}
// Always stop watching, even if no camera op is active
if (mOpsCallback != NULL) {
@@ -1862,17 +1927,18 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
}
void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) {
- Mutex::Autolock al(mTorchStatusMutex);
+ Mutex::Autolock al(mTorchClientMapMutex);
for (size_t i = 0; i < mTorchClientMap.size(); i++) {
if (mTorchClientMap[i] == who) {
// turn off the torch mode that was turned on by dead client
- String16 cameraId = mTorchClientMap.keyAt(i);
- mFlashlight->setTorchMode(cameraId, false);
+ String8 cameraId = mTorchClientMap.keyAt(i);
+ status_t res = mFlashlight->setTorchMode(cameraId, false);
+ if (res) {
+ ALOGE("%s: torch client died but couldn't turn off torch: "
+ "%s (%d)", __FUNCTION__, strerror(-res), res);
+ return;
+ }
mTorchClientMap.removeItemsAt(i);
-
- // notify torch mode was turned off
- onTorchStatusChangedLocked(cameraId,
- ICameraServiceListener::TORCH_STATUS_OFF);
break;
}
}
@@ -1968,6 +2034,19 @@ void CameraService::updateStatus(ICameraServiceListener::Status status,
}
}
+ if (status == ICameraServiceListener::STATUS_NOT_PRESENT ||
+ status == ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ // update torch status to not available when the camera device
+ // becomes not present or not available.
+ onTorchStatusChanged(String8::format("%d", cameraId),
+ ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE);
+ } else if (status == ICameraServiceListener::STATUS_PRESENT) {
+ // update torch status to available when the camera device becomes
+ // present or available
+ onTorchStatusChanged(String8::format("%d", cameraId),
+ ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
+ }
+
Vector<sp<ICameraServiceListener> >::const_iterator it;
for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
(*it)->onStatusChanged(status, cameraId);
@@ -1985,17 +2064,23 @@ ICameraServiceListener::Status CameraService::getStatus(int cameraId) const {
return mStatusList[cameraId];
}
-ICameraServiceListener::TorchStatus CameraService::getTorchStatusLocked(
- const String16& cameraId) const {
+status_t CameraService::getTorchStatusLocked(
+ const String8& cameraId,
+ ICameraServiceListener::TorchStatus *status) const {
+ if (!status) {
+ return BAD_VALUE;
+ }
ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
if (index == NAME_NOT_FOUND) {
- return ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+ // invalid camera ID or the camera doesn't have a flash unit
+ return NAME_NOT_FOUND;
}
- return mTorchStatusMap.valueAt(index);
+ *status = mTorchStatusMap.valueAt(index);
+ return OK;
}
-status_t CameraService::setTorchStatusLocked(const String16& cameraId,
+status_t CameraService::setTorchStatusLocked(const String8& cameraId,
ICameraServiceListener::TorchStatus status) {
ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
if (index == NAME_NOT_FOUND) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 84bcdb8..74b3623 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -72,7 +72,7 @@ public:
// HAL Callbacks
virtual void onDeviceStatusChanged(int cameraId,
int newStatus);
- virtual void onTorchStatusChanged(const String16& cameraId,
+ virtual void onTorchStatusChanged(const String8& cameraId,
ICameraServiceListener::TorchStatus
newStatus);
@@ -418,28 +418,33 @@ private:
// flashlight control
sp<CameraFlashlight> mFlashlight;
- // guard mTorchStatusMap and mTorchClientMap
+ // guard mTorchStatusMap
Mutex mTorchStatusMutex;
+ // guard mTorchClientMap
+ Mutex mTorchClientMapMutex;
// camera id -> torch status
- KeyedVector<String16, ICameraServiceListener::TorchStatus> mTorchStatusMap;
+ KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap;
// camera id -> torch client binder
// only store the last client that turns on each camera's torch mode
- KeyedVector<String16, sp<IBinder> > mTorchClientMap;
+ KeyedVector<String8, sp<IBinder> > mTorchClientMap;
// check and handle if torch client's process has died
void handleTorchClientBinderDied(const wp<IBinder> &who);
// handle torch mode status change and invoke callbacks. mTorchStatusMutex
// should be locked.
- void onTorchStatusChangedLocked(const String16& cameraId,
+ void onTorchStatusChangedLocked(const String8& cameraId,
ICameraServiceListener::TorchStatus newStatus);
+ // validate the camera id for use of setting a torch mode.
+ bool validCameraIdForSetTorchMode(const String8& cameraId);
+
// get a camera's torch status. mTorchStatusMutex should be locked.
- ICameraServiceListener::TorchStatus getTorchStatusLocked(
- const String16 &cameraId) const;
+ status_t getTorchStatusLocked(const String8 &cameraId,
+ ICameraServiceListener::TorchStatus *status) const;
// set a camera's torch status. mTorchStatusMutex should be locked.
- status_t setTorchStatusLocked(const String16 &cameraId,
+ status_t setTorchStatusLocked(const String8 &cameraId,
ICameraServiceListener::TorchStatus status);
// IBinder::DeathRecipient implementation