diff options
author | Eino-Ville Talvala <etalvala@google.com> | 2013-07-25 17:12:35 -0700 |
---|---|---|
committer | Eino-Ville Talvala <etalvala@google.com> | 2013-07-30 10:58:44 -0700 |
commit | 7b82efe7a376c882f8f938e1c41b8311a8cdda4a (patch) | |
tree | d7ed69f0a495bc1a873a285ba11e72a9867c5565 /services/camera/libcameraservice/api_pro | |
parent | d054c32443a493513ab63529b0c8b1aca290278c (diff) | |
download | frameworks_av-7b82efe7a376c882f8f938e1c41b8311a8cdda4a.zip frameworks_av-7b82efe7a376c882f8f938e1c41b8311a8cdda4a.tar.gz frameworks_av-7b82efe7a376c882f8f938e1c41b8311a8cdda4a.tar.bz2 |
Camera: Rename new API to camera2, rearrange camera service
- Support API rename from photography to camera2
- Reorganize camera service files
- API support files to api1/, api2/, api_pro/
- HAL device support files into device{1,2,3}/
- Common files into common/
- Camera service remains at top-level
Change-Id: Ie474c12536f543832fba0a2dc936ac4fd39fe6a9
Diffstat (limited to 'services/camera/libcameraservice/api_pro')
-rw-r--r-- | services/camera/libcameraservice/api_pro/ProCamera2Client.cpp | 446 | ||||
-rw-r--r-- | services/camera/libcameraservice/api_pro/ProCamera2Client.h | 123 |
2 files changed, 569 insertions, 0 deletions
diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp new file mode 100644 index 0000000..2b583e5 --- /dev/null +++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2013 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 "ProCamera2Client" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/Trace.h> + +#include <cutils/properties.h> +#include <gui/Surface.h> +#include <gui/Surface.h> + +#include "api_pro/ProCamera2Client.h" +#include "common/CameraDeviceBase.h" + +namespace android { +using namespace camera2; + +// Interface used by CameraService + +ProCamera2Client::ProCamera2Client(const sp<CameraService>& cameraService, + const sp<IProCameraCallbacks>& remoteCallback, + const String16& clientPackageName, + int cameraId, + int cameraFacing, + int clientPid, + uid_t clientUid, + int servicePid) : + Camera2ClientBase(cameraService, remoteCallback, clientPackageName, + cameraId, cameraFacing, clientPid, clientUid, servicePid) +{ + ATRACE_CALL(); + ALOGI("ProCamera %d: Opened", cameraId); + + mExclusiveLock = false; +} + +status_t ProCamera2Client::initialize(camera_module_t *module) +{ + ATRACE_CALL(); + status_t res; + + res = Camera2ClientBase::initialize(module); + if (res != OK) { + return res; + } + + String8 threadName; + mFrameProcessor = new FrameProcessorBase(mDevice); + threadName = String8::format("PC2-%d-FrameProc", mCameraId); + mFrameProcessor->run(threadName.string()); + + mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID, + FRAME_PROCESSOR_LISTENER_MAX_ID, + /*listener*/this); + + return OK; +} + +ProCamera2Client::~ProCamera2Client() { +} + +status_t ProCamera2Client::exclusiveTryLock() { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mBinderSerializationLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + if (!mDevice.get()) return PERMISSION_DENIED; + + if (!mExclusiveLock) { + mExclusiveLock = true; + + if (mRemoteCallback != NULL) { + mRemoteCallback->onLockStatusChanged( + IProCameraCallbacks::LOCK_ACQUIRED); + } + + ALOGV("%s: exclusive lock acquired", __FUNCTION__); + + return OK; + } + + // TODO: have a PERMISSION_DENIED case for when someone else owns the lock + + // don't allow recursive locking + ALOGW("%s: exclusive lock already exists - recursive locking is not" + "allowed", __FUNCTION__); + + return ALREADY_EXISTS; +} + +status_t ProCamera2Client::exclusiveLock() { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mBinderSerializationLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + if (!mDevice.get()) return PERMISSION_DENIED; + + /** + * TODO: this should asynchronously 'wait' until the lock becomes available + * if another client already has an exclusive lock. + * + * once we have proper sharing support this will need to do + * more than just return immediately + */ + if (!mExclusiveLock) { + mExclusiveLock = true; + + if (mRemoteCallback != NULL) { + mRemoteCallback->onLockStatusChanged(IProCameraCallbacks::LOCK_ACQUIRED); + } + + ALOGV("%s: exclusive lock acquired", __FUNCTION__); + + return OK; + } + + // don't allow recursive locking + ALOGW("%s: exclusive lock already exists - recursive locking is not allowed" + , __FUNCTION__); + return ALREADY_EXISTS; +} + +status_t ProCamera2Client::exclusiveUnlock() { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mBinderSerializationLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + // don't allow unlocking if we have no lock + if (!mExclusiveLock) { + ALOGW("%s: cannot unlock, no lock was held in the first place", + __FUNCTION__); + return BAD_VALUE; + } + + mExclusiveLock = false; + if (mRemoteCallback != NULL ) { + mRemoteCallback->onLockStatusChanged( + IProCameraCallbacks::LOCK_RELEASED); + } + ALOGV("%s: exclusive lock released", __FUNCTION__); + + return OK; +} + +bool ProCamera2Client::hasExclusiveLock() { + Mutex::Autolock icl(mBinderSerializationLock); + return mExclusiveLock; +} + +void ProCamera2Client::onExclusiveLockStolen() { + ALOGV("%s: ProClient lost exclusivity (id %d)", + __FUNCTION__, mCameraId); + + Mutex::Autolock icl(mBinderSerializationLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + if (mExclusiveLock && mRemoteCallback.get() != NULL) { + mRemoteCallback->onLockStatusChanged( + IProCameraCallbacks::LOCK_STOLEN); + } + + mExclusiveLock = false; + + //TODO: we should not need to detach the device, merely reset it. + detachDevice(); +} + +status_t ProCamera2Client::submitRequest(camera_metadata_t* request, + bool streaming) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mBinderSerializationLock); + + if (!mDevice.get()) return DEAD_OBJECT; + + if (!mExclusiveLock) { + return PERMISSION_DENIED; + } + + CameraMetadata metadata(request); + + if (!enforceRequestPermissions(metadata)) { + return PERMISSION_DENIED; + } + + if (streaming) { + return mDevice->setStreamingRequest(metadata); + } else { + return mDevice->capture(metadata); + } + + // unreachable. thx gcc for a useless warning + return OK; +} + +status_t ProCamera2Client::cancelRequest(int requestId) { + (void)requestId; + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mBinderSerializationLock); + + if (!mDevice.get()) return DEAD_OBJECT; + + if (!mExclusiveLock) { + return PERMISSION_DENIED; + } + + // TODO: implement + ALOGE("%s: not fully implemented yet", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t ProCamera2Client::deleteStream(int streamId) { + ATRACE_CALL(); + ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId); + + status_t res; + if ( (res = checkPid(__FUNCTION__) ) != OK) return res; + + Mutex::Autolock icl(mBinderSerializationLock); + + if (!mDevice.get()) return DEAD_OBJECT; + mDevice->clearStreamingRequest(); + + status_t code; + if ((code = mDevice->waitUntilDrained()) != OK) { + ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__, code); + } + + return mDevice->deleteStream(streamId); +} + +status_t ProCamera2Client::createStream(int width, int height, int format, + const sp<IGraphicBufferProducer>& bufferProducer, + /*out*/ + int* streamId) +{ + if (streamId) { + *streamId = -1; + } + + ATRACE_CALL(); + ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format); + + status_t res; + if ( (res = checkPid(__FUNCTION__) ) != OK) return res; + + Mutex::Autolock icl(mBinderSerializationLock); + + if (!mDevice.get()) return DEAD_OBJECT; + + sp<IBinder> binder; + sp<ANativeWindow> window; + if (bufferProducer != 0) { + binder = bufferProducer->asBinder(); + window = new Surface(bufferProducer); + } + + return mDevice->createStream(window, width, height, format, /*size*/1, + streamId); +} + +// Create a request object from a template. +// -- Caller owns the newly allocated metadata +status_t ProCamera2Client::createDefaultRequest(int templateId, + /*out*/ + camera_metadata** request) +{ + ATRACE_CALL(); + ALOGV("%s (templateId = 0x%x)", __FUNCTION__, templateId); + + if (request) { + *request = NULL; + } + + status_t res; + if ( (res = checkPid(__FUNCTION__) ) != OK) return res; + + Mutex::Autolock icl(mBinderSerializationLock); + + if (!mDevice.get()) return DEAD_OBJECT; + + CameraMetadata metadata; + if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK) { + *request = metadata.release(); + } + + return res; +} + +status_t ProCamera2Client::getCameraInfo(int cameraId, + /*out*/ + camera_metadata** info) +{ + if (cameraId != mCameraId) { + return INVALID_OPERATION; + } + + Mutex::Autolock icl(mBinderSerializationLock); + + if (!mDevice.get()) return DEAD_OBJECT; + + CameraMetadata deviceInfo = mDevice->info(); + *info = deviceInfo.release(); + + return OK; +} + +status_t ProCamera2Client::dump(int fd, const Vector<String16>& args) { + String8 result; + result.appendFormat("ProCamera2Client[%d] (%p) PID: %d, dump:\n", + mCameraId, + getRemoteCallback()->asBinder().get(), + mClientPid); + result.append(" State: "); + + // TODO: print dynamic/request section from most recent requests + mFrameProcessor->dump(fd, args); + + return dumpDevice(fd, args); +} + +// IProCameraUser interface + +void ProCamera2Client::detachDevice() { + if (mDevice == 0) return; + + ALOGV("Camera %d: Stopping processors", mCameraId); + + mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID, + FRAME_PROCESSOR_LISTENER_MAX_ID, + /*listener*/this); + mFrameProcessor->requestExit(); + ALOGV("Camera %d: Waiting for threads", mCameraId); + mFrameProcessor->join(); + ALOGV("Camera %d: Disconnecting device", mCameraId); + + // WORKAROUND: HAL refuses to disconnect while there's streams in flight + { + mDevice->clearStreamingRequest(); + + status_t code; + if ((code = mDevice->waitUntilDrained()) != OK) { + ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__, + code); + } + } + + Camera2ClientBase::detachDevice(); +} + +/** Device-related methods */ +void ProCamera2Client::onFrameAvailable(int32_t frameId, + const CameraMetadata& frame) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mBinderSerializationLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + if (mRemoteCallback != NULL) { + CameraMetadata tmp(frame); + camera_metadata_t* meta = tmp.release(); + ALOGV("%s: meta = %p ", __FUNCTION__, meta); + mRemoteCallback->onResultReceived(frameId, meta); + tmp.acquire(meta); + } + +} + +bool ProCamera2Client::enforceRequestPermissions(CameraMetadata& metadata) { + + const int pid = IPCThreadState::self()->getCallingPid(); + const int selfPid = getpid(); + camera_metadata_entry_t entry; + + /** + * Mixin default important security values + * - android.led.transmit = defaulted ON + */ + CameraMetadata staticInfo = mDevice->info(); + entry = staticInfo.find(ANDROID_LED_AVAILABLE_LEDS); + for(size_t i = 0; i < entry.count; ++i) { + uint8_t led = entry.data.u8[i]; + + switch(led) { + case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: { + uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON; + if (!metadata.exists(ANDROID_LED_TRANSMIT)) { + metadata.update(ANDROID_LED_TRANSMIT, + &transmitDefault, 1); + } + break; + } + } + } + + // We can do anything! + if (pid == selfPid) { + return true; + } + + /** + * Permission check special fields in the request + * - android.led.transmit = android.permission.CAMERA_DISABLE_TRANSMIT + */ + entry = metadata.find(ANDROID_LED_TRANSMIT); + if (entry.count > 0 && entry.data.u8[0] != ANDROID_LED_TRANSMIT_ON) { + String16 permissionString = + String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED"); + if (!checkCallingPermission(permissionString)) { + const int uid = IPCThreadState::self()->getCallingUid(); + ALOGE("Permission Denial: " + "can't disable transmit LED pid=%d, uid=%d", pid, uid); + return false; + } + } + + return true; +} + +} // namespace android diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.h b/services/camera/libcameraservice/api_pro/ProCamera2Client.h new file mode 100644 index 0000000..0bf6784 --- /dev/null +++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA_PROCAMERA2CLIENT_H +#define ANDROID_SERVERS_CAMERA_PROCAMERA2CLIENT_H + +#include "CameraService.h" +#include "common/FrameProcessorBase.h" +#include "common/Camera2ClientBase.h" +#include "device2/Camera2Device.h" + +namespace android { + +class IMemory; +/** + * Implements the binder IProCameraUser API, + * meant for HAL2-level private API access. + */ +class ProCamera2Client : + public Camera2ClientBase<CameraService::ProClient>, + public camera2::FrameProcessorBase::FilteredListener +{ +public: + /** + * IProCameraUser interface (see IProCameraUser for details) + */ + virtual status_t exclusiveTryLock(); + virtual status_t exclusiveLock(); + virtual status_t exclusiveUnlock(); + + virtual bool hasExclusiveLock(); + + // Note that the callee gets a copy of the metadata. + virtual int submitRequest(camera_metadata_t* metadata, + bool streaming = false); + virtual status_t cancelRequest(int requestId); + + virtual status_t deleteStream(int streamId); + + virtual status_t createStream( + int width, + int height, + int format, + const sp<IGraphicBufferProducer>& bufferProducer, + /*out*/ + int* streamId); + + // Create a request object from a template. + // -- Caller owns the newly allocated metadata + virtual status_t createDefaultRequest(int templateId, + /*out*/ + camera_metadata** request); + + // Get the static metadata for the camera + // -- Caller owns the newly allocated metadata + virtual status_t getCameraInfo(int cameraId, + /*out*/ + camera_metadata** info); + + /** + * Interface used by CameraService + */ + + ProCamera2Client(const sp<CameraService>& cameraService, + const sp<IProCameraCallbacks>& remoteCallback, + const String16& clientPackageName, + int cameraId, + int cameraFacing, + int clientPid, + uid_t clientUid, + int servicePid); + virtual ~ProCamera2Client(); + + virtual status_t initialize(camera_module_t *module); + + virtual status_t dump(int fd, const Vector<String16>& args); + + // Callbacks from camera service + virtual void onExclusiveLockStolen(); + + /** + * Interface used by independent components of ProCamera2Client. + */ + +protected: + /** FilteredListener implementation **/ + virtual void onFrameAvailable(int32_t frameId, + const CameraMetadata& frame); + virtual void detachDevice(); + +private: + /** IProCameraUser interface-related private members */ + + /** Preview callback related members */ + sp<camera2::FrameProcessorBase> mFrameProcessor; + static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0; + static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL; + + /** Utility members */ + bool enforceRequestPermissions(CameraMetadata& metadata); + + // Whether or not we have an exclusive lock on the device + // - if no we can't modify the request queue. + // note that creating/deleting streams we own is still OK + bool mExclusiveLock; +}; + +}; // namespace android + +#endif |