blob: f86ca475b67804a98d0aa5d4acbfa2c4615a67b0 [file] [log] [blame]
James Dong199d1c12011-03-17 11:48:13 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080017#define LOG_TAG "CameraServiceTest"
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/types.h>
23#include <sys/wait.h>
24#include <unistd.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080025#include <surfaceflinger/ISurface.h>
26#include <camera/Camera.h>
27#include <camera/CameraParameters.h>
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080028#include <ui/GraphicBuffer.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080029#include <camera/ICamera.h>
30#include <camera/ICameraClient.h>
31#include <camera/ICameraService.h>
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080032#include <ui/Overlay.h>
33#include <binder/IPCThreadState.h>
34#include <binder/IServiceManager.h>
35#include <binder/ProcessState.h>
36#include <utils/KeyedVector.h>
37#include <utils/Log.h>
38#include <utils/Vector.h>
39#include <utils/threads.h>
40
41using namespace android;
42
43//
44// Assertion and Logging utilities
45//
46#define INFO(...) \
47 do { \
48 printf(__VA_ARGS__); \
49 printf("\n"); \
50 LOGD(__VA_ARGS__); \
51 } while(0)
52
53void assert_fail(const char *file, int line, const char *func, const char *expr) {
54 INFO("assertion failed at file %s, line %d, function %s:",
55 file, line, func);
56 INFO("%s", expr);
Chih-Chung Change25cc652010-05-06 16:36:58 +080057 abort();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080058}
59
60void assert_eq_fail(const char *file, int line, const char *func,
61 const char *expr, int actual) {
62 INFO("assertion failed at file %s, line %d, function %s:",
63 file, line, func);
64 INFO("(expected) %s != (actual) %d", expr, actual);
Chih-Chung Change25cc652010-05-06 16:36:58 +080065 abort();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080066}
67
68#define ASSERT(e) \
69 do { \
70 if (!(e)) \
71 assert_fail(__FILE__, __LINE__, __func__, #e); \
72 } while(0)
73
74#define ASSERT_EQ(expected, actual) \
75 do { \
76 int _x = (actual); \
77 if (_x != (expected)) \
78 assert_eq_fail(__FILE__, __LINE__, __func__, #expected, _x); \
79 } while(0)
80
81//
82// Holder service for pass objects between processes.
83//
84class IHolder : public IInterface {
85protected:
86 enum {
87 HOLDER_PUT = IBinder::FIRST_CALL_TRANSACTION,
88 HOLDER_GET,
89 HOLDER_CLEAR
90 };
91public:
92 DECLARE_META_INTERFACE(Holder);
93
94 virtual void put(sp<IBinder> obj) = 0;
95 virtual sp<IBinder> get() = 0;
96 virtual void clear() = 0;
97};
98
99class BnHolder : public BnInterface<IHolder> {
100 virtual status_t onTransact(uint32_t code,
101 const Parcel& data,
102 Parcel* reply,
103 uint32_t flags = 0);
104};
105
106class BpHolder : public BpInterface<IHolder> {
107public:
108 BpHolder(const sp<IBinder>& impl)
109 : BpInterface<IHolder>(impl) {
110 }
111
112 virtual void put(sp<IBinder> obj) {
113 Parcel data, reply;
114 data.writeStrongBinder(obj);
115 remote()->transact(HOLDER_PUT, data, &reply, IBinder::FLAG_ONEWAY);
116 }
117
118 virtual sp<IBinder> get() {
119 Parcel data, reply;
120 remote()->transact(HOLDER_GET, data, &reply);
121 return reply.readStrongBinder();
122 }
123
124 virtual void clear() {
125 Parcel data, reply;
126 remote()->transact(HOLDER_CLEAR, data, &reply);
127 }
128};
129
130IMPLEMENT_META_INTERFACE(Holder, "CameraServiceTest.Holder");
131
132status_t BnHolder::onTransact(
133 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
134 switch(code) {
135 case HOLDER_PUT: {
136 put(data.readStrongBinder());
137 return NO_ERROR;
138 } break;
139 case HOLDER_GET: {
140 reply->writeStrongBinder(get());
141 return NO_ERROR;
142 } break;
143 case HOLDER_CLEAR: {
144 clear();
145 return NO_ERROR;
146 } break;
147 default:
148 return BBinder::onTransact(code, data, reply, flags);
149 }
150}
151
152class HolderService : public BnHolder {
153 virtual void put(sp<IBinder> obj) {
154 mObj = obj;
155 }
156 virtual sp<IBinder> get() {
157 return mObj;
158 }
159 virtual void clear() {
160 mObj.clear();
161 }
162private:
163 sp<IBinder> mObj;
164};
165
166//
167// A mock CameraClient
168//
169class MCameraClient : public BnCameraClient {
170public:
171 virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
172 virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
173 virtual void dataCallbackTimestamp(nsecs_t timestamp,
Chih-Chung Change25cc652010-05-06 16:36:58 +0800174 int32_t msgType, const sp<IMemory>& data);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800175
176 // new functions
177 void clearStat();
178 enum OP { EQ, GE, LE, GT, LT };
179 void assertNotify(int32_t msgType, OP op, int count);
180 void assertData(int32_t msgType, OP op, int count);
181 void waitNotify(int32_t msgType, OP op, int count);
182 void waitData(int32_t msgType, OP op, int count);
183 void assertDataSize(int32_t msgType, OP op, int dataSize);
184
185 void setReleaser(ICamera *releaser) {
186 mReleaser = releaser;
187 }
188private:
189 Mutex mLock;
190 Condition mCond;
191 DefaultKeyedVector<int32_t, int> mNotifyCount;
192 DefaultKeyedVector<int32_t, int> mDataCount;
193 DefaultKeyedVector<int32_t, int> mDataSize;
194 bool test(OP op, int v1, int v2);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800195 void assertTest(OP op, int v1, int v2);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800196
197 ICamera *mReleaser;
198};
199
200void MCameraClient::clearStat() {
201 Mutex::Autolock _l(mLock);
202 mNotifyCount.clear();
203 mDataCount.clear();
204 mDataSize.clear();
205}
206
207bool MCameraClient::test(OP op, int v1, int v2) {
208 switch (op) {
209 case EQ: return v1 == v2;
210 case GT: return v1 > v2;
211 case LT: return v1 < v2;
212 case GE: return v1 >= v2;
213 case LE: return v1 <= v2;
214 default: ASSERT(0); break;
215 }
216 return false;
217}
218
Chih-Chung Change25cc652010-05-06 16:36:58 +0800219void MCameraClient::assertTest(OP op, int v1, int v2) {
220 if (!test(op, v1, v2)) {
221 LOGE("assertTest failed: op=%d, v1=%d, v2=%d", op, v1, v2);
222 ASSERT(0);
223 }
224}
225
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800226void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
227 Mutex::Autolock _l(mLock);
228 int v = mNotifyCount.valueFor(msgType);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800229 assertTest(op, v, count);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800230}
231
232void MCameraClient::assertData(int32_t msgType, OP op, int count) {
233 Mutex::Autolock _l(mLock);
234 int v = mDataCount.valueFor(msgType);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800235 assertTest(op, v, count);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800236}
237
238void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
239 Mutex::Autolock _l(mLock);
240 int v = mDataSize.valueFor(msgType);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800241 assertTest(op, v, dataSize);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800242}
243
244void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700245 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800246 Mutex::Autolock _l(mLock);
247 ssize_t i = mNotifyCount.indexOfKey(msgType);
248 if (i < 0) {
249 mNotifyCount.add(msgType, 1);
250 } else {
251 ++mNotifyCount.editValueAt(i);
252 }
253 mCond.signal();
254}
255
256void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700257 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800258 int dataSize = data->size();
259 INFO("data type = %d, size = %d", msgType, dataSize);
260 Mutex::Autolock _l(mLock);
261 ssize_t i = mDataCount.indexOfKey(msgType);
262 if (i < 0) {
263 mDataCount.add(msgType, 1);
264 mDataSize.add(msgType, dataSize);
265 } else {
266 ++mDataCount.editValueAt(i);
267 mDataSize.editValueAt(i) = dataSize;
268 }
269 mCond.signal();
270
271 if (msgType == CAMERA_MSG_VIDEO_FRAME) {
272 ASSERT(mReleaser != NULL);
273 mReleaser->releaseRecordingFrame(data);
274 }
275}
276
Chih-Chung Change25cc652010-05-06 16:36:58 +0800277void MCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
278 const sp<IMemory>& data) {
279 dataCallback(msgType, data);
280}
281
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800282void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {
283 INFO("waitNotify: %d, %d, %d", msgType, op, count);
284 Mutex::Autolock _l(mLock);
285 while (true) {
286 int v = mNotifyCount.valueFor(msgType);
287 if (test(op, v, count)) {
288 break;
289 }
290 mCond.wait(mLock);
291 }
292}
293
294void MCameraClient::waitData(int32_t msgType, OP op, int count) {
295 INFO("waitData: %d, %d, %d", msgType, op, count);
296 Mutex::Autolock _l(mLock);
297 while (true) {
298 int v = mDataCount.valueFor(msgType);
299 if (test(op, v, count)) {
300 break;
301 }
302 mCond.wait(mLock);
303 }
304}
305
306//
307// A mock Surface
308//
309class MSurface : public BnSurface {
310public:
311 virtual status_t registerBuffers(const BufferHeap& buffers);
312 virtual void postBuffer(ssize_t offset);
313 virtual void unregisterBuffers();
314 virtual sp<OverlayRef> createOverlay(
Chih-Chung Change1ceec22010-01-21 17:31:06 -0800315 uint32_t w, uint32_t h, int32_t format, int32_t orientation);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800316 virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
Mathias Agopian75181b42010-05-12 18:37:43 -0700317 virtual status_t setBufferCount(int bufferCount);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800318
319 // new functions
320 void clearStat();
321 void waitUntil(int c0, int c1, int c2);
322
323private:
324 // check callback count
325 Condition mCond;
326 Mutex mLock;
327 int registerBuffersCount;
328 int postBufferCount;
329 int unregisterBuffersCount;
330};
331
332status_t MSurface::registerBuffers(const BufferHeap& buffers) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700333 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800334 Mutex::Autolock _l(mLock);
335 ++registerBuffersCount;
336 mCond.signal();
337 return NO_ERROR;
338}
339
340void MSurface::postBuffer(ssize_t offset) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700341 // INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800342 Mutex::Autolock _l(mLock);
343 ++postBufferCount;
344 mCond.signal();
345}
346
347void MSurface::unregisterBuffers() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700348 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800349 Mutex::Autolock _l(mLock);
350 ++unregisterBuffersCount;
351 mCond.signal();
352}
353
354sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700355 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800356 return NULL;
357}
358
Mathias Agopian75181b42010-05-12 18:37:43 -0700359status_t MSurface::setBufferCount(int bufferCount) {
Nick Kralevich942a2fb2010-05-14 10:29:13 -0700360 INFO("%s", __func__);
Mathias Agopian75181b42010-05-12 18:37:43 -0700361 return NULL;
362}
363
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800364void MSurface::clearStat() {
365 Mutex::Autolock _l(mLock);
366 registerBuffersCount = 0;
367 postBufferCount = 0;
368 unregisterBuffersCount = 0;
369}
370
371void MSurface::waitUntil(int c0, int c1, int c2) {
372 INFO("waitUntil: %d %d %d", c0, c1, c2);
373 Mutex::Autolock _l(mLock);
374 while (true) {
375 if (registerBuffersCount >= c0 &&
376 postBufferCount >= c1 &&
377 unregisterBuffersCount >= c2) {
378 break;
379 }
380 mCond.wait(mLock);
381 }
382}
383
Chih-Chung Change1ceec22010-01-21 17:31:06 -0800384sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
385 int32_t orientation) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800386 // Not implemented.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800387 ASSERT(0);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800388 return NULL;
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800389}
390
391//
392// Utilities to use the Holder service
393//
394sp<IHolder> getHolder() {
395 sp<IServiceManager> sm = defaultServiceManager();
396 ASSERT(sm != 0);
397 sp<IBinder> binder = sm->getService(String16("CameraServiceTest.Holder"));
398 ASSERT(binder != 0);
399 sp<IHolder> holder = interface_cast<IHolder>(binder);
400 ASSERT(holder != 0);
401 return holder;
402}
403
404void putTempObject(sp<IBinder> obj) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700405 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800406 getHolder()->put(obj);
407}
408
409sp<IBinder> getTempObject() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700410 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800411 return getHolder()->get();
412}
413
414void clearTempObject() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700415 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800416 getHolder()->clear();
417}
418
419//
420// Get a Camera Service
421//
422sp<ICameraService> getCameraService() {
423 sp<IServiceManager> sm = defaultServiceManager();
424 ASSERT(sm != 0);
425 sp<IBinder> binder = sm->getService(String16("media.camera"));
426 ASSERT(binder != 0);
427 sp<ICameraService> cs = interface_cast<ICameraService>(binder);
428 ASSERT(cs != 0);
429 return cs;
430}
431
Chih-Chung Change25cc652010-05-06 16:36:58 +0800432int getNumberOfCameras() {
433 sp<ICameraService> cs = getCameraService();
434 return cs->getNumberOfCameras();
435}
436
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800437//
438// Various Connect Tests
439//
Chih-Chung Change25cc652010-05-06 16:36:58 +0800440void testConnect(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700441 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800442 sp<ICameraService> cs = getCameraService();
443 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800444 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800445 ASSERT(c != 0);
446 c->disconnect();
447}
448
Chih-Chung Change25cc652010-05-06 16:36:58 +0800449void testAllowConnectOnceOnly(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700450 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800451 sp<ICameraService> cs = getCameraService();
452 // Connect the first client.
453 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800454 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800455 ASSERT(c != 0);
456 // Same client -- ok.
Chih-Chung Change25cc652010-05-06 16:36:58 +0800457 ASSERT(cs->connect(cc, cameraId) != 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800458 // Different client -- not ok.
459 sp<MCameraClient> cc2 = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800460 ASSERT(cs->connect(cc2, cameraId) == 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800461 c->disconnect();
462}
463
464void testReconnectFailed() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700465 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800466 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
Chih-Chung Change25cc652010-05-06 16:36:58 +0800467 sp<MCameraClient> cc = new MCameraClient();
468 ASSERT(c->connect(cc) != NO_ERROR);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800469}
470
471void testReconnectSuccess() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700472 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800473 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
474 sp<MCameraClient> cc = new MCameraClient();
475 ASSERT(c->connect(cc) == NO_ERROR);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800476 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800477}
478
479void testLockFailed() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700480 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800481 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
482 ASSERT(c->lock() != NO_ERROR);
483}
484
485void testLockUnlockSuccess() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700486 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800487 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
488 ASSERT(c->lock() == NO_ERROR);
489 ASSERT(c->unlock() == NO_ERROR);
490}
491
492void testLockSuccess() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700493 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800494 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
495 ASSERT(c->lock() == NO_ERROR);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800496 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800497}
498
499//
500// Run the connect tests in another process.
501//
502const char *gExecutable;
503
504struct FunctionTableEntry {
505 const char *name;
506 void (*func)();
507};
508
509FunctionTableEntry function_table[] = {
510#define ENTRY(x) {#x, &x}
511 ENTRY(testReconnectFailed),
512 ENTRY(testReconnectSuccess),
513 ENTRY(testLockUnlockSuccess),
514 ENTRY(testLockFailed),
515 ENTRY(testLockSuccess),
516#undef ENTRY
517};
518
519void runFunction(const char *tag) {
520 INFO("runFunction: %s", tag);
521 int entries = sizeof(function_table) / sizeof(function_table[0]);
522 for (int i = 0; i < entries; i++) {
523 if (strcmp(function_table[i].name, tag) == 0) {
524 (*function_table[i].func)();
525 return;
526 }
527 }
528 ASSERT(0);
529}
530
531void runInAnotherProcess(const char *tag) {
532 pid_t pid = fork();
533 if (pid == 0) {
534 execlp(gExecutable, gExecutable, tag, NULL);
535 ASSERT(0);
536 } else {
537 int status;
538 ASSERT_EQ(pid, wait(&status));
539 ASSERT_EQ(0, status);
540 }
541}
542
Chih-Chung Change25cc652010-05-06 16:36:58 +0800543void testReconnect(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700544 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800545 sp<ICameraService> cs = getCameraService();
546 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800547 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800548 ASSERT(c != 0);
549 // Reconnect to the same client -- ok.
550 ASSERT(c->connect(cc) == NO_ERROR);
551 // Reconnect to a different client (but the same pid) -- ok.
552 sp<MCameraClient> cc2 = new MCameraClient();
553 ASSERT(c->connect(cc2) == NO_ERROR);
554 c->disconnect();
555 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
556}
557
Chih-Chung Change25cc652010-05-06 16:36:58 +0800558void testLockUnlock(int cameraId) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800559 sp<ICameraService> cs = getCameraService();
560 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800561 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800562 ASSERT(c != 0);
563 // We can lock as many times as we want.
564 ASSERT(c->lock() == NO_ERROR);
565 ASSERT(c->lock() == NO_ERROR);
566 // Lock from a different process -- not ok.
567 putTempObject(c->asBinder());
568 runInAnotherProcess("testLockFailed");
569 // Unlock then lock from a different process -- ok.
570 ASSERT(c->unlock() == NO_ERROR);
571 runInAnotherProcess("testLockUnlockSuccess");
572 // Unlock then lock from a different process -- ok.
573 runInAnotherProcess("testLockSuccess");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800574 clearTempObject();
575}
576
Chih-Chung Change25cc652010-05-06 16:36:58 +0800577void testReconnectFromAnotherProcess(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700578 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800579
580 sp<ICameraService> cs = getCameraService();
581 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800582 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800583 ASSERT(c != 0);
584 // Reconnect from a different process -- not ok.
585 putTempObject(c->asBinder());
586 runInAnotherProcess("testReconnectFailed");
587 // Unlock then reconnect from a different process -- ok.
588 ASSERT(c->unlock() == NO_ERROR);
589 runInAnotherProcess("testReconnectSuccess");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800590 clearTempObject();
591}
592
593// We need to flush the command buffer after the reference
594// to ICamera is gone. The sleep is for the server to run
595// the destructor for it.
596static void flushCommands() {
597 IPCThreadState::self()->flushCommands();
598 usleep(200000); // 200ms
599}
600
601// Run a test case
Chih-Chung Change25cc652010-05-06 16:36:58 +0800602#define RUN(class_name, cameraId) do { \
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800603 { \
604 INFO(#class_name); \
605 class_name instance; \
Chih-Chung Change25cc652010-05-06 16:36:58 +0800606 instance.init(cameraId); \
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800607 instance.run(); \
608 } \
609 flushCommands(); \
610} while(0)
611
612// Base test case after the the camera is connected.
613class AfterConnect {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800614public:
615 void init(int cameraId) {
616 cs = getCameraService();
617 cc = new MCameraClient();
618 c = cs->connect(cc, cameraId);
619 ASSERT(c != 0);
620 }
621
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800622protected:
623 sp<ICameraService> cs;
624 sp<MCameraClient> cc;
625 sp<ICamera> c;
626
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800627 ~AfterConnect() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800628 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800629 c.clear();
630 cc.clear();
631 cs.clear();
632 }
633};
634
635class TestSetPreviewDisplay : public AfterConnect {
636public:
637 void run() {
638 sp<MSurface> surface = new MSurface();
639 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
640 c->disconnect();
641 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
642 }
643};
644
645class TestStartPreview : public AfterConnect {
646public:
647 void run() {
648 sp<MSurface> surface = new MSurface();
649 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
650
651 ASSERT(c->startPreview() == NO_ERROR);
652 ASSERT(c->previewEnabled() == true);
653
654 surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
655 surface->clearStat();
656
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800657 sp<MSurface> another_surface = new MSurface();
658 c->setPreviewDisplay(another_surface); // just to make sure unregisterBuffers
659 // is called.
660 surface->waitUntil(0, 0, 1); // needs unregisterBuffers
Chih-Chung Change25cc652010-05-06 16:36:58 +0800661
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800662 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
663 }
664};
665
Chih-Chung Change25cc652010-05-06 16:36:58 +0800666class TestStartPreviewWithoutDisplay : public AfterConnect {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800667public:
668 void run() {
669 ASSERT(c->startPreview() == NO_ERROR);
670 ASSERT(c->previewEnabled() == true);
671 c->disconnect();
672 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
673 }
674};
675
676// Base test case after the the camera is connected and the preview is started.
677class AfterStartPreview : public AfterConnect {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800678public:
679 void init(int cameraId) {
680 AfterConnect::init(cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800681 surface = new MSurface();
682 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
683 ASSERT(c->startPreview() == NO_ERROR);
684 }
685
Chih-Chung Change25cc652010-05-06 16:36:58 +0800686protected:
687 sp<MSurface> surface;
688
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800689 ~AfterStartPreview() {
690 surface.clear();
691 }
692};
693
694class TestAutoFocus : public AfterStartPreview {
695public:
696 void run() {
697 cc->assertNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 0);
698 c->autoFocus();
699 cc->waitNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 1);
700 c->disconnect();
701 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
702 }
703};
704
705class TestStopPreview : public AfterStartPreview {
706public:
707 void run() {
708 ASSERT(c->previewEnabled() == true);
709 c->stopPreview();
710 ASSERT(c->previewEnabled() == false);
711 c->disconnect();
712 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
713 }
714};
715
716class TestTakePicture: public AfterStartPreview {
717public:
718 void run() {
719 ASSERT(c->takePicture() == NO_ERROR);
720 cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
721 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
722 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
723 c->stopPreview();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800724 c->disconnect();
725 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
726 }
727};
728
729class TestTakeMultiplePictures: public AfterStartPreview {
730public:
731 void run() {
732 for (int i = 0; i < 10; i++) {
733 cc->clearStat();
734 ASSERT(c->takePicture() == NO_ERROR);
735 cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
736 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
737 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800738 }
739 c->disconnect();
740 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
741 }
742};
743
744class TestGetParameters: public AfterStartPreview {
745public:
746 void run() {
747 String8 param_str = c->getParameters();
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700748 INFO("%s", static_cast<const char*>(param_str));
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800749 }
750};
751
Chih-Chung Change25cc652010-05-06 16:36:58 +0800752static bool getNextSize(const char **ptrS, int *w, int *h) {
753 const char *s = *ptrS;
754
755 // skip over ','
756 if (*s == ',') s++;
757
758 // remember start position in p
759 const char *p = s;
760 while (*s != '\0' && *s != 'x') {
761 s++;
762 }
763 if (*s == '\0') return false;
764
765 // get the width
766 *w = atoi(p);
767
768 // skip over 'x'
769 ASSERT(*s == 'x');
770 p = s + 1;
771 while (*s != '\0' && *s != ',') {
772 s++;
773 }
774
775 // get the height
776 *h = atoi(p);
777 *ptrS = s;
778 return true;
779}
780
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800781class TestPictureSize : public AfterStartPreview {
782public:
783 void checkOnePicture(int w, int h) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800784 const float rate = 0.9; // byte per pixel limit
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800785 int pixels = w * h;
786
787 CameraParameters param(c->getParameters());
788 param.setPictureSize(w, h);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800789 // disable thumbnail to get more accurate size.
790 param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0);
791 param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800792 c->setParameters(param.flatten());
793
794 cc->clearStat();
795 ASSERT(c->takePicture() == NO_ERROR);
796 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800797 //cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800798 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
799 cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
800 int(pixels * rate));
801 cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
802 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800803 }
804
805 void run() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800806 CameraParameters param(c->getParameters());
807 int w, h;
808 const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
809 while (getNextSize(&s, &w, &h)) {
810 LOGD("checking picture size %dx%d", w, h);
811 checkOnePicture(w, h);
812 }
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800813 }
814};
815
816class TestPreviewCallbackFlag : public AfterConnect {
817public:
818 void run() {
819 sp<MSurface> surface = new MSurface();
820 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
821
822 // Try all flag combinations.
823 for (int v = 0; v < 8; v++) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800824 LOGD("TestPreviewCallbackFlag: flag=%d", v);
825 usleep(100000); // sleep a while to clear the in-flight callbacks.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800826 cc->clearStat();
827 c->setPreviewCallbackFlag(v);
828 ASSERT(c->previewEnabled() == false);
829 ASSERT(c->startPreview() == NO_ERROR);
830 ASSERT(c->previewEnabled() == true);
831 sleep(2);
832 c->stopPreview();
Iliyan Malchev9c7ac0d2011-04-14 16:51:21 -0700833 if ((v & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800834 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
835 } else {
Iliyan Malchev9c7ac0d2011-04-14 16:51:21 -0700836 if ((v & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800837 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
838 } else {
839 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
840 }
841 }
842 }
843 }
844};
845
846class TestRecording : public AfterConnect {
847public:
848 void run() {
849 ASSERT(c->recordingEnabled() == false);
850 sp<MSurface> surface = new MSurface();
851 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
Iliyan Malchev9c7ac0d2011-04-14 16:51:21 -0700852 c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800853 cc->setReleaser(c.get());
854 c->startRecording();
855 ASSERT(c->recordingEnabled() == true);
856 sleep(2);
857 c->stopRecording();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800858 usleep(100000); // sleep a while to clear the in-flight callbacks.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800859 cc->setReleaser(NULL);
860 cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
861 }
862};
863
864class TestPreviewSize : public AfterStartPreview {
865public:
866 void checkOnePicture(int w, int h) {
867 int size = w*h*3/2; // should read from parameters
868
869 c->stopPreview();
870
871 CameraParameters param(c->getParameters());
872 param.setPreviewSize(w, h);
Iliyan Malchev9c7ac0d2011-04-14 16:51:21 -0700873 c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800874 c->setParameters(param.flatten());
875
876 c->startPreview();
877
878 cc->clearStat();
879 cc->waitData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 1);
880 cc->assertDataSize(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, size);
881 }
882
883 void run() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800884 CameraParameters param(c->getParameters());
885 int w, h;
886 const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
887 while (getNextSize(&s, &w, &h)) {
888 LOGD("checking preview size %dx%d", w, h);
889 checkOnePicture(w, h);
890 }
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800891 }
892};
893
894void runHolderService() {
895 defaultServiceManager()->addService(
896 String16("CameraServiceTest.Holder"), new HolderService());
897 ProcessState::self()->startThreadPool();
898}
899
900int main(int argc, char **argv)
901{
902 if (argc != 1) {
903 runFunction(argv[1]);
904 return 0;
905 }
906 INFO("CameraServiceTest start");
907 gExecutable = argv[0];
908 runHolderService();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800909 int n = getNumberOfCameras();
910 INFO("%d Cameras available", n);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800911
Chih-Chung Change25cc652010-05-06 16:36:58 +0800912 for (int id = 0; id < n; id++) {
913 INFO("Testing camera %d", id);
914 testConnect(id); flushCommands();
915 testAllowConnectOnceOnly(id); flushCommands();
916 testReconnect(id); flushCommands();
917 testLockUnlock(id); flushCommands();
918 testReconnectFromAnotherProcess(id); flushCommands();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800919
Chih-Chung Change25cc652010-05-06 16:36:58 +0800920 RUN(TestSetPreviewDisplay, id);
921 RUN(TestStartPreview, id);
922 RUN(TestStartPreviewWithoutDisplay, id);
923 RUN(TestAutoFocus, id);
924 RUN(TestStopPreview, id);
925 RUN(TestTakePicture, id);
926 RUN(TestTakeMultiplePictures, id);
927 RUN(TestGetParameters, id);
928 RUN(TestPictureSize, id);
929 RUN(TestPreviewCallbackFlag, id);
930 RUN(TestRecording, id);
931 RUN(TestPreviewSize, id);
932 }
933
934 INFO("CameraServiceTest finished");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800935}