blob: 36c5ada97a9325d996e0415e313a6b149abba999 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
2**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08003** Copyright (C) 2008, The Android Open Source Project
4** Copyright (C) 2008 HTC Inc.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07005**
6** Licensed under the Apache License, Version 2.0 (the "License");
7** you may not use this file except in compliance with the License.
8** You may obtain a copy of the License at
9**
10** http://www.apache.org/licenses/LICENSE-2.0
11**
12** Unless required by applicable law or agreed to in writing, software
13** distributed under the License is distributed on an "AS IS" BASIS,
14** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15** See the License for the specific language governing permissions and
16** limitations under the License.
17*/
18
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080019//#define LOG_NDEBUG 0
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070020#define LOG_TAG "CameraService"
21#include <utils/Log.h>
22
23#include <utils/IServiceManager.h>
24#include <utils/IPCThreadState.h>
25#include <utils/String16.h>
26#include <utils/Errors.h>
27#include <utils/MemoryBase.h>
28#include <utils/MemoryHeapBase.h>
29#include <ui/ICameraService.h>
30
31#include "CameraService.h"
32
33namespace android {
34
35extern "C" {
36#include <stdio.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <fcntl.h>
40#include <pthread.h>
41}
42
43// When you enable this, as well as DEBUG_REFS=1 and
44// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp, this will track all
45// references to the CameraService::Client in order to catch the case where the
46// client is being destroyed while a callback from the CameraHardwareInterface
47// is outstanding. This is a serious bug because if we make another call into
48// CameraHardwreInterface that itself triggers a callback, we will deadlock.
49
50#define DEBUG_CLIENT_REFERENCES 0
51
52#define PICTURE_TIMEOUT seconds(5)
53
54#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */
55#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0
56#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0
57
58#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
59static int debug_frame_cnt;
60#endif
61
62// ----------------------------------------------------------------------------
63
64void CameraService::instantiate() {
65 defaultServiceManager()->addService(
66 String16("media.camera"), new CameraService());
67}
68
69// ----------------------------------------------------------------------------
70
71CameraService::CameraService() :
72 BnCameraService()
73{
74 LOGI("CameraService started: pid=%d", getpid());
75}
76
77CameraService::~CameraService()
78{
79 if (mClient != 0) {
80 LOGE("mClient was still connected in destructor!");
81 }
82}
83
84sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
85{
86 LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
87
88 Mutex::Autolock lock(mLock);
89 if (mClient != 0) {
90 sp<Client> currentClient = mClient.promote();
91 if (currentClient != 0) {
92 sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
93 if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
94 // this is the same client reconnecting...
95 LOGD("Connect X same client is reconnecting...");
96 return currentClient;
97 } else {
98 // it's another client... boot the previous one...
99 LOGD("new client connecting, booting the old one...");
100 mClient.clear();
101 }
102 } else {
103 // can't promote, the previous client has died...
104 LOGD("new client connecting, old reference was dangling...");
105 mClient.clear();
106 }
107 }
108
109 // create a new Client object
The Android Open Source Project27629322009-01-09 17:51:23 -0800110 sp<Client> client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700111 mClient = client;
112#if DEBUG_CLIENT_REFERENCES
113 // Enable tracking for this object, and track increments and decrements of
114 // the refcount.
115 client->trackMe(true, true);
116#endif
117 LOGD("Connect X");
118 return client;
119}
120
121void CameraService::removeClient(const sp<ICameraClient>& cameraClient)
122{
123 // declar this outside the lock to make absolutely sure the
124 // destructor won't be called with the lock held.
125 sp<Client> client;
126
127 Mutex::Autolock lock(mLock);
128
129 if (mClient == 0) {
130 // This happens when we have already disconnected.
131 LOGV("mClient is null.");
132 return;
133 }
134
135 // Promote mClient. It should never fail because we're called from
136 // a binder call, so someone has to have a strong reference.
137 client = mClient.promote();
138 if (client == 0) {
139 LOGW("can't get a strong reference on mClient!");
140 mClient.clear();
141 return;
142 }
143
144 if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) {
145 // ugh! that's not our client!!
146 LOGW("removeClient() called, but mClient doesn't match!");
147 } else {
148 // okay, good, forget about mClient
149 mClient.clear();
150 }
151}
152
153CameraService::Client::Client(const sp<CameraService>& cameraService,
The Android Open Source Project27629322009-01-09 17:51:23 -0800154 const sp<ICameraClient>& cameraClient, pid_t clientPid)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700155{
156 LOGD("Client E constructor");
The Android Open Source Project27629322009-01-09 17:51:23 -0800157 mCameraService = cameraService;
158 mCameraClient = cameraClient;
159 mClientPid = clientPid;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700160 mHardware = openCameraHardware();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800161
162 // Callback is disabled by default
163 mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700164 LOGD("Client X constructor");
165}
166
The Android Open Source Project27629322009-01-09 17:51:23 -0800167status_t CameraService::Client::checkPid()
168{
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800169 if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
170 LOGW("Attempt to use locked camera from different process");
171 return -EBUSY;
The Android Open Source Project27629322009-01-09 17:51:23 -0800172}
173
174status_t CameraService::Client::lock()
175{
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800176 // lock camera to this client if the the camera is unlocked
177 if (mClientPid == 0) {
178 mClientPid = IPCThreadState::self()->getCallingPid();
179 return NO_ERROR;
180 }
181 // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
182 return checkPid();
The Android Open Source Project27629322009-01-09 17:51:23 -0800183}
184
185status_t CameraService::Client::unlock()
186{
187 // allow anyone to use camera
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800188 LOGV("unlock");
The Android Open Source Project27629322009-01-09 17:51:23 -0800189 status_t result = checkPid();
190 if (result == NO_ERROR) mClientPid = 0;
191 return result;
192}
193
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800194status_t CameraService::Client::connect(const sp<ICameraClient>& client)
195{
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800196 // connect a new process to the camera
197 LOGV("connect");
198
199 // hold a reference to the old client or we will deadlock if the client is
200 // in the same process and we hold the lock when we remove the reference
201 sp<ICameraClient> oldClient;
202 {
203 Mutex::Autolock _l(mLock);
204 if (mClientPid != 0) {
205 LOGW("Tried to connect to locked camera");
206 return -EBUSY;
207 }
208 oldClient = mCameraClient;
209
210 // did the client actually change?
211 if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
212
213 LOGV("connect new process to existing camera client");
214 mCameraClient = client;
215 mClientPid = IPCThreadState::self()->getCallingPid();
216 mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
217 }
218
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800219 return NO_ERROR;
220}
221
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700222#if HAVE_ANDROID_OS
223static void *unregister_surface(void *arg)
224{
225 ISurface *surface = (ISurface *)arg;
226 surface->unregisterBuffers();
227 IPCThreadState::self()->flushCommands();
228 return NULL;
229}
230#endif
231
232CameraService::Client::~Client()
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800233{
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800234 // tear down client
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700235 LOGD("Client E destructor");
236 if (mSurface != 0) {
237#if HAVE_ANDROID_OS
238 pthread_t thr;
239 // We unregister the buffers in a different thread because binder does
240 // not let us make sychronous transactions in a binder destructor (that
241 // is, upon our reaching a refcount of zero.)
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800242 pthread_create(&thr, NULL,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700243 unregister_surface,
244 mSurface.get());
245 pthread_join(thr, NULL);
246#else
247 mSurface->unregisterBuffers();
248#endif
249 }
250
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800251 // make sure we tear down the hardware
252 mClientPid = IPCThreadState::self()->getCallingPid();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700253 disconnect();
254 LOGD("Client X destructor");
255}
256
257void CameraService::Client::disconnect()
258{
259 LOGD("Client E disconnect");
260 Mutex::Autolock lock(mLock);
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800261 if (mClientPid == 0) {
262 LOGV("camera is unlocked, don't tear down hardware");
263 return;
264 }
The Android Open Source Project27629322009-01-09 17:51:23 -0800265 if (checkPid() != NO_ERROR) return;
The Android Open Source Project5f78a482009-01-20 14:03:58 -0800266
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700267 mCameraService->removeClient(mCameraClient);
268 if (mHardware != 0) {
269 // Before destroying mHardware, we must make sure it's in the
270 // idle state.
271 mHardware->stopPreview();
272 // Cancel all picture callbacks.
273 mHardware->cancelPicture(true, true, true);
274 // Release the hardware resources.
275 mHardware->release();
276 }
277 mHardware.clear();
278 LOGD("Client X disconnect");
279}
280
281// pass the buffered ISurface to the camera service
282status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
283{
284 LOGD("setPreviewDisplay(%p)", surface.get());
285 Mutex::Autolock lock(mLock);
The Android Open Source Project27629322009-01-09 17:51:23 -0800286 status_t result = checkPid();
287 if (result != NO_ERROR) return result;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700288 Mutex::Autolock surfaceLock(mSurfaceLock);
289 // asBinder() is safe on NULL (returns NULL)
290 if (surface->asBinder() != mSurface->asBinder()) {
291 if (mSurface != 0) {
292 LOGD("clearing old preview surface %p", mSurface.get());
293 mSurface->unregisterBuffers();
294 }
295 mSurface = surface;
296 }
297 return NO_ERROR;
298}
299
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800300// set the frame callback flag to affect how the received frames from
301// preview are handled.
302void CameraService::Client::setFrameCallbackFlag(int frame_callback_flag)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700303{
304 Mutex::Autolock lock(mLock);
The Android Open Source Project27629322009-01-09 17:51:23 -0800305 if (checkPid() != NO_ERROR) return;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800306 mFrameCallbackFlag = frame_callback_flag;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700307}
308
309// start preview mode, must call setPreviewDisplay first
310status_t CameraService::Client::startPreview()
311{
312 LOGD("startPreview()");
313
314 /* we cannot call into mHardware with mLock held because
315 * mHardware has callbacks onto us which acquire this lock
316 */
317
318 Mutex::Autolock lock(mLock);
The Android Open Source Project27629322009-01-09 17:51:23 -0800319 status_t result = checkPid();
320 if (result != NO_ERROR) return result;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700321
322 if (mHardware == 0) {
323 LOGE("mHardware is NULL, returning.");
324 return INVALID_OPERATION;
325 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800326
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700327 if (mSurface == 0) {
328 LOGE("setPreviewDisplay must be called before startPreview!");
329 return INVALID_OPERATION;
330 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800331
The Android Open Source Project27629322009-01-09 17:51:23 -0800332 // do nothing if preview is already started
333 if (mHardware->previewEnabled()) return NO_ERROR;
334
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700335 // XXX: This needs to be improved. remove all hardcoded stuff
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800336
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700337 int w, h;
338 CameraParameters params(mHardware->getParameters());
339 params.getPreviewSize(&w, &h);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800340
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700341#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
342 debug_frame_cnt = 0;
343#endif
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800344
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700345 status_t ret = mHardware->startPreview(previewCallback,
346 mCameraService.get());
347 if (ret == NO_ERROR) {
The Android Open Source Project27629322009-01-09 17:51:23 -0800348 mSurface->unregisterBuffers();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700349 mSurface->registerBuffers(w,h,w,h,
350 PIXEL_FORMAT_YCbCr_420_SP,
351 mHardware->getPreviewHeap());
352 }
353 else LOGE("mHardware->startPreview() failed with status %d\n",
354 ret);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800355
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700356 return ret;
357}
358
359// stop preview mode
360void CameraService::Client::stopPreview()
361{
362 LOGD("stopPreview()");
363
364 Mutex::Autolock lock(mLock);
The Android Open Source Project27629322009-01-09 17:51:23 -0800365 if (checkPid() != NO_ERROR) return;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700366
367 if (mHardware == 0) {
368 LOGE("mHardware is NULL, returning.");
369 return;
370 }
371
372 mHardware->stopPreview();
373 LOGD("stopPreview(), hardware stopped OK");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800374
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700375 if (mSurface != 0) {
376 mSurface->unregisterBuffers();
377 }
378 mPreviewBuffer.clear();
379}
380
The Android Open Source Project27629322009-01-09 17:51:23 -0800381bool CameraService::Client::previewEnabled()
382{
383 Mutex::Autolock lock(mLock);
384 if (mHardware == 0) return false;
385 return mHardware->previewEnabled();
386}
387
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700388// Safely retrieves a strong pointer to the client during a hardware callback.
389sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user)
390{
391 sp<Client> client = 0;
392 CameraService *service = static_cast<CameraService*>(user);
393 if (service != NULL) {
394 Mutex::Autolock ourLock(service->mLock);
395 if (service->mClient != 0) {
396 client = service->mClient.promote();
397 if (client == 0) {
398 LOGE("getClientFromCookie: client appears to have died");
399 service->mClient.clear();
400 }
401 } else {
402 LOGE("getClientFromCookie: got callback but client was NULL");
403 }
404 }
405 return client;
406}
407
408
409#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE || \
410 DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE || \
411 DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
412static void dump_to_file(const char *fname,
413 uint8_t *buf, uint32_t size)
414{
415 int nw, cnt = 0;
416 uint32_t written = 0;
417
418 LOGD("opening file [%s]\n", fname);
419 int fd = open(fname, O_RDWR | O_CREAT);
420 if (fd < 0) {
421 LOGE("failed to create file [%s]: %s", fname, strerror(errno));
422 return;
423 }
424
425 LOGD("writing %d bytes to file [%s]\n", size, fname);
426 while (written < size) {
427 nw = ::write(fd,
428 buf + written,
429 size - written);
430 if (nw < 0) {
431 LOGE("failed to write to file [%s]: %s",
432 fname, strerror(errno));
433 break;
434 }
435 written += nw;
436 cnt++;
437 }
438 LOGD("done writing %d bytes to file [%s] in %d passes\n",
439 size, fname, cnt);
440 ::close(fd);
441}
442#endif
443
444// preview callback - frame buffer update
445void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
446{
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800447 LOGV("previewCallback()");
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700448 sp<Client> client = getClientFromCookie(user);
449 if (client == 0) {
450 return;
451 }
452
453#if DEBUG_HEAP_LEAKS && 0 // debugging
454 if (gWeakHeap == NULL) {
455 ssize_t offset;
456 size_t size;
457 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
458 if (gWeakHeap != heap) {
459 LOGD("SETTING PREVIEW HEAP");
460 heap->trackMe(true, true);
461 gWeakHeap = heap;
462 }
463 }
464#endif
465
466#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
467 {
468 if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
469 ssize_t offset;
470 size_t size;
471 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
472 dump_to_file("/data/preview.yuv",
473 (uint8_t *)heap->base() + offset, size);
474 }
475 }
476#endif
477
478 // The strong pointer guarantees the client will exist, but no lock is held.
479 client->postFrame(mem);
480
481#if DEBUG_CLIENT_REFERENCES
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800482 //**** if the client's refcount is 1, then we are about to destroy it here,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700483 // which is bad--print all refcounts.
484 if (client->getStrongCount() == 1) {
485 LOGE("++++++++++++++++ (PREVIEW) THIS WILL CAUSE A LOCKUP!");
486 client->printRefs();
487 }
488#endif
489}
490
491// take a picture - image is returned in callback
492status_t CameraService::Client::autoFocus()
493{
494 LOGV("autoFocus");
495
496 Mutex::Autolock lock(mLock);
The Android Open Source Project27629322009-01-09 17:51:23 -0800497 status_t result = checkPid();
498 if (result != NO_ERROR) return result;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700499
500 if (mHardware == 0) {
501 LOGE("mHardware is NULL, returning.");
502 return INVALID_OPERATION;
503 }
504
505 return mHardware->autoFocus(autoFocusCallback,
506 mCameraService.get());
507}
508
509// take a picture - image is returned in callback
510status_t CameraService::Client::takePicture()
511{
512 LOGD("takePicture");
513
514 Mutex::Autolock lock(mLock);
The Android Open Source Project27629322009-01-09 17:51:23 -0800515 status_t result = checkPid();
516 if (result != NO_ERROR) return result;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700517
518 if (mHardware == 0) {
519 LOGE("mHardware is NULL, returning.");
520 return INVALID_OPERATION;
521 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800522
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700523 if (mSurface != NULL)
524 mSurface->unregisterBuffers();
525
526 return mHardware->takePicture(shutterCallback,
527 yuvPictureCallback,
528 jpegPictureCallback,
529 mCameraService.get());
530}
531
532// picture callback - snapshot taken
533void CameraService::Client::shutterCallback(void *user)
534{
535 sp<Client> client = getClientFromCookie(user);
536 if (client == 0) {
537 return;
538 }
539
540 client->postShutter();
541}
542
543// picture callback - raw image ready
544void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
545 void *user)
546{
547 sp<Client> client = getClientFromCookie(user);
548 if (client == 0) {
549 return;
550 }
551 if (mem == NULL) {
552 client->postRaw(NULL);
553 client->postError(UNKNOWN_ERROR);
554 return;
555 }
556
557 ssize_t offset;
558 size_t size;
559 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
560#if DEBUG_HEAP_LEAKS && 0 // debugging
561 gWeakHeap = heap; // debugging
562#endif
563
564 //LOGV("yuvPictureCallback(%d, %d, %p)", offset, size, user);
565#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only
566 dump_to_file("/data/photo.yuv",
567 (uint8_t *)heap->base() + offset, size);
568#endif
569
570 // Put the YUV version of the snapshot in the preview display.
571 int w, h;
572 CameraParameters params(client->mHardware->getParameters());
573 params.getPictureSize(&w, &h);
574
575// Mutex::Autolock clientLock(client->mLock);
576 if (client->mSurface != 0) {
577 client->mSurface->unregisterBuffers();
578 client->mSurface->registerBuffers(w,h,w,h,
579 PIXEL_FORMAT_YCbCr_420_SP, heap);
580 client->mSurface->postBuffer(offset);
581 }
582
583 client->postRaw(mem);
584
585#if DEBUG_CLIENT_REFERENCES
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800586 //**** if the client's refcount is 1, then we are about to destroy it here,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700587 // which is bad--print all refcounts.
588 if (client->getStrongCount() == 1) {
589 LOGE("++++++++++++++++ (RAW) THIS WILL CAUSE A LOCKUP!");
590 client->printRefs();
591 }
592#endif
593}
594
595// picture callback - jpeg ready
596void CameraService::Client::jpegPictureCallback(const sp<IMemory>& mem, void *user)
597{
598 sp<Client> client = getClientFromCookie(user);
599 if (client == 0) {
600 return;
601 }
602 if (mem == NULL) {
603 client->postJpeg(NULL);
604 client->postError(UNKNOWN_ERROR);
605 return;
606 }
607
608 /** We absolutely CANNOT call into user code with a lock held **/
609
610#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
611 {
612 ssize_t offset;
613 size_t size;
614 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
615 dump_to_file("/data/photo.jpg",
616 (uint8_t *)heap->base() + offset, size);
617 }
618#endif
619
620 client->postJpeg(mem);
621
622#if DEBUG_CLIENT_REFERENCES
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800623 //**** if the client's refcount is 1, then we are about to destroy it here,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700624 // which is bad--print all refcounts.
625 if (client->getStrongCount() == 1) {
626 LOGE("++++++++++++++++ (JPEG) THIS WILL CAUSE A LOCKUP!");
627 client->printRefs();
628 }
629#endif
630}
631
632void CameraService::Client::autoFocusCallback(bool focused, void *user)
633{
634 LOGV("autoFocusCallback");
635
636 sp<Client> client = getClientFromCookie(user);
637 if (client == 0) {
638 return;
639 }
640
641 client->postAutoFocus(focused);
642
643#if DEBUG_CLIENT_REFERENCES
644 if (client->getStrongCount() == 1) {
645 LOGE("++++++++++++++++ (AUTOFOCUS) THIS WILL CAUSE A LOCKUP!");
646 client->printRefs();
647 }
648#endif
649}
650
651// set preview/capture parameters - key/value pairs
652status_t CameraService::Client::setParameters(const String8& params)
653{
654 LOGD("setParameters(%s)", params.string());
655
656 Mutex::Autolock lock(mLock);
The Android Open Source Project27629322009-01-09 17:51:23 -0800657 status_t result = checkPid();
658 if (result != NO_ERROR) return result;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700659
660 if (mHardware == 0) {
661 LOGE("mHardware is NULL, returning.");
662 return INVALID_OPERATION;
663 }
664
665 CameraParameters p(params);
666 mHardware->setParameters(p);
667 return NO_ERROR;
668}
669
670// get preview/capture parameters - key/value pairs
671String8 CameraService::Client::getParameters() const
672{
673 LOGD("getParameters");
674
675 Mutex::Autolock lock(mLock);
676
677 if (mHardware == 0) {
678 LOGE("mHardware is NULL, returning.");
679 return String8();
680 }
681
682 return mHardware->getParameters().flatten();
683}
684
685void CameraService::Client::postAutoFocus(bool focused)
686{
687 LOGV("postAutoFocus");
688 mCameraClient->autoFocusCallback(focused);
689}
690
691void CameraService::Client::postShutter()
692{
693 mCameraClient->shutterCallback();
694}
695
696void CameraService::Client::postRaw(const sp<IMemory>& mem)
697{
698 LOGD("postRaw");
699 mCameraClient->rawCallback(mem);
700}
701
702void CameraService::Client::postJpeg(const sp<IMemory>& mem)
703{
704 LOGD("postJpeg");
705 mCameraClient->jpegCallback(mem);
706}
707
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800708void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size)
709{
710 LOGV("copyFrameAndPostCopiedFrame");
711 // It is necessary to copy out of pmem before sending this to
712 // the callback. For efficiency, reuse the same MemoryHeapBase
713 // provided it's big enough. Don't allocate the memory or
714 // perform the copy if there's no callback.
715 if (mPreviewBuffer == 0) {
716 mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
717 } else if (size > mPreviewBuffer->virtualSize()) {
718 mPreviewBuffer.clear();
719 mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
720 if (mPreviewBuffer == 0) {
721 LOGE("failed to allocate space for preview buffer");
722 return;
723 }
724 }
725 memcpy(mPreviewBuffer->base(),
726 (uint8_t *)heap->base() + offset, size);
727
728 sp<MemoryBase> frame = new MemoryBase(mPreviewBuffer, 0, size);
729 if (frame == 0) {
730 LOGE("failed to allocate space for frame callback");
731 return;
732 }
733 mCameraClient->frameCallback(frame);
734}
735
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700736void CameraService::Client::postFrame(const sp<IMemory>& mem)
737{
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800738 LOGV("postFrame");
739 if (mem == 0) {
740 LOGW("mem is a null pointer");
741 return;
742 }
743
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700744 ssize_t offset;
745 size_t size;
746 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700747 {
748 Mutex::Autolock surfaceLock(mSurfaceLock);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800749 if (mSurface != NULL) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700750 mSurface->postBuffer(offset);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700751 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700752 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800753
754 // Is the callback enabled or not?
755 if (!(mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
756 // If the enable bit is off, the copy-out and one-shot bits are ignored
757 LOGV("frame callback is diabled");
758 return;
759 }
760
761 // Is the received frame copied out or not?
762 if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
763 LOGV("frame is copied out");
764 copyFrameAndPostCopiedFrame(heap, offset, size);
765 } else {
766 LOGV("frame is directly sent out without copying");
767 mCameraClient->frameCallback(mem);
768 }
769
770 // Is this is one-shot only?
771 if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
772 LOGV("One-shot only, thus clear the bits and disable frame callback");
773 mFrameCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
774 FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
775 FRAME_CALLBACK_FLAG_ENABLE_MASK);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700776 }
777}
778
779void CameraService::Client::postError(status_t error) {
780 mCameraClient->errorCallback(error);
781}
782
783status_t CameraService::dump(int fd, const Vector<String16>& args)
784{
785 const size_t SIZE = 256;
786 char buffer[SIZE];
787 String8 result;
788 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
789 snprintf(buffer, SIZE, "Permission Denial: "
790 "can't dump CameraService from pid=%d, uid=%d\n",
791 IPCThreadState::self()->getCallingPid(),
792 IPCThreadState::self()->getCallingUid());
793 result.append(buffer);
794 write(fd, result.string(), result.size());
795 } else {
796 AutoMutex lock(&mLock);
797 if (mClient != 0) {
798 sp<Client> currentClient = mClient.promote();
799 currentClient->mHardware->dump(fd, args);
800 } else {
801 result.append("No camera client yet.\n");
802 write(fd, result.string(), result.size());
803 }
804 }
805 return NO_ERROR;
806}
807
808
809#if DEBUG_HEAP_LEAKS
810
811#define CHECK_INTERFACE(interface, data, reply) \
812 do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
813 LOGW("Call incorrectly routed to " #interface); \
814 return PERMISSION_DENIED; \
815 } } while (0)
816
817status_t CameraService::onTransact(
818 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
819{
820 // permission checks...
821 switch (code) {
822 case BnCameraService::CONNECT:
823 IPCThreadState* ipc = IPCThreadState::self();
824 const int pid = ipc->getCallingPid();
825 const int self_pid = getpid();
826 if (pid != self_pid) {
827 // we're called from a different process, do the real check
828 if (!checkCallingPermission(
829 String16("android.permission.CAMERA")))
830 {
831 const int uid = ipc->getCallingUid();
832 LOGE("Permission Denial: "
833 "can't use the camera pid=%d, uid=%d", pid, uid);
834 return PERMISSION_DENIED;
835 }
836 }
837 break;
838 }
839
840 status_t err = BnCameraService::onTransact(code, data, reply, flags);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800841
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700842 LOGD("+++ onTransact err %d code %d", err, code);
843
844 if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
845 // the 'service' command interrogates this binder for its name, and then supplies it
846 // even for the debugging commands. that means we need to check for it here, using
847 // ISurfaceComposer (since we delegated the INTERFACE_TRANSACTION handling to
848 // BnSurfaceComposer before falling through to this code).
849
850 LOGD("+++ onTransact code %d", code);
851
852 CHECK_INTERFACE(ICameraService, data, reply);
853
854 switch(code) {
855 case 1000:
856 {
857 if (gWeakHeap != 0) {
858 sp<IMemoryHeap> h = gWeakHeap.promote();
859 IMemoryHeap *p = gWeakHeap.unsafe_get();
860 LOGD("CHECKING WEAK REFERENCE %p (%p)", h.get(), p);
861 if (h != 0)
862 h->printRefs();
863 bool attempt_to_delete = data.readInt32() == 1;
864 if (attempt_to_delete) {
865 // NOT SAFE!
866 LOGD("DELETING WEAK REFERENCE %p (%p)", h.get(), p);
867 if (p) delete p;
868 }
869 return NO_ERROR;
870 }
871 }
872 break;
873 default:
874 break;
875 }
876 }
877 return err;
878}
879
880#endif // DEBUG_HEAP_LEAKS
881
882}; // namespace android
883
884