summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWu-cheng Li <wuchengli@google.com>2012-02-23 19:01:00 -0800
committerWu-cheng Li <wuchengli@google.com>2012-03-15 14:50:48 +0800
commit2fd2440d0175ca3e196b01b7541a9e0d4ed9a694 (patch)
treed87e4314688e65f4c53f04021c8452051d4b31eb
parentcbcd6e869dd41158076e742a31c1ee410fc0c713 (diff)
downloadframeworks_av-2fd2440d0175ca3e196b01b7541a9e0d4ed9a694.zip
frameworks_av-2fd2440d0175ca3e196b01b7541a9e0d4ed9a694.tar.gz
frameworks_av-2fd2440d0175ca3e196b01b7541a9e0d4ed9a694.tar.bz2
Add a new camera open API that allows taking the ownership.
The purpose is to let face unlock always get the camera successfully. What happened was the camera applications may have opened the camera in onResume under the lock screen. This API lets face unlock take the camera from the camera application. A new permission will be added, so other applicatoins won't be able to take the camera from the face unlock. bug:5584464 Change-Id: Ib3d9dcbc2161815b68db42327dc01148453704c6
-rw-r--r--camera/Camera.cpp4
-rw-r--r--camera/ICameraService.cpp11
-rw-r--r--include/camera/Camera.h2
-rw-r--r--include/camera/ICameraService.h2
-rwxr-xr-xmedia/libstagefright/CameraSource.cpp2
-rw-r--r--services/camera/libcameraservice/CameraService.cpp149
-rw-r--r--services/camera/libcameraservice/CameraService.h15
7 files changed, 143 insertions, 42 deletions
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index d43cb0b..b81fe86 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -116,13 +116,13 @@ status_t Camera::getCameraInfo(int cameraId,
return cs->getCameraInfo(cameraId, cameraInfo);
}
-sp<Camera> Camera::connect(int cameraId)
+sp<Camera> Camera::connect(int cameraId, bool force, bool keep)
{
ALOGV("connect");
sp<Camera> c = new Camera();
const sp<ICameraService>& cs = getCameraService();
if (cs != 0) {
- c->mCamera = cs->connect(c, cameraId);
+ c->mCamera = cs->connect(c, cameraId, force, keep);
}
if (c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 85f1a29..c74298a 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -56,12 +56,15 @@ public:
}
// connect to camera service
- virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId)
+ virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
+ bool force, bool keep)
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
data.writeStrongBinder(cameraClient->asBinder());
data.writeInt32(cameraId);
+ data.writeInt32(force);
+ data.writeInt32(keep);
remote()->transact(BnCameraService::CONNECT, data, &reply);
return interface_cast<ICamera>(reply.readStrongBinder());
}
@@ -93,7 +96,10 @@ status_t BnCameraService::onTransact(
case CONNECT: {
CHECK_INTERFACE(ICameraService, data, reply);
sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
- sp<ICamera> camera = connect(cameraClient, data.readInt32());
+ const int cameraId = data.readInt32();
+ const int force = data.readInt32();
+ const int keep = data.readInt32();
+ sp<ICamera> camera = connect(cameraClient, cameraId, force, keep);
reply->writeStrongBinder(camera->asBinder());
return NO_ERROR;
} break;
@@ -105,4 +111,3 @@ status_t BnCameraService::onTransact(
// ----------------------------------------------------------------------------
}; // namespace android
-
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 234e165..3fedea0 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -72,7 +72,7 @@ public:
static int32_t getNumberOfCameras();
static status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo);
- static sp<Camera> connect(int cameraId);
+ static sp<Camera> connect(int cameraId, bool force, bool keep);
virtual ~Camera();
void init();
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 7d70c1e..97e3169 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -42,7 +42,7 @@ public:
virtual status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo) = 0;
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient,
- int cameraId) = 0;
+ int cameraId, bool force, bool keep) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 2df5528..0d67800 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -182,7 +182,7 @@ status_t CameraSource::isCameraAvailable(
int32_t cameraId) {
if (camera == 0) {
- mCamera = Camera::connect(cameraId);
+ mCamera = Camera::connect(cameraId, false, false);
if (mCamera == 0) return -EBUSY;
mCameraFlags &= ~FLAGS_HOT_CAMERA;
} else {
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index adf1d49..22836e3 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <sys/types.h>
#include <pthread.h>
+#include <time.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -33,6 +34,7 @@
#include <hardware/hardware.h>
#include <media/AudioSystem.h>
#include <media/mediaplayer.h>
+#include <utils/Condition.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/String16.h>
@@ -42,6 +44,8 @@
namespace android {
+#define WAIT_RELEASE_TIMEOUT 250 // 250ms
+
// ----------------------------------------------------------------------------
// Logging support -- this is for debugging only
// Use "adb shell dumpsys media.camera -v 1" to change it.
@@ -64,6 +68,13 @@ static int getCallingUid() {
return IPCThreadState::self()->getCallingUid();
}
+static long long getTimeInMs() {
+ struct timeval t;
+ t.tv_sec = t.tv_usec = 0;
+ gettimeofday(&t, NULL);
+ return t.tv_sec * 1000LL + t.tv_usec / 1000;
+}
+
// ----------------------------------------------------------------------------
// This is ugly and only safe if we never re-create the CameraService, but
@@ -131,7 +142,7 @@ status_t CameraService::getCameraInfo(int cameraId,
}
sp<ICamera> CameraService::connect(
- const sp<ICameraClient>& cameraClient, int cameraId) {
+ const sp<ICameraClient>& cameraClient, int cameraId, bool force, bool keep) {
int callingPid = getCallingPid();
sp<CameraHardwareInterface> hardware = NULL;
@@ -157,27 +168,73 @@ sp<ICamera> CameraService::connect(
return NULL;
}
+ if (keep && !checkCallingPermission(String16("android.permission.KEEP_CAMERA"))) {
+ ALOGE("connect X (pid %d) rejected (no KEEP_CAMERA permission).", callingPid);
+ return NULL;
+ }
+
Mutex::Autolock lock(mServiceLock);
- if (mClient[cameraId] != 0) {
- client = mClient[cameraId].promote();
- if (client != 0) {
- if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
- LOG1("CameraService::connect X (pid %d) (the same client)",
- callingPid);
- return client;
- } else {
- ALOGW("CameraService::connect X (pid %d) rejected (existing client).",
- callingPid);
- return NULL;
- }
+ // Check if there is an existing client.
+ client = mClient[cameraId].promote();
+ if (client != 0 &&
+ cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
+ LOG1("connect X (pid %d) (the same client)", callingPid);
+ return client;
+ }
+
+ if (!force) {
+ if (mClient[cameraId].promote() != 0) {
+ ALOGW("connect X (pid %d) rejected (existing client).", callingPid);
+ return NULL;
}
mClient[cameraId].clear();
- }
+ if (mBusy[cameraId]) {
+ ALOGW("connect X (pid %d) rejected (camera %d is still busy).",
+ callingPid, cameraId);
+ return NULL;
+ }
+ } else { // force == true
+ int i = 0;
+ long long start_time = getTimeInMs();
+ while (i < mNumberOfCameras) {
+ if (getTimeInMs() - start_time >= 3000LL) {
+ ALOGE("connect X (pid %d) rejected (timeout 3s)", callingPid);
+ return NULL;
+ }
- if (mBusy[cameraId]) {
- ALOGW("CameraService::connect X (pid %d) rejected"
- " (camera %d is still busy).", callingPid, cameraId);
- return NULL;
+ client = mClient[i].promote();
+ if (client != 0) {
+ if (client->keep()) {
+ ALOGW("connect X (pid %d) rejected (existing client wants to keeps the camera)",
+ callingPid);
+ return NULL;
+ } else {
+ ALOGW("New client (pid %d, id=%d). Disconnect the existing client (id=%d).",
+ callingPid, cameraId, i);
+ // Do not hold mServiceLock because disconnect will try to get it.
+ mServiceLock.unlock();
+ client->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0, &i);
+ client->waitRelease(WAIT_RELEASE_TIMEOUT);
+ client->disconnectInternal(false);
+ mServiceLock.lock();
+ // Restart from the first client because a new client may have connected
+ // when mServiceLock is unlocked.
+ i = 0;
+ continue;
+ }
+ }
+
+ if (mBusy[i]) {
+ // Give the client a chance to release the hardware.
+ mServiceLock.unlock();
+ usleep(10 * 1000);
+ mServiceLock.lock();
+ i = 0; // Restart from the first client
+ continue;
+ }
+
+ i++;
+ }
}
struct camera_info info;
@@ -195,9 +252,15 @@ sp<ICamera> CameraService::connect(
return NULL;
}
- client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
+ client = new Client(this, cameraClient, hardware, cameraId, info.facing,
+ callingPid, keep);
+ // We need to clear the hardware here. After the destructor of mServiceLock
+ // finishes, a new client may connect and disconnect this client. If this
+ // reference is not cleared, the destructor of CameraHardwareInterface
+ // cannot run. The new client will not be able to connect.
+ hardware.clear();
mClient[cameraId] = client;
- LOG1("CameraService::connect X");
+ LOG1("CameraService::connect X (id %d)", cameraId);
return client;
}
@@ -331,9 +394,9 @@ void CameraService::playSound(sound_kind kind) {
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient,
const sp<CameraHardwareInterface>& hardware,
- int cameraId, int cameraFacing, int clientPid) {
+ int cameraId, int cameraFacing, int clientPid, bool keep) {
int callingPid = getCallingPid();
- LOG1("Client::Client E (pid %d)", callingPid);
+ LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
mCameraService = cameraService;
mCameraClient = cameraClient;
@@ -341,6 +404,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
mCameraId = cameraId;
mCameraFacing = cameraFacing;
mClientPid = clientPid;
+ mKeep = keep;
mMsgEnabled = 0;
mSurface = 0;
mPreviewWindow = 0;
@@ -359,7 +423,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
mPlayShutterSound = true;
cameraService->setCameraBusy(cameraId);
cameraService->loadSound();
- LOG1("Client::Client X (pid %d)", callingPid);
+ LOG1("Client::Client X (pid %d, id %d)", callingPid, cameraId);
}
// tear down the client
@@ -468,18 +532,24 @@ static void disconnectWindow(const sp<ANativeWindow>& window) {
}
void CameraService::Client::disconnect() {
+ disconnectInternal(true);
+}
+
+void CameraService::Client::disconnectInternal(bool needCheckPid) {
int callingPid = getCallingPid();
- LOG1("disconnect E (pid %d)", callingPid);
+ LOG1("disconnectInternal E (pid %d)", callingPid);
Mutex::Autolock lock(mLock);
- if (checkPid() != NO_ERROR) {
- ALOGW("different client - don't disconnect");
- return;
- }
+ if (needCheckPid) {
+ if (checkPid() != NO_ERROR) {
+ ALOGW("different client - don't disconnect");
+ return;
+ }
- if (mClientPid <= 0) {
- LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
- return;
+ if (mClientPid <= 0) {
+ LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
+ return;
+ }
}
// Make sure disconnect() is done once and once only, whether it is called
@@ -506,8 +576,16 @@ void CameraService::Client::disconnect() {
mCameraService->removeClient(mCameraClient);
mCameraService->setCameraFree(mCameraId);
+ mReleaseCondition.signal();
+
+ LOG1("disconnectInternal X (pid %d)", callingPid);
+}
- LOG1("disconnect X (pid %d)", callingPid);
+void CameraService::Client::waitRelease(int ms) {
+ Mutex::Autolock lock(mLock);
+ if (mHardware != 0) {
+ mReleaseCondition.waitRelative(mLock, ms * 1000000);
+ }
}
// ----------------------------------------------------------------------------
@@ -874,6 +952,9 @@ status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t a
return OK;
} else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) {
mCameraService->playSound(SOUND_RECORDING);
+ } else if (cmd == CAMERA_CMD_PING) {
+ // If mHardware is 0, checkPidAndHardware will return error.
+ return OK;
}
return mHardware->sendCommand(cmd, arg1, arg2);
@@ -1217,6 +1298,10 @@ int CameraService::Client::getOrientation(int degrees, bool mirror) {
return -1;
}
+// Whether the client wants to keep the camera from taking
+bool CameraService::Client::keep() const {
+ return mKeep;
+}
// ----------------------------------------------------------------------------
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index bad41f5..457c79b 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -46,7 +46,8 @@ public:
virtual int32_t getNumberOfCameras();
virtual status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo);
- virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId);
+ virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
+ bool force, bool keep);
virtual void removeClient(const sp<ICameraClient>& cameraClient);
virtual sp<Client> getClientById(int cameraId);
@@ -114,7 +115,8 @@ private:
const sp<CameraHardwareInterface>& hardware,
int cameraId,
int cameraFacing,
- int clientPid);
+ int clientPid,
+ bool keep);
~Client();
// return our camera client
@@ -172,12 +174,19 @@ private:
const sp<IBinder>& binder,
const sp<ANativeWindow>& window);
+ void disconnectInternal(bool needCheckPid);
+ bool keep() const;
+ void waitRelease(int ms);
+
+
// these are initialized in the constructor.
sp<CameraService> mCameraService; // immutable after constructor
sp<ICameraClient> mCameraClient;
int mCameraId; // immutable after constructor
int mCameraFacing; // immutable after constructor
pid_t mClientPid;
+ // Client wants to keep the camera from taking by other clients.
+ bool mKeep;
sp<CameraHardwareInterface> mHardware; // cleared after disconnect()
int mPreviewCallbackFlag;
int mOrientation; // Current display orientation
@@ -185,6 +194,8 @@ private:
// Ensures atomicity among the public methods
mutable Mutex mLock;
+ // This will get notified when the hardware is released.
+ Condition mReleaseCondition;
// This is a binder of Surface or SurfaceTexture.
sp<IBinder> mSurface;
sp<ANativeWindow> mPreviewWindow;