Loading NOTICE +51 −0 Original line number Diff line number Diff line Loading @@ -220,3 +220,54 @@ the Apache2 License. END OF TERMS AND CONDITIONS UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/ . Unicode Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. COPYRIGHT AND PERMISSION NOTICE Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that (a) the above copyright notice(s) and this permission notice appear with all copies of the Data Files or Software, (b) both the above copyright notice(s) and this permission notice appear in associated documentation, and (c) there is clear notice in each modified Data File or in the Software as well as in the documentation associated with the Data File(s) or Software that the data or software has been modified. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. camera/libcameraservice/CameraService.cpp +226 −118 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <media/AudioSystem.h> #include "CameraService.h" #include <cutils/atomic.h> #include <cutils/properties.h> namespace android { Loading @@ -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 Loading @@ -63,6 +65,10 @@ extern "C" { static int debug_frame_cnt; #endif static int getCallingPid() { return IPCThreadState::self()->getCallingPid(); } // ---------------------------------------------------------------------------- void CameraService::instantiate() { Loading @@ -76,6 +82,7 @@ CameraService::CameraService() : BnCameraService() { LOGI("CameraService started: pid=%d", getpid()); mUsers = 0; } CameraService::~CameraService() Loading @@ -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) Loading @@ -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; Loading @@ -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 Loading @@ -213,13 +260,14 @@ 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; 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(); Loading @@ -229,8 +277,10 @@ status_t CameraService::Client::unlock() 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 Loading @@ -245,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; } Loading @@ -280,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; Loading @@ -307,29 +365,33 @@ 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"); // 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(); Loading @@ -337,19 +399,25 @@ void CameraService::Client::disconnect() 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) { Loading @@ -357,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 Loading @@ -389,23 +468,25 @@ status_t CameraService::Client::startCameraMode(camera_mode mode) return INVALID_OPERATION; } switch(mode) { case CAMERA_RECORDING_MODE: if (mSurface == 0) { LOGE("setPreviewDisplay must be called before startCameraMode!"); LOGE("setPreviewDisplay must be called before startRecordingMode."); return INVALID_OPERATION; } switch(mode) { case CAMERA_RECORDING_MODE: 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; Loading @@ -431,28 +512,15 @@ status_t CameraService::Client::startRecordingMode() return ret; } status_t CameraService::Client::startPreviewMode() status_t CameraService::Client::setOverlay() { LOGV("startPreviewMode"); // if preview has been enabled, nothing needs to be done if (mHardware->previewEnabled()) { return NO_ERROR; } // start preview mode #if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE debug_frame_cnt = 0; #endif status_t ret = UNKNOWN_ERROR; LOGD("setOverlay"); int w, h; CameraParameters params(mHardware->getParameters()); params.getPreviewSize(&w, &h); 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")) Loading @@ -461,22 +529,25 @@ status_t CameraService::Client::startPreviewMode() 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; } 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(); status_t CameraService::Client::registerPreviewBuffers() { int w, h; CameraParameters params(mHardware->getParameters()); params.getPreviewSize(&w, &h); uint32_t transform = 0; if (params.getOrientation() == Loading @@ -490,9 +561,44 @@ status_t CameraService::Client::startPreviewMode() 0, mHardware->getPreviewHeap()); mSurface->registerBuffers(buffers); status_t ret = mSurface->registerBuffers(buffers); if (ret != NO_ERROR) { LOGE("registerBuffers failed with status %d", ret); } return ret; } status_t CameraService::Client::startPreviewMode() { LOGD("startPreviewMode (pid %d)", getCallingPid()); // if preview has been enabled, nothing needs to be done if (mHardware->previewEnabled()) { return NO_ERROR; } // start preview mode #if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE debug_frame_cnt = 0; #endif status_t ret = NO_ERROR; if (mUseOverlay) { // 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()); } else { LOGE("mHardware->startPreview() failed with status %d", ret); ret = mHardware->startPreview(previewCallback, mCameraService.get()); 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; Loading @@ -500,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(); Loading @@ -515,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; Loading @@ -537,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; Loading @@ -552,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; Loading Loading @@ -592,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) { Loading Loading @@ -704,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(); Loading @@ -722,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(); Loading Loading @@ -920,6 +1028,7 @@ void CameraService::Client::postAutoFocus(bool focused) void CameraService::Client::postShutter() { LOGD("postShutter"); mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0); } Loading Loading @@ -1029,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", Loading @@ -1052,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); \ Loading Loading @@ -1085,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) { Loading Loading @@ -1120,9 +1228,9 @@ status_t CameraService::onTransact( break; } } #endif // DEBUG_HEAP_LEAKS return err; } #endif // DEBUG_HEAP_LEAKS }; // namespace android camera/libcameraservice/CameraService.h +8 −3 Original line number Diff line number Diff line Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading
NOTICE +51 −0 Original line number Diff line number Diff line Loading @@ -220,3 +220,54 @@ the Apache2 License. END OF TERMS AND CONDITIONS UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/ . Unicode Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. COPYRIGHT AND PERMISSION NOTICE Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that (a) the above copyright notice(s) and this permission notice appear with all copies of the Data Files or Software, (b) both the above copyright notice(s) and this permission notice appear in associated documentation, and (c) there is clear notice in each modified Data File or in the Software as well as in the documentation associated with the Data File(s) or Software that the data or software has been modified. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder.
camera/libcameraservice/CameraService.cpp +226 −118 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <media/AudioSystem.h> #include "CameraService.h" #include <cutils/atomic.h> #include <cutils/properties.h> namespace android { Loading @@ -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 Loading @@ -63,6 +65,10 @@ extern "C" { static int debug_frame_cnt; #endif static int getCallingPid() { return IPCThreadState::self()->getCallingPid(); } // ---------------------------------------------------------------------------- void CameraService::instantiate() { Loading @@ -76,6 +82,7 @@ CameraService::CameraService() : BnCameraService() { LOGI("CameraService started: pid=%d", getpid()); mUsers = 0; } CameraService::~CameraService() Loading @@ -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) Loading @@ -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; Loading @@ -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 Loading @@ -213,13 +260,14 @@ 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; 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(); Loading @@ -229,8 +277,10 @@ status_t CameraService::Client::unlock() 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 Loading @@ -245,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; } Loading @@ -280,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; Loading @@ -307,29 +365,33 @@ 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"); // 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(); Loading @@ -337,19 +399,25 @@ void CameraService::Client::disconnect() 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) { Loading @@ -357,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 Loading @@ -389,23 +468,25 @@ status_t CameraService::Client::startCameraMode(camera_mode mode) return INVALID_OPERATION; } switch(mode) { case CAMERA_RECORDING_MODE: if (mSurface == 0) { LOGE("setPreviewDisplay must be called before startCameraMode!"); LOGE("setPreviewDisplay must be called before startRecordingMode."); return INVALID_OPERATION; } switch(mode) { case CAMERA_RECORDING_MODE: 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; Loading @@ -431,28 +512,15 @@ status_t CameraService::Client::startRecordingMode() return ret; } status_t CameraService::Client::startPreviewMode() status_t CameraService::Client::setOverlay() { LOGV("startPreviewMode"); // if preview has been enabled, nothing needs to be done if (mHardware->previewEnabled()) { return NO_ERROR; } // start preview mode #if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE debug_frame_cnt = 0; #endif status_t ret = UNKNOWN_ERROR; LOGD("setOverlay"); int w, h; CameraParameters params(mHardware->getParameters()); params.getPreviewSize(&w, &h); 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")) Loading @@ -461,22 +529,25 @@ status_t CameraService::Client::startPreviewMode() 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; } 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(); status_t CameraService::Client::registerPreviewBuffers() { int w, h; CameraParameters params(mHardware->getParameters()); params.getPreviewSize(&w, &h); uint32_t transform = 0; if (params.getOrientation() == Loading @@ -490,9 +561,44 @@ status_t CameraService::Client::startPreviewMode() 0, mHardware->getPreviewHeap()); mSurface->registerBuffers(buffers); status_t ret = mSurface->registerBuffers(buffers); if (ret != NO_ERROR) { LOGE("registerBuffers failed with status %d", ret); } return ret; } status_t CameraService::Client::startPreviewMode() { LOGD("startPreviewMode (pid %d)", getCallingPid()); // if preview has been enabled, nothing needs to be done if (mHardware->previewEnabled()) { return NO_ERROR; } // start preview mode #if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE debug_frame_cnt = 0; #endif status_t ret = NO_ERROR; if (mUseOverlay) { // 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()); } else { LOGE("mHardware->startPreview() failed with status %d", ret); ret = mHardware->startPreview(previewCallback, mCameraService.get()); 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; Loading @@ -500,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(); Loading @@ -515,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; Loading @@ -537,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; Loading @@ -552,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; Loading Loading @@ -592,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) { Loading Loading @@ -704,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(); Loading @@ -722,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(); Loading Loading @@ -920,6 +1028,7 @@ void CameraService::Client::postAutoFocus(bool focused) void CameraService::Client::postShutter() { LOGD("postShutter"); mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0); } Loading Loading @@ -1029,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", Loading @@ -1052,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); \ Loading Loading @@ -1085,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) { Loading Loading @@ -1120,9 +1228,9 @@ status_t CameraService::onTransact( break; } } #endif // DEBUG_HEAP_LEAKS return err; } #endif // DEBUG_HEAP_LEAKS }; // namespace android
camera/libcameraservice/CameraService.h +8 −3 Original line number Diff line number Diff line Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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 Loading