diff options
-rw-r--r-- | camera/Android.mk | 5 | ||||
-rw-r--r-- | camera/Camera.cpp | 3 | ||||
-rw-r--r-- | camera/ICameraService.cpp | 18 | ||||
-rw-r--r-- | camera/IProCameraCallbacks.cpp | 144 | ||||
-rw-r--r-- | camera/IProCameraUser.cpp | 264 | ||||
-rw-r--r-- | camera/ProCamera.cpp | 230 | ||||
-rw-r--r-- | camera/tests/Android.mk | 1 | ||||
-rw-r--r-- | camera/tests/ProCameraTests.cpp | 68 | ||||
-rw-r--r-- | include/camera/ICameraService.h | 8 | ||||
-rw-r--r-- | include/camera/IProCameraCallbacks.h | 57 | ||||
-rw-r--r-- | include/camera/IProCameraUser.h | 82 | ||||
-rw-r--r-- | include/camera/ProCamera.h | 167 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 296 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 147 |
14 files changed, 1434 insertions, 56 deletions
diff --git a/camera/Android.mk b/camera/Android.mk index a17ad1a..3e7e5a5 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -12,7 +12,10 @@ LOCAL_SRC_FILES:= \ ICameraClient.cpp \ ICameraService.cpp \ ICameraRecordingProxy.cpp \ - ICameraRecordingProxyListener.cpp + ICameraRecordingProxyListener.cpp \ + IProCameraUser.cpp \ + IProCameraCallbacks.cpp \ + ProCamera.cpp \ LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/camera/Camera.cpp b/camera/Camera.cpp index 3aaacaf..be395ba 100644 --- a/camera/Camera.cpp +++ b/camera/Camera.cpp @@ -120,9 +120,10 @@ sp<Camera> Camera::connect(int cameraId) { ALOGV("connect"); sp<Camera> c = new Camera(); + sp<ICameraClient> cl = c; const sp<ICameraService>& cs = getCameraService(); if (cs != 0) { - c->mCamera = cs->connect(c, cameraId); + c->mCamera = cs->connect(cl, cameraId); } if (c->mCamera != 0) { c->mCamera->asBinder()->linkToDeath(c); diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index f2d367e..8237c66 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -65,6 +65,17 @@ public: remote()->transact(BnCameraService::CONNECT, data, &reply); return interface_cast<ICamera>(reply.readStrongBinder()); } + + // connect to camera service (pro client) + virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb, int cameraId) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); + data.writeStrongBinder(cameraCb->asBinder()); + data.writeInt32(cameraId); + remote()->transact(BnCameraService::CONNECT_PRO, data, &reply); + return interface_cast<IProCameraUser>(reply.readStrongBinder()); + } }; IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService"); @@ -97,6 +108,13 @@ status_t BnCameraService::onTransact( reply->writeStrongBinder(camera->asBinder()); return NO_ERROR; } break; + case CONNECT_PRO: { + CHECK_INTERFACE(ICameraService, data, reply); + sp<IProCameraCallbacks> cameraClient = interface_cast<IProCameraCallbacks>(data.readStrongBinder()); + sp<IProCameraUser> camera = connect(cameraClient, data.readInt32()); + reply->writeStrongBinder(camera->asBinder()); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/IProCameraCallbacks.cpp b/camera/IProCameraCallbacks.cpp new file mode 100644 index 0000000..c2ad74f --- /dev/null +++ b/camera/IProCameraCallbacks.cpp @@ -0,0 +1,144 @@ +/* +** +** Copyright 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_NDEBUG 0 +#define LOG_TAG "IProCameraCallbacks" +#include <utils/Log.h> +#include <stdint.h> +#include <sys/types.h> + +#include <binder/Parcel.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> +#include <utils/Mutex.h> + +#include <camera/IProCameraCallbacks.h> + +namespace android { + +enum { + NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, + DATA_CALLBACK, + DATA_CALLBACK_TIMESTAMP, +}; + +class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks> +{ +public: + BpProCameraCallbacks(const sp<IBinder>& impl) + : BpInterface<IProCameraCallbacks>(impl) + { + } + + // generic callback from camera service to app + void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) + { + ALOGV("notifyCallback"); + Parcel data, reply; + data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor()); + data.writeInt32(msgType); + data.writeInt32(ext1); + data.writeInt32(ext2); + remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } + + // generic data callback from camera service to app with image data + void dataCallback(int32_t msgType, const sp<IMemory>& imageData, + camera_frame_metadata_t *metadata) + { + ALOGV("dataCallback"); + Parcel data, reply; + data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor()); + data.writeInt32(msgType); + data.writeStrongBinder(imageData->asBinder()); + if (metadata) { + data.writeInt32(metadata->number_of_faces); + data.write(metadata->faces, + sizeof(camera_face_t) * metadata->number_of_faces); + } + remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } + + // generic data callback from camera service to app with image data + void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, + const sp<IMemory>& imageData) + { + ALOGV("dataCallback"); + Parcel data, reply; + data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor()); + data.writeInt64(timestamp); + data.writeInt32(msgType); + data.writeStrongBinder(imageData->asBinder()); + remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, + IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(ProCameraCallbacks, + "android.hardware.IProCameraCallbacks"); + +// ---------------------------------------------------------------------- + +status_t BnProCameraCallbacks::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case NOTIFY_CALLBACK: { + ALOGV("NOTIFY_CALLBACK"); + CHECK_INTERFACE(IProCameraCallbacks, data, reply); + int32_t msgType = data.readInt32(); + int32_t ext1 = data.readInt32(); + int32_t ext2 = data.readInt32(); + notifyCallback(msgType, ext1, ext2); + return NO_ERROR; + } break; + case DATA_CALLBACK: { + ALOGV("DATA_CALLBACK"); + CHECK_INTERFACE(IProCameraCallbacks, data, reply); + int32_t msgType = data.readInt32(); + sp<IMemory> imageData = interface_cast<IMemory>( + data.readStrongBinder()); + camera_frame_metadata_t *metadata = NULL; + if (data.dataAvail() > 0) { + metadata = new camera_frame_metadata_t; + metadata->number_of_faces = data.readInt32(); + metadata->faces = (camera_face_t *) data.readInplace( + sizeof(camera_face_t) * metadata->number_of_faces); + } + dataCallback(msgType, imageData, metadata); + if (metadata) delete metadata; + return NO_ERROR; + } break; + case DATA_CALLBACK_TIMESTAMP: { + ALOGV("DATA_CALLBACK_TIMESTAMP"); + CHECK_INTERFACE(IProCameraCallbacks, data, reply); + nsecs_t timestamp = data.readInt64(); + int32_t msgType = data.readInt32(); + sp<IMemory> imageData = interface_cast<IMemory>( + data.readStrongBinder()); + dataCallbackTimestamp(timestamp, msgType, imageData); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/camera/IProCameraUser.cpp b/camera/IProCameraUser.cpp new file mode 100644 index 0000000..76c2dcd --- /dev/null +++ b/camera/IProCameraUser.cpp @@ -0,0 +1,264 @@ +/* +** +** Copyright 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_NDEBUG 0 +#define LOG_TAG "IProCameraUser" +#include <utils/Log.h> +#include <stdint.h> +#include <sys/types.h> +#include <binder/Parcel.h> +#include <camera/IProCameraUser.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> +#include <system/camera_metadata.h> + +namespace android { + +typedef Parcel::WritableBlob WritableBlob; +typedef Parcel::ReadableBlob ReadableBlob; + +enum { + DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, + CONNECT, + EXCLUSIVE_TRY_LOCK, + EXCLUSIVE_LOCK, + EXCLUSIVE_UNLOCK, + HAS_EXCLUSIVE_LOCK, + SUBMIT_REQUEST, + CANCEL_REQUEST, + REQUEST_STREAM, + CANCEL_STREAM, +}; + +class BpProCameraUser: public BpInterface<IProCameraUser> +{ +public: + BpProCameraUser(const sp<IBinder>& impl) + : BpInterface<IProCameraUser>(impl) + { + } + + // disconnect from camera service + void disconnect() + { + ALOGV("disconnect"); + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + remote()->transact(DISCONNECT, data, &reply); + } + + virtual status_t connect(const sp<IProCameraCallbacks>& cameraClient) + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + data.writeStrongBinder(cameraClient->asBinder()); + remote()->transact(CONNECT, data, &reply); + return reply.readInt32(); + } + + /* Shared ProCameraUser */ + + virtual status_t exclusiveTryLock() + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + remote()->transact(EXCLUSIVE_TRY_LOCK, data, &reply); + return reply.readInt32(); + } + virtual status_t exclusiveLock() + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + remote()->transact(EXCLUSIVE_LOCK, data, &reply); + return reply.readInt32(); + } + + virtual status_t exclusiveUnlock() + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + remote()->transact(EXCLUSIVE_UNLOCK, data, &reply); + return reply.readInt32(); + } + + virtual bool hasExclusiveLock() + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + remote()->transact(HAS_EXCLUSIVE_LOCK, data, &reply); + return !!reply.readInt32(); + } + + virtual int submitRequest(camera_metadata_t* metadata, bool streaming) + { + + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + + // arg0 = metadataSize (int32) + size_t metadataSize = get_camera_metadata_compact_size(metadata); + data.writeInt32(static_cast<int32_t>(metadataSize)); + + // arg1 = metadata (blob) + WritableBlob blob; + { + data.writeBlob(metadataSize, &blob); + copy_camera_metadata(blob.data(), metadataSize, metadata); + } + blob.release(); + + // arg2 = streaming (bool) + data.writeInt32(streaming); + + remote()->transact(SUBMIT_REQUEST, data, &reply); + return reply.readInt32(); + } + + virtual status_t cancelRequest(int requestId) + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + data.writeInt32(requestId); + + remote()->transact(CANCEL_REQUEST, data, &reply); + return reply.readInt32(); + } + + virtual status_t requestStream(int streamId) + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + data.writeInt32(streamId); + + remote()->transact(REQUEST_STREAM, data, &reply); + return reply.readInt32(); + } + virtual status_t cancelStream(int streamId) + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + data.writeInt32(streamId); + + remote()->transact(CANCEL_STREAM, data, &reply); + return reply.readInt32(); + } + +}; + +IMPLEMENT_META_INTERFACE(ProCameraUser, "android.hardware.IProCameraUser"); + +// ---------------------------------------------------------------------- + +status_t BnProCameraUser::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case DISCONNECT: { + ALOGV("DISCONNECT"); + CHECK_INTERFACE(IProCameraUser, data, reply); + disconnect(); + return NO_ERROR; + } break; + case CONNECT: { + CHECK_INTERFACE(IProCameraUser, data, reply); + sp<IProCameraCallbacks> cameraClient = + interface_cast<IProCameraCallbacks>(data.readStrongBinder()); + reply->writeInt32(connect(cameraClient)); + return NO_ERROR; + } break; + + /* Shared ProCameraUser */ + case EXCLUSIVE_TRY_LOCK: { + CHECK_INTERFACE(IProCameraUser, data, reply); + reply->writeInt32(exclusiveTryLock()); + return NO_ERROR; + } break; + case EXCLUSIVE_LOCK: { + CHECK_INTERFACE(IProCameraUser, data, reply); + reply->writeInt32(exclusiveLock()); + return NO_ERROR; + } break; + case EXCLUSIVE_UNLOCK: { + CHECK_INTERFACE(IProCameraUser, data, reply); + reply->writeInt32(exclusiveUnlock()); + return NO_ERROR; + } break; + case HAS_EXCLUSIVE_LOCK: { + CHECK_INTERFACE(IProCameraUser, data, reply); + reply->writeInt32(hasExclusiveLock()); + return NO_ERROR; + } break; + case SUBMIT_REQUEST: { + CHECK_INTERFACE(IProCameraUser, data, reply); + camera_metadata_t* metadata; + + // arg0 = metadataSize (int32) + size_t metadataSize = static_cast<size_t>(data.readInt32()); + + // NOTE: this doesn't make sense to me. shouldnt the blob + // know how big it is? why do we have to specify the size + // to Parcel::readBlob ? + + ReadableBlob blob; + // arg1 = metadata (blob) + { + data.readBlob(metadataSize, &blob); + const camera_metadata_t* tmp = + reinterpret_cast<const camera_metadata_t*>(blob.data()); + size_t entry_capacity = get_camera_metadata_entry_capacity(tmp); + size_t data_capacity = get_camera_metadata_data_capacity(tmp); + + metadata = allocate_camera_metadata(entry_capacity, + data_capacity); + copy_camera_metadata(metadata, metadataSize, tmp); + } + blob.release(); + + // arg2 = streaming (bool) + bool streaming = data.readInt32(); + + // return code: requestId (int32) + reply->writeInt32(submitRequest(metadata, streaming)); + + return NO_ERROR; + } break; + case CANCEL_REQUEST: { + CHECK_INTERFACE(IProCameraUser, data, reply); + int requestId = data.readInt32(); + reply->writeInt32(cancelRequest(requestId)); + return NO_ERROR; + } break; + case REQUEST_STREAM: { + CHECK_INTERFACE(IProCameraUser, data, reply); + int streamId = data.readInt32(); + reply->writeInt32(requestStream(streamId)); + return NO_ERROR; + } break; + case CANCEL_STREAM: { + CHECK_INTERFACE(IProCameraUser, data, reply); + int streamId = data.readInt32(); + reply->writeInt32(cancelStream(streamId)); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp new file mode 100644 index 0000000..134a4a3 --- /dev/null +++ b/camera/ProCamera.cpp @@ -0,0 +1,230 @@ +/* +** +** 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_NDEBUG 0 +#define LOG_TAG "ProCamera" +#include <utils/Log.h> +#include <utils/threads.h> +#include <utils/Mutex.h> + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/IMemory.h> + +#include <camera/ProCamera.h> +#include <camera/ICameraService.h> +#include <camera/IProCameraUser.h> +#include <camera/IProCameraCallbacks.h> + +#include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> + +namespace android { + +// client singleton for camera service binder interface +Mutex ProCamera::mLock; +sp<ICameraService> ProCamera::mCameraService; +sp<ProCamera::DeathNotifier> ProCamera::mDeathNotifier; + +// establish binder interface to camera service +const sp<ICameraService>& ProCamera::getCameraService() +{ + Mutex::Autolock _l(mLock); + if (mCameraService.get() == 0) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder; + do { + binder = sm->getService(String16("media.camera")); + if (binder != 0) + break; + ALOGW("CameraService not published, waiting..."); + usleep(500000); // 0.5 s + } while(true); + if (mDeathNotifier == NULL) { + mDeathNotifier = new DeathNotifier(); + } + binder->linkToDeath(mDeathNotifier); + mCameraService = interface_cast<ICameraService>(binder); + } + ALOGE_IF(mCameraService==0, "no CameraService!?"); + return mCameraService; +} + +sp<ProCamera> ProCamera::connect(int cameraId) +{ + ALOGV("connect"); + sp<ProCamera> c = new ProCamera(); + sp<IProCameraCallbacks> cl = c; + const sp<ICameraService>& cs = getCameraService(); + if (cs != 0) { + c->mCamera = cs->connect(cl, cameraId); + } + if (c->mCamera != 0) { + c->mCamera->asBinder()->linkToDeath(c); + c->mStatus = NO_ERROR; + } else { + c.clear(); + } + return c; +} + +void ProCamera::disconnect() +{ + ALOGV("disconnect"); + if (mCamera != 0) { + mCamera->disconnect(); + mCamera->asBinder()->unlinkToDeath(this); + mCamera = 0; + } +} + +ProCamera::ProCamera() +{ +} + +ProCamera::~ProCamera() +{ + +} + +sp<IProCameraUser> ProCamera::remote() +{ + return mCamera; +} + +void ProCamera::binderDied(const wp<IBinder>& who) { + ALOGW("IProCameraUser died"); + notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0); +} + +void ProCamera::DeathNotifier::binderDied(const wp<IBinder>& who) { + ALOGV("binderDied"); + Mutex::Autolock _l(ProCamera::mLock); + ProCamera::mCameraService.clear(); + ALOGW("Camera service died!"); +} + + +// callback from camera service +void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) +{ + sp<ProCameraListener> listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; + } + if (listener != NULL) { + listener->notify(msgType, ext1, ext2); + } +} + +// callback from camera service when frame or image is ready +void ProCamera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, + camera_frame_metadata_t *metadata) +{ + sp<ProCameraListener> listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; + } + if (listener != NULL) { + listener->postData(msgType, dataPtr, metadata); + } +} + +// callback from camera service when timestamped frame is ready +void ProCamera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, + const sp<IMemory>& dataPtr) +{ + sp<ProCameraListener> listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; + } + if (listener != NULL) { + listener->postDataTimestamp(timestamp, msgType, dataPtr); + } else { + ALOGW("No listener was set. Drop a recording frame."); + } +} + +/* IProCameraUser's implementation */ + +status_t ProCamera::exclusiveTryLock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->exclusiveTryLock(); +} +status_t ProCamera::exclusiveLock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->exclusiveLock(); +} +status_t ProCamera::exclusiveUnlock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->exclusiveUnlock(); +} +bool ProCamera::hasExclusiveLock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->hasExclusiveLock(); +} + +// Note that the callee gets a copy of the metadata. +int ProCamera::submitRequest(const struct camera_metadata* metadata, + bool streaming) +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->submitRequest(const_cast<struct camera_metadata*>(metadata), + streaming); +} + +status_t ProCamera::cancelRequest(int requestId) +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->cancelRequest(requestId); +} + +status_t ProCamera::requestStream(int streamId) +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->requestStream(streamId); +} +status_t ProCamera::cancelStream(int streamId) +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->cancelStream(streamId); +} + +}; // namespace android diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk index 586e814..5d386c4 100644 --- a/camera/tests/Android.mk +++ b/camera/tests/Android.mk @@ -3,6 +3,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ main.cpp \ + ProCameraTests.cpp \ LOCAL_SHARED_LIBRARIES := \ libutils \ diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp new file mode 100644 index 0000000..4de9c10 --- /dev/null +++ b/camera/tests/ProCameraTests.cpp @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#include <gtest/gtest.h> +#include <iostream> + +#include "Camera.h" +#include "ProCamera.h" + +namespace android { +namespace camera2 { +namespace tests { +namespace client { + +#define CAMERA_ID 0 +#define TEST_DEBUGGING 0 + +#if TEST_DEBUGGING +#define dout std::cerr +#else +#define dout if (0) std::cerr +#endif + +class ProCameraTest : public ::testing::Test { + + virtual void SetUp() { + mCamera = ProCamera::connect(CAMERA_ID); + ASSERT_NE((void*)NULL, mCamera.get()); + } + + virtual void TearDown() { + ASSERT_NE((void*)NULL, mCamera.get()); + mCamera->disconnect(); + } + +protected: + sp<ProCamera> mCamera; +}; + +TEST_F(ProCameraTest, Locking) { + + if (HasFatalFailure()) { + return; + } + + status_t res = mCamera->exclusiveTryLock(); + + EXPECT_EQ(OK, res); +} + +} +} +} +} + diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h index 7d70c1e..11d7b65 100644 --- a/include/camera/ICameraService.h +++ b/include/camera/ICameraService.h @@ -23,6 +23,7 @@ #include <camera/ICameraClient.h> #include <camera/ICamera.h> +#include <camera/IProCameraUser.h> namespace android { @@ -32,7 +33,8 @@ public: enum { GET_NUMBER_OF_CAMERAS = IBinder::FIRST_CALL_TRANSACTION, GET_CAMERA_INFO, - CONNECT + CONNECT, + CONNECT_PRO }; public: @@ -43,6 +45,10 @@ public: struct CameraInfo* cameraInfo) = 0; virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId) = 0; + + virtual sp<IProCameraUser> + connect(const sp<IProCameraCallbacks>& cameraCb, + int cameraId) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/camera/IProCameraCallbacks.h b/include/camera/IProCameraCallbacks.h new file mode 100644 index 0000000..ac1d5eb --- /dev/null +++ b/include/camera/IProCameraCallbacks.h @@ -0,0 +1,57 @@ +/* + * 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_HARDWARE_IPROCAMERA_CALLBACKS_H +#define ANDROID_HARDWARE_IPROCAMERA_CALLBACKS_H + +#include <utils/RefBase.h> +#include <binder/IInterface.h> +#include <binder/Parcel.h> +#include <binder/IMemory.h> +#include <utils/Timers.h> +#include <system/camera.h> + +namespace android { + +class IProCameraCallbacks: public IInterface +{ +public: + DECLARE_META_INTERFACE(ProCameraCallbacks); + + virtual void notifyCallback(int32_t msgType, int32_t ext1, + int32_t ext2) = 0; + virtual void dataCallback(int32_t msgType, + const sp<IMemory>& data, + camera_frame_metadata_t *metadata) = 0; + virtual void dataCallbackTimestamp(nsecs_t timestamp, + int32_t msgType, + const sp<IMemory>& data) = 0; +}; + +// ---------------------------------------------------------------------------- + +class BnProCameraCallbacks: public BnInterface<IProCameraCallbacks> +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +}; // namespace android + +#endif diff --git a/include/camera/IProCameraUser.h b/include/camera/IProCameraUser.h new file mode 100644 index 0000000..6170410 --- /dev/null +++ b/include/camera/IProCameraUser.h @@ -0,0 +1,82 @@ +/* + * 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_HARDWARE_IPROCAMERAUSER_H +#define ANDROID_HARDWARE_IPROCAMERAUSER_H + +#include <utils/RefBase.h> +#include <binder/IInterface.h> +#include <binder/Parcel.h> +#include <binder/IMemory.h> +#include <utils/String8.h> +#include <camera/IProCameraCallbacks.h> + +struct camera_metadata; + +namespace android { + +class IProCameraUserClient; +class IGraphicBufferProducer; +class Surface; + +class IProCameraUser: public IInterface +{ +public: + DECLARE_META_INTERFACE(ProCameraUser); + + virtual void disconnect() = 0; + + // connect to the service, given a callbacks listener + virtual status_t connect(const sp<IProCameraCallbacks>& callbacks) + = 0; + + /** + * Locking + **/ + virtual status_t exclusiveTryLock() = 0; + virtual status_t exclusiveLock() = 0; + virtual status_t exclusiveUnlock() = 0; + + virtual bool hasExclusiveLock() = 0; + + /** + * Request Handling + **/ + + // Note that the callee gets a copy of the metadata. + virtual int submitRequest(struct camera_metadata* metadata, + bool streaming = false) = 0; + virtual status_t cancelRequest(int requestId) = 0; + + virtual status_t requestStream(int streamId) = 0; + virtual status_t cancelStream(int streamId) = 0; + +}; + +// ---------------------------------------------------------------------------- + +class BnProCameraUser: public BnInterface<IProCameraUser> +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +}; // namespace android + +#endif diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h new file mode 100644 index 0000000..ba5fdc0 --- /dev/null +++ b/include/camera/ProCamera.h @@ -0,0 +1,167 @@ +/* + * 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_HARDWARE_PRO_CAMERA_H +#define ANDROID_HARDWARE_PRO_CAMERA_H + +#include <utils/Timers.h> +#include <gui/IGraphicBufferProducer.h> +#include <system/camera.h> +#include <camera/IProCameraCallbacks.h> +#include <camera/IProCameraUser.h> +#include <camera/Camera.h> + +struct camera_metadata; + +namespace android { + +// ref-counted object for callbacks +class ProCameraListener : public CameraListener +{ +public: + // Lock has been acquired. Write operations now available. + virtual void onLockAcquired() = 0; + // Lock has been released with exclusiveUnlock, or has been stolen by + // another client. + virtual void onLockReleased() = 0; + + // Lock free. + virtual void onTriggerNotify(int32_t msgType, int32_t ext1, int32_t ext2) + = 0; +}; + +class ProCamera : public BnProCameraCallbacks, public IBinder::DeathRecipient +{ +public: + /** + * Connect a shared camera. By default access is restricted to read only + * (Lock free) operations. To be able to submit custom requests a lock needs + * to be acquired with exclusive[Try]Lock. + */ + static sp<ProCamera> connect(int cameraId); + virtual void disconnect(); + virtual ~ProCamera(); + + void setListener(const sp<ProCameraListener>& listener); + + /** + * Exclusive Locks: + * - We may request exclusive access to a camera if no other + * clients are using the camera. This works as a traditional + * client, writing/reading any camera state. + * - An application opening the camera (a regular 'Camera') will + * always steal away the exclusive lock from a ProCamera, + * this will call onLockReleased. + * - onLockAcquired will be called again once it is possible + * to again exclusively lock the camera. + * + */ + + /** + * All exclusiveLock/unlock functions are asynchronous. The remote endpoint + * shall not block while waiting to acquire the lock. Instead the lock + * notifications will come in asynchronously on the listener. + */ + + /** + * Attempt to acquire the lock instantly (non-blocking) + * - If this succeeds, you do not need to wait for onLockAcquired + * but the event will still be fired + * + * Returns -EBUSY if already locked. 0 on success. + */ + status_t exclusiveTryLock(); + // always returns 0. wait for onLockAcquired before lock is acquired. + status_t exclusiveLock(); + // release a lock if we have one, or cancel the lock request. + status_t exclusiveUnlock(); + + // exclusive lock = do whatever we want. no lock = read only. + bool hasExclusiveLock(); + + /** + * < 0 error, >= 0 the request ID. streaming to have the request repeat + * until cancelled. + * The request queue is flushed when a lock is released or stolen + * if not locked will return PERMISSION_DENIED + */ + int submitRequest(const struct camera_metadata* metadata, + bool streaming = false); + // if not locked will return PERMISSION_DENIED, BAD_VALUE if requestId bad + status_t cancelRequest(int requestId); + + /** + * Ask for a stream to be enabled. + * Lock free. Service maintains counter of streams. + */ + status_t requestStream(int streamId); + /** + * Ask for a stream to be disabled. + * Lock free. Service maintains counter of streams. + * Errors: BAD_VALUE if unknown stream ID. + */ + status_t cancelStream(int streamId); + + sp<IProCameraUser> remote(); + +protected: + //////////////////////////////////////////////////////// + // IProCameraCallbacks implementation + //////////////////////////////////////////////////////// + virtual void notifyCallback(int32_t msgType, int32_t ext, + int32_t ext2); + virtual void dataCallback(int32_t msgType, + const sp<IMemory>& dataPtr, + camera_frame_metadata_t *metadata); + virtual void dataCallbackTimestamp(nsecs_t timestamp, + int32_t msgType, + const sp<IMemory>& dataPtr); + + class DeathNotifier: public IBinder::DeathRecipient + { + public: + DeathNotifier() { + } + + virtual void binderDied(const wp<IBinder>& who); + }; + +private: + ProCamera(); + + virtual void binderDied(const wp<IBinder>& who); + + // helper function to obtain camera service handle + static const sp<ICameraService>& getCameraService(); + + static sp<DeathNotifier> mDeathNotifier; + + sp<IProCameraUser> mCamera; + status_t mStatus; + + sp<ProCameraListener> mListener; + + friend class DeathNotifier; + + static Mutex mLock; + static sp<ICameraService> mCameraService; + + +}; + +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index b1c594a..4941965 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -79,6 +79,8 @@ CameraService::CameraService() void CameraService::onFirstRef() { + LOG1("CameraService::onFirstRef"); + BnCameraService::onFirstRef(); if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, @@ -131,6 +133,26 @@ status_t CameraService::getCameraInfo(int cameraId, return rc; } +int CameraService::getDeviceVersion(int cameraId, int* facing) { + struct camera_info info; + if (mModule->get_camera_info(cameraId, &info) != OK) { + return -1; + } + + int deviceVersion; + if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_0) { + deviceVersion = info.device_version; + } else { + deviceVersion = CAMERA_DEVICE_API_VERSION_1_0; + } + + if (facing) { + *facing = info.facing; + } + + return deviceVersion; +} + sp<ICamera> CameraService::connect( const sp<ICameraClient>& cameraClient, int cameraId) { int callingPid = getCallingPid(); @@ -175,34 +197,96 @@ sp<ICamera> CameraService::connect( mClient[cameraId].clear(); } + /* + mBusy is set to false as the last step of the Client destructor, + after which it is guaranteed that the Client destructor has finished ( + including any inherited destructors) + + We only need this for a Client subclasses since we don't allow + multiple Clents to be opened concurrently, but multiple BasicClient + would be fine + */ if (mBusy[cameraId]) { ALOGW("CameraService::connect X (pid %d) rejected" " (camera %d is still busy).", callingPid, cameraId); return NULL; } - struct camera_info info; - if (mModule->get_camera_info(cameraId, &info) != OK) { + int facing = -1; + int deviceVersion = getDeviceVersion(cameraId, &facing); + + switch(deviceVersion) { + case CAMERA_DEVICE_API_VERSION_1_0: + client = new CameraClient(this, cameraClient, cameraId, + facing, callingPid, getpid()); + break; + case CAMERA_DEVICE_API_VERSION_2_0: + case CAMERA_DEVICE_API_VERSION_2_1: + client = new Camera2Client(this, cameraClient, cameraId, + facing, callingPid, getpid()); + break; + case -1: ALOGE("Invalid camera id %d", cameraId); return NULL; + default: + ALOGE("Unknown camera device HAL version: %d", deviceVersion); + return NULL; } - int deviceVersion; - if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) { - deviceVersion = info.device_version; - } else { - deviceVersion = CAMERA_DEVICE_API_VERSION_1_0; + if (client->initialize(mModule) != OK) { + return NULL; + } + + cameraClient->asBinder()->linkToDeath(this); + + mClient[cameraId] = client; + LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid()); + return client; +} + +sp<IProCameraUser> CameraService::connect( + const sp<IProCameraCallbacks>& cameraCb, + int cameraId) +{ + int callingPid = getCallingPid(); + + LOG1("CameraService::connectPro E (pid %d, id %d)", callingPid, cameraId); + + if (!mModule) { + ALOGE("Camera HAL module not loaded"); + return NULL; + } + + sp<ProClient> client; + if (cameraId < 0 || cameraId >= mNumberOfCameras) { + ALOGE("CameraService::connectPro X (pid %d) rejected (invalid cameraId %d).", + callingPid, cameraId); + return NULL; } + char value[PROPERTY_VALUE_MAX]; + property_get("sys.secpolicy.camera.disabled", value, "0"); + if (strcmp(value, "1") == 0) { + // Camera is disabled by DevicePolicyManager. + ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid); + return NULL; + } + + int facing = -1; + int deviceVersion = getDeviceVersion(cameraId, &facing); + switch(deviceVersion) { case CAMERA_DEVICE_API_VERSION_1_0: - client = new CameraClient(this, cameraClient, cameraId, - info.facing, callingPid, getpid()); + ALOGE("Camera id %d uses HALv1, doesn't support ProCamera", cameraId); + return NULL; break; case CAMERA_DEVICE_API_VERSION_2_0: - client = new Camera2Client(this, cameraClient, cameraId, - info.facing, callingPid, getpid()); + client = new ProClient(this, cameraCb, cameraId, + facing, callingPid, getpid()); break; + case -1: + ALOGE("Invalid camera id %d", cameraId); + return NULL; default: ALOGE("Unknown camera device HAL version: %d", deviceVersion); return NULL; @@ -212,23 +296,27 @@ sp<ICamera> CameraService::connect( return NULL; } - cameraClient->asBinder()->linkToDeath(this); + mProClientList[cameraId].push(client); + + cameraCb->asBinder()->linkToDeath(this); - mClient[cameraId] = client; LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid()); return client; + + + return NULL; } -void CameraService::removeClient(const sp<ICameraClient>& cameraClient) { +void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) { int callingPid = getCallingPid(); - LOG1("CameraService::removeClient E (pid %d)", callingPid); + LOG1("CameraService::removeClientByRemote E (pid %d)", callingPid); // Declare this before the lock to make absolutely sure the // destructor won't be called with the lock held. Mutex::Autolock lock(mServiceLock); int outIndex; - sp<Client> client = findClientUnsafe(cameraClient->asBinder(), outIndex); + sp<Client> client = findClientUnsafe(remoteBinder, outIndex); if (client != 0) { // Found our camera, clear and leave. @@ -236,9 +324,50 @@ void CameraService::removeClient(const sp<ICameraClient>& cameraClient) { mClient[outIndex].clear(); client->unlinkToDeath(this); + } else { + + sp<ProClient> clientPro = findProClientUnsafe(remoteBinder); + + if (clientPro != NULL) { + // Found our camera, clear and leave. + LOG1("removeClient: clear pro %p", clientPro.get()); + + clientPro->getRemoteCallback()->asBinder()->unlinkToDeath(this); + } + } + + LOG1("CameraService::removeClientByRemote X (pid %d)", callingPid); +} + +sp<CameraService::ProClient> CameraService::findProClientUnsafe( + const wp<IBinder>& cameraCallbacksRemote) +{ + sp<ProClient> clientPro; + + for (int i = 0; i < mNumberOfCameras; ++i) { + Vector<size_t> removeIdx; + + for (size_t j = 0; j < mProClientList[i].size(); ++j) { + wp<ProClient> cl = mProClientList[i][j]; + + sp<ProClient> clStrong = cl.promote(); + if (clStrong != NULL && clStrong->getRemote() == cameraCallbacksRemote) { + clientPro = clStrong; + break; + } else if (clStrong == NULL) { + // mark to clean up dead ptr + removeIdx.push(j); + } + } + + // remove stale ptrs (in reverse so the indices dont change) + for (ssize_t j = (ssize_t)removeIdx.size() - 1; j >= 0; --j) { + mProClientList[i].removeAt(removeIdx[j]); + } + } - LOG1("CameraService::removeClient X (pid %d)", callingPid); + return clientPro; } sp<CameraService::Client> CameraService::findClientUnsafe( @@ -252,7 +381,7 @@ sp<CameraService::Client> CameraService::findClientUnsafe( if (mClient[i] == 0) continue; // Promote mClient. It can fail if we are called from this path: - // Client::~Client() -> disconnect() -> removeClient(). + // Client::~Client() -> disconnect() -> removeClientByRemote(). client = mClient[i].promote(); // Clean up stale client entry @@ -282,12 +411,12 @@ Mutex* CameraService::getClientLockById(int cameraId) { return &mClientLock[cameraId]; } -sp<CameraService::Client> CameraService::getClientByRemote( +sp<CameraService::BasicClient> CameraService::getClientByRemote( const wp<IBinder>& cameraClient) { // Declare this before the lock to make absolutely sure the // destructor won't be called with the lock held. - sp<Client> client; + sp<BasicClient> client; Mutex::Autolock lock(mServiceLock); @@ -302,6 +431,7 @@ status_t CameraService::onTransact( // Permission checks switch (code) { case BnCameraService::CONNECT: + case BnCameraService::CONNECT_PRO: const int pid = getCallingPid(); const int self_pid = getpid(); if (pid != self_pid) { @@ -390,17 +520,15 @@ void CameraService::playSound(sound_kind kind) { CameraService::Client::Client(const sp<CameraService>& cameraService, const sp<ICameraClient>& cameraClient, - int cameraId, int cameraFacing, int clientPid, int servicePid) { + int cameraId, int cameraFacing, int clientPid, int servicePid) : + CameraService::BasicClient(cameraService, cameraClient->asBinder(), + cameraId, cameraFacing, + clientPid, servicePid) +{ int callingPid = getCallingPid(); LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId); - mCameraService = cameraService; mCameraClient = cameraClient; - mCameraId = cameraId; - mCameraFacing = cameraFacing; - mClientPid = clientPid; - mServicePid = servicePid; - mDestructionStarted = false; cameraService->setCameraBusy(cameraId); cameraService->loadSound(); @@ -409,12 +537,37 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, // tear down the client CameraService::Client::~Client() { + mDestructionStarted = true; + mCameraService->releaseSound(); // unconditionally disconnect. function is idempotent Client::disconnect(); } +CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService, + const sp<IBinder>& remoteCallback, + int cameraId, int cameraFacing, + int clientPid, int servicePid) +{ + mCameraService = cameraService; + mRemoteCallback = remoteCallback; + mCameraId = cameraId; + mCameraFacing = cameraFacing; + mClientPid = clientPid; + mServicePid = servicePid; + + mDestructionStarted = false; +} + +CameraService::BasicClient::~BasicClient() { + mDestructionStarted = true; +} + +void CameraService::BasicClient::disconnect() { + mCameraService->removeClientByRemote(mRemoteCallback); +} + // ---------------------------------------------------------------------------- Mutex* CameraService::Client::getClientLockFromCookie(void* user) { @@ -439,11 +592,96 @@ CameraService::Client* CameraService::Client::getClientFromCookie(void* user) { // NOTE: function is idempotent void CameraService::Client::disconnect() { - mCameraService->removeClient(mCameraClient); + BasicClient::disconnect(); mCameraService->setCameraFree(mCameraId); } // ---------------------------------------------------------------------------- +// IProCamera +// ---------------------------------------------------------------------------- + +CameraService::ProClient::ProClient(const sp<CameraService>& cameraService, + const sp<IProCameraCallbacks>& remoteCallback, + int cameraId, + int cameraFacing, + int clientPid, + int servicePid) + : CameraService::BasicClient(cameraService, remoteCallback->asBinder(), + cameraId, cameraFacing, + clientPid, servicePid) +{ + mRemoteCallback = remoteCallback; +} + +CameraService::ProClient::~ProClient() { + mDestructionStarted = true; + + ProClient::disconnect(); +} + +status_t CameraService::ProClient::connect(const sp<IProCameraCallbacks>& callbacks) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + +void CameraService::ProClient::disconnect() { + BasicClient::disconnect(); +} + +status_t CameraService::ProClient::initialize(camera_module_t* module) +{ + ALOGW("%s: not implemented yet", __FUNCTION__); + return OK; +} + +status_t CameraService::ProClient::exclusiveTryLock() { + ALOGE("%s: not implemented yet", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t CameraService::ProClient::exclusiveLock() { + ALOGE("%s: not implemented yet", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t CameraService::ProClient::exclusiveUnlock() { + ALOGE("%s: not implemented yet", __FUNCTION__); + return INVALID_OPERATION; +} + +bool CameraService::ProClient::hasExclusiveLock() { + ALOGE("%s: not implemented yet", __FUNCTION__); + return false; +} + +status_t CameraService::ProClient::submitRequest(camera_metadata_t* request, bool streaming) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + free_camera_metadata(request); + + return INVALID_OPERATION; +} + +status_t CameraService::ProClient::cancelRequest(int requestId) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + +status_t CameraService::ProClient::requestStream(int streamId) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + +status_t CameraService::ProClient::cancelStream(int streamId) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + +// ---------------------------------------------------------------------------- static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 60000; @@ -569,7 +807,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { ALOGV("java clients' binder died"); - sp<Client> cameraClient = getClientByRemote(who); + sp<BasicClient> cameraClient = getClientByRemote(who); if (cameraClient == 0) { ALOGV("java clients' binder death already cleaned up (normal case)"); diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 41365a0..9e0f62a 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -18,6 +18,7 @@ #ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H +#include <utils/Vector.h> #include <binder/BinderService.h> #include <camera/ICameraService.h> #include <hardware/camera.h> @@ -40,27 +41,32 @@ class CameraService : friend class BinderService<CameraService>; public: class Client; + class BasicClient; + + // Implementation of BinderService<T> static char const* getServiceName() { return "media.camera"; } CameraService(); virtual ~CameraService(); + ///////////////////////////////////////////////////////////////////// + // ICameraService virtual int32_t getNumberOfCameras(); virtual status_t getCameraInfo(int cameraId, struct CameraInfo* cameraInfo); virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId); - virtual void removeClient(const sp<ICameraClient>& cameraClient); - // returns plain pointer of client. Note that mClientLock should be acquired to - // prevent the client from destruction. The result can be NULL. - virtual Client* getClientByIdUnsafe(int cameraId); - virtual Mutex* getClientLockById(int cameraId); - - virtual sp<Client> getClientByRemote(const wp<IBinder>& cameraClient); + virtual sp<IProCameraUser> + connect(const sp<IProCameraCallbacks>& cameraCb, int cameraId); - virtual status_t dump(int fd, const Vector<String16>& args); + // Extra permissions checks virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - virtual void onFirstRef(); + + virtual status_t dump(int fd, const Vector<String16>& args); + + ///////////////////////////////////////////////////////////////////// + // Client functionality + virtual void removeClientByRemote(const wp<IBinder>& remoteBinder); enum sound_kind { SOUND_SHUTTER = 0, @@ -72,7 +78,53 @@ public: void playSound(sound_kind kind); void releaseSound(); - class Client : public BnCamera + + ///////////////////////////////////////////////////////////////////// + // CameraClient functionality + + // returns plain pointer of client. Note that mClientLock should be acquired to + // prevent the client from destruction. The result can be NULL. + virtual Client* getClientByIdUnsafe(int cameraId); + virtual Mutex* getClientLockById(int cameraId); + + class BasicClient : public virtual RefBase { + public: + virtual status_t initialize(camera_module_t *module) = 0; + + virtual void disconnect() = 0; + + wp<IBinder> getRemote() { + return mRemoteCallback; + } + + protected: + BasicClient(const sp<CameraService>& cameraService, + const sp<IBinder>& remoteCallback, + int cameraId, + int cameraFacing, + int clientPid, + int servicePid); + + virtual ~BasicClient(); + + // the instance is in the middle of destruction. When this is set, + // the instance should not be accessed from callback. + // CameraService's mClientLock should be acquired to access this. + // - subclasses should set this to true in their destructors. + bool mDestructionStarted; + + // these are initialized in the constructor. + sp<CameraService> mCameraService; // immutable after constructor + int mCameraId; // immutable after constructor + int mCameraFacing; // immutable after constructor + pid_t mClientPid; + pid_t mServicePid; // immutable after constructor + + // - The app-side Binder interface to receive callbacks from us + wp<IBinder> mRemoteCallback; // immutable after constructor + }; + + class Client : public BnCamera, public BasicClient { public: // ICamera interface (see ICamera for details) @@ -112,38 +164,82 @@ public: return mCameraClient; } - virtual status_t initialize(camera_module_t *module) = 0; - - virtual status_t dump(int fd, const Vector<String16>& args) = 0; - protected: static Mutex* getClientLockFromCookie(void* user); // convert client from cookie. Client lock should be acquired before getting Client. static Client* getClientFromCookie(void* user); - // the instance is in the middle of destruction. When this is set, - // the instance should not be accessed from callback. - // CameraService's mClientLock should be acquired to access this. - bool mDestructionStarted; + // Initialized in constructor - // these are initialized in the constructor. - sp<CameraService> mCameraService; // immutable after constructor + // - The app-side Binder interface to receive callbacks from us sp<ICameraClient> mCameraClient; - int mCameraId; // immutable after constructor - int mCameraFacing; // immutable after constructor - pid_t mClientPid; - pid_t mServicePid; // immutable after constructor + }; + + class ProClient : public BnProCameraUser, public BasicClient { + public: + ProClient(const sp<CameraService>& cameraService, + const sp<IProCameraCallbacks>& remoteCallback, + int cameraId, + int cameraFacing, + int clientPid, + int servicePid); + + virtual ~ProClient(); + + const sp<IProCameraCallbacks>& getRemoteCallback() { + return mRemoteCallback; + } + + // BasicClient implementation + virtual status_t initialize(camera_module_t *module); + + /*** + IProCamera implementation + ***/ + + + virtual status_t connect( + const sp<IProCameraCallbacks>& callbacks); + virtual void disconnect(); + + 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 requestStream(int streamId); + virtual status_t cancelStream(int streamId); + + protected: + sp<IProCameraCallbacks> mRemoteCallback; }; private: + + // Delay-load the Camera HAL module + virtual void onFirstRef(); + + virtual sp<BasicClient> getClientByRemote(const wp<IBinder>& cameraClient); + Mutex mServiceLock; wp<Client> mClient[MAX_CAMERAS]; // protected by mServiceLock Mutex mClientLock[MAX_CAMERAS]; // prevent Client destruction inside callbacks int mNumberOfCameras; + typedef wp<ProClient> weak_pro_client_ptr; + Vector<weak_pro_client_ptr> mProClientList[MAX_CAMERAS]; + // needs to be called with mServiceLock held sp<Client> findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex); + sp<ProClient> findProClientUnsafe( + const wp<IBinder>& cameraCallbacksRemote); // atomics to record whether the hardware is allocated to some client. volatile int32_t mBusy[MAX_CAMERAS]; @@ -161,6 +257,9 @@ private: // IBinder::DeathRecipient implementation virtual void binderDied(const wp<IBinder> &who); + + // Helpers + int getDeviceVersion(int cameraId, int* facing); }; } // namespace android |