diff options
Diffstat (limited to 'camera')
-rw-r--r-- | camera/libcameraservice/CameraHardwareStub.cpp | 2 | ||||
-rw-r--r-- | camera/libcameraservice/CameraService.cpp | 372 | ||||
-rw-r--r-- | camera/libcameraservice/CameraService.h | 11 | ||||
-rw-r--r-- | camera/libcameraservice/FakeCamera.cpp | 30 | ||||
-rw-r--r-- | camera/libcameraservice/FakeCamera.h | 22 |
5 files changed, 299 insertions, 138 deletions
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp index 0f1ae8e..a7af57c 100644 --- a/camera/libcameraservice/CameraHardwareStub.cpp +++ b/camera/libcameraservice/CameraHardwareStub.cpp @@ -314,7 +314,7 @@ status_t CameraHardwareStub::dump(int fd, const Vector<String16>& args) const String8 result; AutoMutex lock(&mLock); if (mFakeCamera != 0) { - mFakeCamera->dump(fd, args); + mFakeCamera->dump(fd); mParameters.dump(fd, args); snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false"); result.append(buffer); diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index cb8ab58..022fe5a 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -32,6 +32,7 @@ #include <media/AudioSystem.h> #include "CameraService.h" +#include <cutils/atomic.h> #include <cutils/properties.h> namespace android { @@ -42,6 +43,7 @@ extern "C" { #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> +#include <signal.h> } // When you enable this, as well as DEBUG_REFS=1 and @@ -63,6 +65,10 @@ extern "C" { static int debug_frame_cnt; #endif +static int getCallingPid() { + return IPCThreadState::self()->getCallingPid(); +} + // ---------------------------------------------------------------------------- void CameraService::instantiate() { @@ -76,6 +82,7 @@ CameraService::CameraService() : BnCameraService() { LOGI("CameraService started: pid=%d", getpid()); + mUsers = 0; } CameraService::~CameraService() @@ -87,72 +94,105 @@ CameraService::~CameraService() sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient) { - LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get()); + int callingPid = getCallingPid(); + LOGD("CameraService::connect E (pid %d, client %p)", callingPid, + cameraClient->asBinder().get()); - Mutex::Autolock lock(mLock); + Mutex::Autolock lock(mServiceLock); sp<Client> client; if (mClient != 0) { sp<Client> currentClient = mClient.promote(); if (currentClient != 0) { sp<ICameraClient> currentCameraClient(currentClient->getCameraClient()); if (cameraClient->asBinder() == currentCameraClient->asBinder()) { - // this is the same client reconnecting... - LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get()); + // This is the same client reconnecting... + LOGD("CameraService::connect X (pid %d, same client %p) is reconnecting...", + callingPid, cameraClient->asBinder().get()); return currentClient; } else { - // it's another client... reject it - LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get()); + // It's another client... reject it + LOGD("CameraService::connect X (pid %d, new client %p) rejected. " + "(old pid %d, old client %p)", + callingPid, cameraClient->asBinder().get(), + currentClient->mClientPid, currentCameraClient->asBinder().get()); + if (kill(currentClient->mClientPid, 0) == -1 && errno == ESRCH) { + LOGD("The old client is dead!"); + } return client; } } else { // can't promote, the previous client has died... - LOGD("new client connecting, old reference was dangling..."); + LOGD("New client (pid %d) connecting, old reference was dangling...", + callingPid); mClient.clear(); } } + if (mUsers > 0) { + LOGD("Still have client, rejected"); + return client; + } + // create a new Client object - client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid()); + client = new Client(this, cameraClient, callingPid); mClient = client; #if DEBUG_CLIENT_REFERENCES // Enable tracking for this object, and track increments and decrements of // the refcount. client->trackMe(true, true); #endif - LOGD("Connect X"); + LOGD("CameraService::connect X"); return client; } void CameraService::removeClient(const sp<ICameraClient>& cameraClient) { - // declar this outside the lock to make absolutely sure the + int callingPid = getCallingPid(); + + // Declare this outside the lock to make absolutely sure the // destructor won't be called with the lock held. sp<Client> client; - Mutex::Autolock lock(mLock); + Mutex::Autolock lock(mServiceLock); if (mClient == 0) { // This happens when we have already disconnected. - LOGV("mClient is null."); + LOGD("removeClient (pid %d): already disconnected", callingPid); return; } - // Promote mClient. It should never fail because we're called from - // a binder call, so someone has to have a strong reference. + // Promote mClient. It can fail if we are called from this path: + // Client::~Client() -> disconnect() -> removeClient(). client = mClient.promote(); if (client == 0) { - LOGW("can't get a strong reference on mClient!"); + LOGD("removeClient (pid %d): no more strong reference", callingPid); mClient.clear(); return; } if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) { // ugh! that's not our client!! - LOGW("removeClient() called, but mClient doesn't match!"); + LOGW("removeClient (pid %d): mClient doesn't match!", callingPid); } else { // okay, good, forget about mClient mClient.clear(); } + + LOGD("removeClient (pid %d) done", callingPid); +} + +// The reason we need this count is a new CameraService::connect() request may +// come in while the previous Client's destructor has not been run or is still +// running. If the last strong reference of the previous Client is gone but +// destructor has not been run, we should not allow the new Client to be created +// because we need to wait for the previous Client to tear down the hardware +// first. +void CameraService::incUsers() { + android_atomic_inc(&mUsers); +} + +void CameraService::decUsers() { + android_atomic_dec(&mUsers); } static sp<MediaPlayer> newMediaPlayer(const char *file) @@ -177,7 +217,8 @@ static sp<MediaPlayer> newMediaPlayer(const char *file) CameraService::Client::Client(const sp<CameraService>& cameraService, const sp<ICameraClient>& cameraClient, pid_t clientPid) { - LOGD("Client E constructor"); + int callingPid = getCallingPid(); + LOGD("Client::Client E (pid %d)", callingPid); mCameraService = cameraService; mCameraClient = cameraClient; mClientPid = clientPid; @@ -189,22 +230,28 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, // Callback is disabled by default mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; - LOGD("Client X constructor"); + cameraService->incUsers(); + LOGD("Client::Client X (pid %d)", callingPid); } status_t CameraService::Client::checkPid() { - if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR; - LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get()); + int callingPid = getCallingPid(); + if (mClientPid == callingPid) return NO_ERROR; + LOGW("Attempt to use locked camera (client %p) from different process " + " (old pid %d, new pid %d)", + getCameraClient()->asBinder().get(), mClientPid, callingPid); return -EBUSY; } status_t CameraService::Client::lock() { + int callingPid = getCallingPid(); + LOGD("lock from pid %d (mClientPid %d)", callingPid, mClientPid); Mutex::Autolock _l(mLock); // lock camera to this client if the the camera is unlocked if (mClientPid == 0) { - mClientPid = IPCThreadState::self()->getCallingPid(); + mClientPid = callingPid; return NO_ERROR; } // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise @@ -213,25 +260,34 @@ status_t CameraService::Client::lock() status_t CameraService::Client::unlock() { + int callingPid = getCallingPid(); + LOGD("unlock from pid %d (mClientPid %d)", callingPid, mClientPid); Mutex::Autolock _l(mLock); // allow anyone to use camera - LOGV("unlock (%p)", getCameraClient()->asBinder().get()); status_t result = checkPid(); - if (result == NO_ERROR) mClientPid = 0; + if (result == NO_ERROR) { + mClientPid = 0; + LOGD("clear mCameraClient (pid %d)", callingPid); + // we need to remove the reference so that when app goes + // away, the reference count goes to 0. + mCameraClient.clear(); + } return result; } status_t CameraService::Client::connect(const sp<ICameraClient>& client) { + int callingPid = getCallingPid(); + // connect a new process to the camera - LOGV("connect (%p)", client->asBinder().get()); + LOGD("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get()); // I hate this hack, but things get really ugly when the media recorder // service is handing back the camera to the app. The ICameraClient // destructor will be called during the same IPC, making it look like // the remote client is trying to disconnect. This hack temporarily // sets the mClientPid to an invalid pid to prevent the hardware from - // being torn down. + // being torn down. { // hold a reference to the old client or we will deadlock if the client is @@ -239,25 +295,30 @@ status_t CameraService::Client::connect(const sp<ICameraClient>& client) sp<ICameraClient> oldClient; { Mutex::Autolock _l(mLock); - if (mClientPid != 0) { - LOGW("Tried to connect to locked camera"); + if (mClientPid != 0 && checkPid() != NO_ERROR) { + LOGW("Tried to connect to locked camera (old pid %d, new pid %d)", + mClientPid, callingPid); return -EBUSY; } oldClient = mCameraClient; // did the client actually change? - if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR; + if (client->asBinder() == mCameraClient->asBinder()) { + LOGD("Connect to the same client"); + return NO_ERROR; + } mCameraClient = client; mClientPid = -1; mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; - LOGV("connect new process (%d) to existing camera client", mClientPid); + LOGD("Connect to the new client (pid %d, client %p)", + callingPid, mCameraClient->asBinder().get()); } } // the old client destructor is called when oldClient goes out of scope // now we set the new PID to lock the interface again - mClientPid = IPCThreadState::self()->getCallingPid(); + mClientPid = callingPid; return NO_ERROR; } @@ -274,8 +335,11 @@ static void *unregister_surface(void *arg) CameraService::Client::~Client() { + int callingPid = getCallingPid(); + // tear down client - LOGD("Client (%p) E destructor", getCameraClient()->asBinder().get()); + LOGD("Client::~Client E (pid %d, client %p)", + callingPid, getCameraClient()->asBinder().get()); if (mSurface != 0 && !mUseOverlay) { #if HAVE_ANDROID_OS pthread_t thr; @@ -301,49 +365,59 @@ CameraService::Client::~Client() } // make sure we tear down the hardware - mClientPid = IPCThreadState::self()->getCallingPid(); + mClientPid = callingPid; disconnect(); - LOGD("Client X destructor"); + LOGD("Client::~Client X (pid %d)", mClientPid); } void CameraService::Client::disconnect() { - LOGD("Client (%p) E disconnect from (%d)", - getCameraClient()->asBinder().get(), - IPCThreadState::self()->getCallingPid()); + int callingPid = getCallingPid(); + + LOGD("Client::disconnect() E (pid %d client %p)", + callingPid, getCameraClient()->asBinder().get()); + Mutex::Autolock lock(mLock); if (mClientPid <= 0) { - LOGV("camera is unlocked, don't tear down hardware"); + LOGD("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid); return; } if (checkPid() != NO_ERROR) { - LOGV("Different client - don't disconnect"); + LOGD("Different client - don't disconnect"); return; } - mCameraService->removeClient(mCameraClient); - if (mHardware != 0) { - LOGV("hardware teardown"); - // Before destroying mHardware, we must make sure it's in the - // idle state. - mHardware->stopPreview(); - // Cancel all picture callbacks. - mHardware->cancelPicture(true, true, true); - // Release the hardware resources. - mHardware->release(); - } + // Make sure disconnect() is done once and once only, whether it is called + // from the user directly, or called by the destructor. + if (mHardware == 0) return; + + LOGD("hardware teardown"); + // Before destroying mHardware, we must make sure it's in the + // idle state. + mHardware->stopPreview(); + // Cancel all picture callbacks. + mHardware->cancelPicture(true, true, true); + // Release the hardware resources. + mHardware->release(); mHardware.clear(); - LOGD("Client X disconnect"); + + mCameraService->removeClient(mCameraClient); + mCameraService->decUsers(); + + LOGD("Client::disconnect() X (pid %d)", callingPid); } // pass the buffered ISurface to the camera service status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) { - LOGD("setPreviewDisplay(%p)", surface.get()); + LOGD("setPreviewDisplay(%p) (pid %d)", + ((surface == NULL) ? NULL : surface.get()), getCallingPid()); Mutex::Autolock lock(mLock); status_t result = checkPid(); if (result != NO_ERROR) return result; + Mutex::Autolock surfaceLock(mSurfaceLock); + result = NO_ERROR; // asBinder() is safe on NULL (returns NULL) if (surface->asBinder() != mSurface->asBinder()) { if (mSurface != 0 && !mUseOverlay) { @@ -351,24 +425,35 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) mSurface->unregisterBuffers(); } mSurface = surface; + // If preview has been already started, set overlay or register preview + // buffers now. + if (mHardware->previewEnabled()) { + if (mUseOverlay) { + result = setOverlay(); + } else if (mSurface != 0) { + result = registerPreviewBuffers(); + } + } } - return NO_ERROR; + return result; } // set the preview callback flag to affect how the received frames from // preview are handled. void CameraService::Client::setPreviewCallbackFlag(int callback_flag) { - LOGV("setPreviewCallbackFlag"); + LOGV("setPreviewCallbackFlag (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock); if (checkPid() != NO_ERROR) return; mPreviewCallbackFlag = callback_flag; } -// start preview mode, must call setPreviewDisplay first +// start preview mode status_t CameraService::Client::startCameraMode(camera_mode mode) { - LOGD("startCameraMode(%d)", mode); + int callingPid = getCallingPid(); + + LOGD("startCameraMode(%d) (pid %d)", mode, callingPid); /* we cannot call into mHardware with mLock held because * mHardware has callbacks onto us which acquire this lock @@ -383,23 +468,25 @@ status_t CameraService::Client::startCameraMode(camera_mode mode) return INVALID_OPERATION; } - if (mSurface == 0) { - LOGE("setPreviewDisplay must be called before startCameraMode!"); - return INVALID_OPERATION; - } - switch(mode) { case CAMERA_RECORDING_MODE: + if (mSurface == 0) { + LOGE("setPreviewDisplay must be called before startRecordingMode."); + return INVALID_OPERATION; + } return startRecordingMode(); default: // CAMERA_PREVIEW_MODE + if (mSurface == 0) { + LOGD("mSurface is not set yet."); + } return startPreviewMode(); } } status_t CameraService::Client::startRecordingMode() { - LOGV("startRecordingMode"); + LOGD("startRecordingMode (pid %d)", getCallingPid()); status_t ret = UNKNOWN_ERROR; @@ -425,9 +512,65 @@ status_t CameraService::Client::startRecordingMode() return ret; } +status_t CameraService::Client::setOverlay() +{ + LOGD("setOverlay"); + int w, h; + CameraParameters params(mHardware->getParameters()); + params.getPreviewSize(&w, &h); + + const char *format = params.getPreviewFormat(); + int fmt; + if (!strcmp(format, "yuv422i")) + fmt = OVERLAY_FORMAT_YCbCr_422_I; + else if (!strcmp(format, "rgb565")) + fmt = OVERLAY_FORMAT_RGB_565; + else { + LOGE("Invalid preview format for overlays"); + return -EINVAL; + } + + status_t ret = NO_ERROR; + if (mSurface != 0) { + sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt); + ret = mHardware->setOverlay(new Overlay(ref)); + } else { + ret = mHardware->setOverlay(NULL); + } + if (ret != NO_ERROR) { + LOGE("mHardware->setOverlay() failed with status %d\n", ret); + } + return ret; +} + +status_t CameraService::Client::registerPreviewBuffers() +{ + int w, h; + CameraParameters params(mHardware->getParameters()); + params.getPreviewSize(&w, &h); + + uint32_t transform = 0; + if (params.getOrientation() == + CameraParameters::CAMERA_ORIENTATION_PORTRAIT) { + LOGV("portrait mode"); + transform = ISurface::BufferHeap::ROT_90; + } + ISurface::BufferHeap buffers(w, h, w, h, + PIXEL_FORMAT_YCbCr_420_SP, + transform, + 0, + mHardware->getPreviewHeap()); + + status_t ret = mSurface->registerBuffers(buffers); + if (ret != NO_ERROR) { + LOGE("registerBuffers failed with status %d", ret); + } + return ret; +} + status_t CameraService::Client::startPreviewMode() { - LOGV("startPreviewMode"); + LOGD("startPreviewMode (pid %d)", getCallingPid()); // if preview has been enabled, nothing needs to be done if (mHardware->previewEnabled()) { @@ -438,55 +581,24 @@ status_t CameraService::Client::startPreviewMode() #if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE debug_frame_cnt = 0; #endif - status_t ret = UNKNOWN_ERROR; - int w, h; - CameraParameters params(mHardware->getParameters()); - params.getPreviewSize(&w, &h); + status_t ret = NO_ERROR; if (mUseOverlay) { - const char *format = params.getPreviewFormat(); - int fmt; - LOGD("Use Overlays"); - if (!strcmp(format, "yuv422i")) - fmt = OVERLAY_FORMAT_YCbCr_422_I; - else if (!strcmp(format, "rgb565")) - fmt = OVERLAY_FORMAT_RGB_565; - else { - LOGE("Invalid preview format for overlays"); - return -EINVAL; - } - sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt); - ret = mHardware->setOverlay(new Overlay(ref)); - if (ret != NO_ERROR) { - LOGE("mHardware->setOverlay() failed with status %d\n", ret); - return ret; + // If preview display has been set, set overlay now. + if (mSurface != 0) { + ret = setOverlay(); } + if (ret != NO_ERROR) return ret; ret = mHardware->startPreview(NULL, mCameraService.get()); - if (ret != NO_ERROR) - LOGE("mHardware->startPreview() failed with status %d\n", ret); - } else { ret = mHardware->startPreview(previewCallback, mCameraService.get()); - if (ret == NO_ERROR) { - - mSurface->unregisterBuffers(); - - uint32_t transform = 0; - if (params.getOrientation() == - CameraParameters::CAMERA_ORIENTATION_PORTRAIT) { - LOGV("portrait mode"); - transform = ISurface::BufferHeap::ROT_90; - } - ISurface::BufferHeap buffers(w, h, w, h, - PIXEL_FORMAT_YCbCr_420_SP, - transform, - 0, - mHardware->getPreviewHeap()); - - mSurface->registerBuffers(buffers); - } else { - LOGE("mHardware->startPreview() failed with status %d", ret); + if (ret != NO_ERROR) return ret; + // If preview display has been set, register preview buffers now. + if (mSurface != 0) { + // Unregister here because the surface registered with raw heap. + mSurface->unregisterBuffers(); + ret = registerPreviewBuffers(); } } return ret; @@ -494,11 +606,15 @@ status_t CameraService::Client::startPreviewMode() status_t CameraService::Client::startPreview() { + LOGD("startPreview (pid %d)", getCallingPid()); + return startCameraMode(CAMERA_PREVIEW_MODE); } status_t CameraService::Client::startRecording() { + LOGD("startRecording (pid %d)", getCallingPid()); + if (mMediaPlayerBeep.get() != NULL) { mMediaPlayerBeep->seekTo(0); mMediaPlayerBeep->start(); @@ -509,7 +625,7 @@ status_t CameraService::Client::startRecording() // stop preview mode void CameraService::Client::stopPreview() { - LOGD("stopPreview()"); + LOGD("stopPreview (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock); if (checkPid() != NO_ERROR) return; @@ -531,7 +647,7 @@ void CameraService::Client::stopPreview() // stop recording mode void CameraService::Client::stopRecording() { - LOGV("stopRecording()"); + LOGD("stopRecording (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock); if (checkPid() != NO_ERROR) return; @@ -546,15 +662,13 @@ void CameraService::Client::stopRecording() mMediaPlayerBeep->start(); } mHardware->stopRecording(); - LOGV("stopRecording(), hardware stopped OK"); + LOGD("stopRecording(), hardware stopped OK"); mPreviewBuffer.clear(); } // release a recording frame void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) { - LOGV("releaseRecordingFrame()"); - Mutex::Autolock lock(mLock); if (checkPid() != NO_ERROR) return; @@ -586,7 +700,7 @@ sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) sp<Client> client = 0; CameraService *service = static_cast<CameraService*>(user); if (service != NULL) { - Mutex::Autolock ourLock(service->mLock); + Mutex::Autolock ourLock(service->mServiceLock); if (service->mClient != 0) { client = service->mClient.promote(); if (client == 0) { @@ -698,7 +812,7 @@ void CameraService::Client::recordingCallback(const sp<IMemory>& mem, void* user // take a picture - image is returned in callback status_t CameraService::Client::autoFocus() { - LOGV("autoFocus"); + LOGD("autoFocus (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock); status_t result = checkPid(); @@ -716,7 +830,7 @@ status_t CameraService::Client::autoFocus() // take a picture - image is returned in callback status_t CameraService::Client::takePicture() { - LOGD("takePicture"); + LOGD("takePicture (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock); status_t result = checkPid(); @@ -894,8 +1008,6 @@ status_t CameraService::Client::setParameters(const String8& params) // get preview/capture parameters - key/value pairs String8 CameraService::Client::getParameters() const { - LOGD("getParameters"); - Mutex::Autolock lock(mLock); if (mHardware == 0) { @@ -903,30 +1015,33 @@ String8 CameraService::Client::getParameters() const return String8(); } - return mHardware->getParameters().flatten(); + String8 params(mHardware->getParameters().flatten()); + LOGD("getParameters(%s)", params.string()); + return params; } void CameraService::Client::postAutoFocus(bool focused) { LOGV("postAutoFocus"); - mCameraClient->autoFocusCallback(focused); + mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, (int32_t)focused, 0); } void CameraService::Client::postShutter() { - mCameraClient->shutterCallback(); + LOGD("postShutter"); + mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0); } void CameraService::Client::postRaw(const sp<IMemory>& mem) { LOGD("postRaw"); - mCameraClient->rawCallback(mem); + mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem); } void CameraService::Client::postJpeg(const sp<IMemory>& mem) { LOGD("postJpeg"); - mCameraClient->jpegCallback(mem); + mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem); } void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size) @@ -954,7 +1069,7 @@ void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, si LOGE("failed to allocate space for frame callback"); return; } - mCameraClient->previewCallback(frame); + mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame); } void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame) @@ -964,7 +1079,7 @@ void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame) LOGW("frame is a null pointer"); return; } - mCameraClient->recordingCallback(frame); + mCameraClient->dataCallback(CAMERA_MSG_VIDEO_FRAME, frame); } void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem) @@ -998,7 +1113,7 @@ void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem) copyFrameAndPostCopiedFrame(heap, offset, size); } else { LOGV("frame is directly sent out without copying"); - mCameraClient->previewCallback(mem); + mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem); } // Is this is one-shot only? @@ -1012,7 +1127,7 @@ void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem) void CameraService::Client::postError(status_t error) { - mCameraClient->errorCallback(error); + mCameraClient->notifyCallback(CAMERA_MSG_ERROR, error, 0); } status_t CameraService::dump(int fd, const Vector<String16>& args) @@ -1023,12 +1138,12 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) if (checkCallingPermission(String16("android.permission.DUMP")) == false) { snprintf(buffer, SIZE, "Permission Denial: " "can't dump CameraService from pid=%d, uid=%d\n", - IPCThreadState::self()->getCallingPid(), + getCallingPid(), IPCThreadState::self()->getCallingUid()); result.append(buffer); write(fd, result.string(), result.size()); } else { - AutoMutex lock(&mLock); + AutoMutex lock(&mServiceLock); if (mClient != 0) { sp<Client> currentClient = mClient.promote(); sprintf(buffer, "Client (%p) PID: %d\n", @@ -1046,8 +1161,6 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) } -#if DEBUG_HEAP_LEAKS - #define CHECK_INTERFACE(interface, data, reply) \ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ LOGW("Call incorrectly routed to " #interface); \ @@ -1079,6 +1192,7 @@ status_t CameraService::onTransact( status_t err = BnCameraService::onTransact(code, data, reply, flags); +#if DEBUG_HEAP_LEAKS LOGD("+++ onTransact err %d code %d", err, code); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { @@ -1114,9 +1228,9 @@ status_t CameraService::onTransact( break; } } +#endif // DEBUG_HEAP_LEAKS + return err; } -#endif // DEBUG_HEAP_LEAKS - }; // namespace android diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h index 6752f26..0f07673 100644 --- a/camera/libcameraservice/CameraService.h +++ b/camera/libcameraservice/CameraService.h @@ -58,10 +58,8 @@ public: void removeClient(const sp<ICameraClient>& cameraClient); -#if DEBUG_HEAP_LEAKS virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); -#endif private: @@ -159,6 +157,8 @@ private: status_t startCameraMode(camera_mode mode); status_t startPreviewMode(); status_t startRecordingMode(); + status_t setOverlay(); + status_t registerPreviewBuffers(); // Ensures atomicity among the public methods mutable Mutex mLock; @@ -196,7 +196,12 @@ private: CameraService(); virtual ~CameraService(); - mutable Mutex mLock; + // We use a count for number of clients (shoule only be 0 or 1). + volatile int32_t mUsers; + virtual void incUsers(); + virtual void decUsers(); + + mutable Mutex mServiceLock; wp<Client> mClient; #if DEBUG_HEAP_LEAKS diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp index 3592eab..3daf47d 100644 --- a/camera/libcameraservice/FakeCamera.cpp +++ b/camera/libcameraservice/FakeCamera.cpp @@ -1,12 +1,39 @@ +/* +** +** Copyright 2008, 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 "FakeCamera" #include <utils/Log.h> #include <string.h> #include <stdlib.h> +#include <utils/String8.h> + #include "FakeCamera.h" + namespace android { +// TODO: All this rgb to yuv should probably be in a util class. + +// TODO: I think something is wrong in this class because the shadow is kBlue +// and the square color should alternate between kRed and kGreen. However on the +// emulator screen these are all shades of gray. Y seems ok but the U and V are +// probably not. + static int tables_initialized = 0; uint8_t *gYTable, *gCbTable, *gCrTable; @@ -389,7 +416,7 @@ void FakeCamera::drawCheckerboard(uint16_t *dst, int size) } -status_t FakeCamera::dump(int fd, const Vector<String16>& args) +void FakeCamera::dump(int fd) const { const size_t SIZE = 256; char buffer[SIZE]; @@ -397,7 +424,6 @@ status_t FakeCamera::dump(int fd, const Vector<String16>& args) snprintf(buffer, 255, " width x height (%d x %d), counter (%d), check x-y coordinate(%d, %d)\n", mWidth, mHeight, mCounter, mCheckX, mCheckY); result.append(buffer); ::write(fd, result.string(), result.size()); - return NO_ERROR; } diff --git a/camera/libcameraservice/FakeCamera.h b/camera/libcameraservice/FakeCamera.h index 77c994c..f7f8803 100644 --- a/camera/libcameraservice/FakeCamera.h +++ b/camera/libcameraservice/FakeCamera.h @@ -18,21 +18,37 @@ #ifndef ANDROID_HARDWARE_FAKECAMERA_H #define ANDROID_HARDWARE_FAKECAMERA_H -#include <ui/CameraHardwareInterface.h> +#include <sys/types.h> +#include <stdint.h> namespace android { +/* + * FakeCamera is used in the CameraHardwareStub to provide a fake video feed + * when the system does not have a camera in hardware. + * The fake video is a moving black and white checkerboard background with a + * bouncing gray square in the foreground. + * This class is not thread-safe. + * + * TODO: Since the major methods provides a raw/uncompressed video feed, rename + * this class to RawVideoSource. + */ + class FakeCamera { public: FakeCamera(int width, int height); ~FakeCamera(); void setSize(int width, int height); - void getNextFrameAsRgb565(uint16_t *buffer); void getNextFrameAsYuv422(uint8_t *buffer); - status_t dump(int fd, const Vector<String16>& args); + // Write to the fd a string representing the current state. + void dump(int fd) const; private: + // TODO: remove the uint16_t buffer param everywhere since it is a field of + // this class. + void getNextFrameAsRgb565(uint16_t *buffer); + void drawSquare(uint16_t *buffer, int x, int y, int size, int color, int shadow); void drawCheckerboard(uint16_t *buffer, int size); |