blob: 41670af52a02e5d15b717e891cf6ce8cf211c748 [file] [log] [blame]
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +08001#define LOG_TAG "CameraServiceTest"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/wait.h>
8#include <unistd.h>
Mathias Agopian000479f2010-02-09 17:46:37 -08009#include <surfaceflinger/ISurface.h>
10#include <camera/Camera.h>
11#include <camera/CameraParameters.h>
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080012#include <ui/GraphicBuffer.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080013#include <camera/ICamera.h>
14#include <camera/ICameraClient.h>
15#include <camera/ICameraService.h>
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080016#include <ui/Overlay.h>
17#include <binder/IPCThreadState.h>
18#include <binder/IServiceManager.h>
19#include <binder/ProcessState.h>
20#include <utils/KeyedVector.h>
21#include <utils/Log.h>
22#include <utils/Vector.h>
23#include <utils/threads.h>
24
25using namespace android;
26
27//
28// Assertion and Logging utilities
29//
30#define INFO(...) \
31 do { \
32 printf(__VA_ARGS__); \
33 printf("\n"); \
34 LOGD(__VA_ARGS__); \
35 } while(0)
36
37void assert_fail(const char *file, int line, const char *func, const char *expr) {
38 INFO("assertion failed at file %s, line %d, function %s:",
39 file, line, func);
40 INFO("%s", expr);
Chih-Chung Change25cc652010-05-06 16:36:58 +080041 abort();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080042}
43
44void assert_eq_fail(const char *file, int line, const char *func,
45 const char *expr, int actual) {
46 INFO("assertion failed at file %s, line %d, function %s:",
47 file, line, func);
48 INFO("(expected) %s != (actual) %d", expr, actual);
Chih-Chung Change25cc652010-05-06 16:36:58 +080049 abort();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +080050}
51
52#define ASSERT(e) \
53 do { \
54 if (!(e)) \
55 assert_fail(__FILE__, __LINE__, __func__, #e); \
56 } while(0)
57
58#define ASSERT_EQ(expected, actual) \
59 do { \
60 int _x = (actual); \
61 if (_x != (expected)) \
62 assert_eq_fail(__FILE__, __LINE__, __func__, #expected, _x); \
63 } while(0)
64
65//
66// Holder service for pass objects between processes.
67//
68class IHolder : public IInterface {
69protected:
70 enum {
71 HOLDER_PUT = IBinder::FIRST_CALL_TRANSACTION,
72 HOLDER_GET,
73 HOLDER_CLEAR
74 };
75public:
76 DECLARE_META_INTERFACE(Holder);
77
78 virtual void put(sp<IBinder> obj) = 0;
79 virtual sp<IBinder> get() = 0;
80 virtual void clear() = 0;
81};
82
83class BnHolder : public BnInterface<IHolder> {
84 virtual status_t onTransact(uint32_t code,
85 const Parcel& data,
86 Parcel* reply,
87 uint32_t flags = 0);
88};
89
90class BpHolder : public BpInterface<IHolder> {
91public:
92 BpHolder(const sp<IBinder>& impl)
93 : BpInterface<IHolder>(impl) {
94 }
95
96 virtual void put(sp<IBinder> obj) {
97 Parcel data, reply;
98 data.writeStrongBinder(obj);
99 remote()->transact(HOLDER_PUT, data, &reply, IBinder::FLAG_ONEWAY);
100 }
101
102 virtual sp<IBinder> get() {
103 Parcel data, reply;
104 remote()->transact(HOLDER_GET, data, &reply);
105 return reply.readStrongBinder();
106 }
107
108 virtual void clear() {
109 Parcel data, reply;
110 remote()->transact(HOLDER_CLEAR, data, &reply);
111 }
112};
113
114IMPLEMENT_META_INTERFACE(Holder, "CameraServiceTest.Holder");
115
116status_t BnHolder::onTransact(
117 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
118 switch(code) {
119 case HOLDER_PUT: {
120 put(data.readStrongBinder());
121 return NO_ERROR;
122 } break;
123 case HOLDER_GET: {
124 reply->writeStrongBinder(get());
125 return NO_ERROR;
126 } break;
127 case HOLDER_CLEAR: {
128 clear();
129 return NO_ERROR;
130 } break;
131 default:
132 return BBinder::onTransact(code, data, reply, flags);
133 }
134}
135
136class HolderService : public BnHolder {
137 virtual void put(sp<IBinder> obj) {
138 mObj = obj;
139 }
140 virtual sp<IBinder> get() {
141 return mObj;
142 }
143 virtual void clear() {
144 mObj.clear();
145 }
146private:
147 sp<IBinder> mObj;
148};
149
150//
151// A mock CameraClient
152//
153class MCameraClient : public BnCameraClient {
154public:
155 virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
156 virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
157 virtual void dataCallbackTimestamp(nsecs_t timestamp,
Chih-Chung Change25cc652010-05-06 16:36:58 +0800158 int32_t msgType, const sp<IMemory>& data);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800159
160 // new functions
161 void clearStat();
162 enum OP { EQ, GE, LE, GT, LT };
163 void assertNotify(int32_t msgType, OP op, int count);
164 void assertData(int32_t msgType, OP op, int count);
165 void waitNotify(int32_t msgType, OP op, int count);
166 void waitData(int32_t msgType, OP op, int count);
167 void assertDataSize(int32_t msgType, OP op, int dataSize);
168
169 void setReleaser(ICamera *releaser) {
170 mReleaser = releaser;
171 }
172private:
173 Mutex mLock;
174 Condition mCond;
175 DefaultKeyedVector<int32_t, int> mNotifyCount;
176 DefaultKeyedVector<int32_t, int> mDataCount;
177 DefaultKeyedVector<int32_t, int> mDataSize;
178 bool test(OP op, int v1, int v2);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800179 void assertTest(OP op, int v1, int v2);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800180
181 ICamera *mReleaser;
182};
183
184void MCameraClient::clearStat() {
185 Mutex::Autolock _l(mLock);
186 mNotifyCount.clear();
187 mDataCount.clear();
188 mDataSize.clear();
189}
190
191bool MCameraClient::test(OP op, int v1, int v2) {
192 switch (op) {
193 case EQ: return v1 == v2;
194 case GT: return v1 > v2;
195 case LT: return v1 < v2;
196 case GE: return v1 >= v2;
197 case LE: return v1 <= v2;
198 default: ASSERT(0); break;
199 }
200 return false;
201}
202
Chih-Chung Change25cc652010-05-06 16:36:58 +0800203void MCameraClient::assertTest(OP op, int v1, int v2) {
204 if (!test(op, v1, v2)) {
205 LOGE("assertTest failed: op=%d, v1=%d, v2=%d", op, v1, v2);
206 ASSERT(0);
207 }
208}
209
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800210void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
211 Mutex::Autolock _l(mLock);
212 int v = mNotifyCount.valueFor(msgType);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800213 assertTest(op, v, count);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800214}
215
216void MCameraClient::assertData(int32_t msgType, OP op, int count) {
217 Mutex::Autolock _l(mLock);
218 int v = mDataCount.valueFor(msgType);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800219 assertTest(op, v, count);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800220}
221
222void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
223 Mutex::Autolock _l(mLock);
224 int v = mDataSize.valueFor(msgType);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800225 assertTest(op, v, dataSize);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800226}
227
228void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
229 INFO(__func__);
230 Mutex::Autolock _l(mLock);
231 ssize_t i = mNotifyCount.indexOfKey(msgType);
232 if (i < 0) {
233 mNotifyCount.add(msgType, 1);
234 } else {
235 ++mNotifyCount.editValueAt(i);
236 }
237 mCond.signal();
238}
239
240void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
241 INFO(__func__);
242 int dataSize = data->size();
243 INFO("data type = %d, size = %d", msgType, dataSize);
244 Mutex::Autolock _l(mLock);
245 ssize_t i = mDataCount.indexOfKey(msgType);
246 if (i < 0) {
247 mDataCount.add(msgType, 1);
248 mDataSize.add(msgType, dataSize);
249 } else {
250 ++mDataCount.editValueAt(i);
251 mDataSize.editValueAt(i) = dataSize;
252 }
253 mCond.signal();
254
255 if (msgType == CAMERA_MSG_VIDEO_FRAME) {
256 ASSERT(mReleaser != NULL);
257 mReleaser->releaseRecordingFrame(data);
258 }
259}
260
Chih-Chung Change25cc652010-05-06 16:36:58 +0800261void MCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
262 const sp<IMemory>& data) {
263 dataCallback(msgType, data);
264}
265
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800266void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {
267 INFO("waitNotify: %d, %d, %d", msgType, op, count);
268 Mutex::Autolock _l(mLock);
269 while (true) {
270 int v = mNotifyCount.valueFor(msgType);
271 if (test(op, v, count)) {
272 break;
273 }
274 mCond.wait(mLock);
275 }
276}
277
278void MCameraClient::waitData(int32_t msgType, OP op, int count) {
279 INFO("waitData: %d, %d, %d", msgType, op, count);
280 Mutex::Autolock _l(mLock);
281 while (true) {
282 int v = mDataCount.valueFor(msgType);
283 if (test(op, v, count)) {
284 break;
285 }
286 mCond.wait(mLock);
287 }
288}
289
290//
291// A mock Surface
292//
293class MSurface : public BnSurface {
294public:
295 virtual status_t registerBuffers(const BufferHeap& buffers);
296 virtual void postBuffer(ssize_t offset);
297 virtual void unregisterBuffers();
298 virtual sp<OverlayRef> createOverlay(
Chih-Chung Change1ceec22010-01-21 17:31:06 -0800299 uint32_t w, uint32_t h, int32_t format, int32_t orientation);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800300 virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
301
302 // new functions
303 void clearStat();
304 void waitUntil(int c0, int c1, int c2);
305
306private:
307 // check callback count
308 Condition mCond;
309 Mutex mLock;
310 int registerBuffersCount;
311 int postBufferCount;
312 int unregisterBuffersCount;
313};
314
315status_t MSurface::registerBuffers(const BufferHeap& buffers) {
316 INFO(__func__);
317 Mutex::Autolock _l(mLock);
318 ++registerBuffersCount;
319 mCond.signal();
320 return NO_ERROR;
321}
322
323void MSurface::postBuffer(ssize_t offset) {
324 // INFO(__func__);
325 Mutex::Autolock _l(mLock);
326 ++postBufferCount;
327 mCond.signal();
328}
329
330void MSurface::unregisterBuffers() {
331 INFO(__func__);
332 Mutex::Autolock _l(mLock);
333 ++unregisterBuffersCount;
334 mCond.signal();
335}
336
337sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) {
338 INFO(__func__);
339 return NULL;
340}
341
342void MSurface::clearStat() {
343 Mutex::Autolock _l(mLock);
344 registerBuffersCount = 0;
345 postBufferCount = 0;
346 unregisterBuffersCount = 0;
347}
348
349void MSurface::waitUntil(int c0, int c1, int c2) {
350 INFO("waitUntil: %d %d %d", c0, c1, c2);
351 Mutex::Autolock _l(mLock);
352 while (true) {
353 if (registerBuffersCount >= c0 &&
354 postBufferCount >= c1 &&
355 unregisterBuffersCount >= c2) {
356 break;
357 }
358 mCond.wait(mLock);
359 }
360}
361
Chih-Chung Change1ceec22010-01-21 17:31:06 -0800362sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
363 int32_t orientation) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800364 // Not implemented.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800365 ASSERT(0);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800366 return NULL;
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800367}
368
369//
370// Utilities to use the Holder service
371//
372sp<IHolder> getHolder() {
373 sp<IServiceManager> sm = defaultServiceManager();
374 ASSERT(sm != 0);
375 sp<IBinder> binder = sm->getService(String16("CameraServiceTest.Holder"));
376 ASSERT(binder != 0);
377 sp<IHolder> holder = interface_cast<IHolder>(binder);
378 ASSERT(holder != 0);
379 return holder;
380}
381
382void putTempObject(sp<IBinder> obj) {
383 INFO(__func__);
384 getHolder()->put(obj);
385}
386
387sp<IBinder> getTempObject() {
388 INFO(__func__);
389 return getHolder()->get();
390}
391
392void clearTempObject() {
393 INFO(__func__);
394 getHolder()->clear();
395}
396
397//
398// Get a Camera Service
399//
400sp<ICameraService> getCameraService() {
401 sp<IServiceManager> sm = defaultServiceManager();
402 ASSERT(sm != 0);
403 sp<IBinder> binder = sm->getService(String16("media.camera"));
404 ASSERT(binder != 0);
405 sp<ICameraService> cs = interface_cast<ICameraService>(binder);
406 ASSERT(cs != 0);
407 return cs;
408}
409
Chih-Chung Change25cc652010-05-06 16:36:58 +0800410int getNumberOfCameras() {
411 sp<ICameraService> cs = getCameraService();
412 return cs->getNumberOfCameras();
413}
414
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800415//
416// Various Connect Tests
417//
Chih-Chung Change25cc652010-05-06 16:36:58 +0800418void testConnect(int cameraId) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800419 INFO(__func__);
420 sp<ICameraService> cs = getCameraService();
421 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800422 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800423 ASSERT(c != 0);
424 c->disconnect();
425}
426
Chih-Chung Change25cc652010-05-06 16:36:58 +0800427void testAllowConnectOnceOnly(int cameraId) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800428 INFO(__func__);
429 sp<ICameraService> cs = getCameraService();
430 // Connect the first client.
431 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800432 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800433 ASSERT(c != 0);
434 // Same client -- ok.
Chih-Chung Change25cc652010-05-06 16:36:58 +0800435 ASSERT(cs->connect(cc, cameraId) != 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800436 // Different client -- not ok.
437 sp<MCameraClient> cc2 = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800438 ASSERT(cs->connect(cc2, cameraId) == 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800439 c->disconnect();
440}
441
442void testReconnectFailed() {
443 INFO(__func__);
444 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
Chih-Chung Change25cc652010-05-06 16:36:58 +0800445 sp<MCameraClient> cc = new MCameraClient();
446 ASSERT(c->connect(cc) != NO_ERROR);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800447}
448
449void testReconnectSuccess() {
450 INFO(__func__);
451 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
452 sp<MCameraClient> cc = new MCameraClient();
453 ASSERT(c->connect(cc) == NO_ERROR);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800454 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800455}
456
457void testLockFailed() {
458 INFO(__func__);
459 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
460 ASSERT(c->lock() != NO_ERROR);
461}
462
463void testLockUnlockSuccess() {
464 INFO(__func__);
465 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
466 ASSERT(c->lock() == NO_ERROR);
467 ASSERT(c->unlock() == NO_ERROR);
468}
469
470void testLockSuccess() {
471 INFO(__func__);
472 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
473 ASSERT(c->lock() == NO_ERROR);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800474 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800475}
476
477//
478// Run the connect tests in another process.
479//
480const char *gExecutable;
481
482struct FunctionTableEntry {
483 const char *name;
484 void (*func)();
485};
486
487FunctionTableEntry function_table[] = {
488#define ENTRY(x) {#x, &x}
489 ENTRY(testReconnectFailed),
490 ENTRY(testReconnectSuccess),
491 ENTRY(testLockUnlockSuccess),
492 ENTRY(testLockFailed),
493 ENTRY(testLockSuccess),
494#undef ENTRY
495};
496
497void runFunction(const char *tag) {
498 INFO("runFunction: %s", tag);
499 int entries = sizeof(function_table) / sizeof(function_table[0]);
500 for (int i = 0; i < entries; i++) {
501 if (strcmp(function_table[i].name, tag) == 0) {
502 (*function_table[i].func)();
503 return;
504 }
505 }
506 ASSERT(0);
507}
508
509void runInAnotherProcess(const char *tag) {
510 pid_t pid = fork();
511 if (pid == 0) {
512 execlp(gExecutable, gExecutable, tag, NULL);
513 ASSERT(0);
514 } else {
515 int status;
516 ASSERT_EQ(pid, wait(&status));
517 ASSERT_EQ(0, status);
518 }
519}
520
Chih-Chung Change25cc652010-05-06 16:36:58 +0800521void testReconnect(int cameraId) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800522 INFO(__func__);
523 sp<ICameraService> cs = getCameraService();
524 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800525 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800526 ASSERT(c != 0);
527 // Reconnect to the same client -- ok.
528 ASSERT(c->connect(cc) == NO_ERROR);
529 // Reconnect to a different client (but the same pid) -- ok.
530 sp<MCameraClient> cc2 = new MCameraClient();
531 ASSERT(c->connect(cc2) == NO_ERROR);
532 c->disconnect();
533 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
534}
535
Chih-Chung Change25cc652010-05-06 16:36:58 +0800536void testLockUnlock(int cameraId) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800537 sp<ICameraService> cs = getCameraService();
538 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800539 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800540 ASSERT(c != 0);
541 // We can lock as many times as we want.
542 ASSERT(c->lock() == NO_ERROR);
543 ASSERT(c->lock() == NO_ERROR);
544 // Lock from a different process -- not ok.
545 putTempObject(c->asBinder());
546 runInAnotherProcess("testLockFailed");
547 // Unlock then lock from a different process -- ok.
548 ASSERT(c->unlock() == NO_ERROR);
549 runInAnotherProcess("testLockUnlockSuccess");
550 // Unlock then lock from a different process -- ok.
551 runInAnotherProcess("testLockSuccess");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800552 clearTempObject();
553}
554
Chih-Chung Change25cc652010-05-06 16:36:58 +0800555void testReconnectFromAnotherProcess(int cameraId) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800556 INFO(__func__);
557
558 sp<ICameraService> cs = getCameraService();
559 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800560 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800561 ASSERT(c != 0);
562 // Reconnect from a different process -- not ok.
563 putTempObject(c->asBinder());
564 runInAnotherProcess("testReconnectFailed");
565 // Unlock then reconnect from a different process -- ok.
566 ASSERT(c->unlock() == NO_ERROR);
567 runInAnotherProcess("testReconnectSuccess");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800568 clearTempObject();
569}
570
571// We need to flush the command buffer after the reference
572// to ICamera is gone. The sleep is for the server to run
573// the destructor for it.
574static void flushCommands() {
575 IPCThreadState::self()->flushCommands();
576 usleep(200000); // 200ms
577}
578
579// Run a test case
Chih-Chung Change25cc652010-05-06 16:36:58 +0800580#define RUN(class_name, cameraId) do { \
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800581 { \
582 INFO(#class_name); \
583 class_name instance; \
Chih-Chung Change25cc652010-05-06 16:36:58 +0800584 instance.init(cameraId); \
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800585 instance.run(); \
586 } \
587 flushCommands(); \
588} while(0)
589
590// Base test case after the the camera is connected.
591class AfterConnect {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800592public:
593 void init(int cameraId) {
594 cs = getCameraService();
595 cc = new MCameraClient();
596 c = cs->connect(cc, cameraId);
597 ASSERT(c != 0);
598 }
599
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800600protected:
601 sp<ICameraService> cs;
602 sp<MCameraClient> cc;
603 sp<ICamera> c;
604
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800605 ~AfterConnect() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800606 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800607 c.clear();
608 cc.clear();
609 cs.clear();
610 }
611};
612
613class TestSetPreviewDisplay : public AfterConnect {
614public:
615 void run() {
616 sp<MSurface> surface = new MSurface();
617 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
618 c->disconnect();
619 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
620 }
621};
622
623class TestStartPreview : public AfterConnect {
624public:
625 void run() {
626 sp<MSurface> surface = new MSurface();
627 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
628
629 ASSERT(c->startPreview() == NO_ERROR);
630 ASSERT(c->previewEnabled() == true);
631
632 surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
633 surface->clearStat();
634
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800635 sp<MSurface> another_surface = new MSurface();
636 c->setPreviewDisplay(another_surface); // just to make sure unregisterBuffers
637 // is called.
638 surface->waitUntil(0, 0, 1); // needs unregisterBuffers
Chih-Chung Change25cc652010-05-06 16:36:58 +0800639
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800640 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
641 }
642};
643
Chih-Chung Change25cc652010-05-06 16:36:58 +0800644class TestStartPreviewWithoutDisplay : public AfterConnect {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800645public:
646 void run() {
647 ASSERT(c->startPreview() == NO_ERROR);
648 ASSERT(c->previewEnabled() == true);
649 c->disconnect();
650 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
651 }
652};
653
654// Base test case after the the camera is connected and the preview is started.
655class AfterStartPreview : public AfterConnect {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800656public:
657 void init(int cameraId) {
658 AfterConnect::init(cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800659 surface = new MSurface();
660 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
661 ASSERT(c->startPreview() == NO_ERROR);
662 }
663
Chih-Chung Change25cc652010-05-06 16:36:58 +0800664protected:
665 sp<MSurface> surface;
666
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800667 ~AfterStartPreview() {
668 surface.clear();
669 }
670};
671
672class TestAutoFocus : public AfterStartPreview {
673public:
674 void run() {
675 cc->assertNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 0);
676 c->autoFocus();
677 cc->waitNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 1);
678 c->disconnect();
679 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
680 }
681};
682
683class TestStopPreview : public AfterStartPreview {
684public:
685 void run() {
686 ASSERT(c->previewEnabled() == true);
687 c->stopPreview();
688 ASSERT(c->previewEnabled() == false);
689 c->disconnect();
690 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
691 }
692};
693
694class TestTakePicture: public AfterStartPreview {
695public:
696 void run() {
697 ASSERT(c->takePicture() == NO_ERROR);
698 cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
699 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
700 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
701 c->stopPreview();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800702 c->disconnect();
703 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
704 }
705};
706
707class TestTakeMultiplePictures: public AfterStartPreview {
708public:
709 void run() {
710 for (int i = 0; i < 10; i++) {
711 cc->clearStat();
712 ASSERT(c->takePicture() == NO_ERROR);
713 cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
714 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
715 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800716 }
717 c->disconnect();
718 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
719 }
720};
721
722class TestGetParameters: public AfterStartPreview {
723public:
724 void run() {
725 String8 param_str = c->getParameters();
726 INFO(param_str);
727 }
728};
729
Chih-Chung Change25cc652010-05-06 16:36:58 +0800730static bool getNextSize(const char **ptrS, int *w, int *h) {
731 const char *s = *ptrS;
732
733 // skip over ','
734 if (*s == ',') s++;
735
736 // remember start position in p
737 const char *p = s;
738 while (*s != '\0' && *s != 'x') {
739 s++;
740 }
741 if (*s == '\0') return false;
742
743 // get the width
744 *w = atoi(p);
745
746 // skip over 'x'
747 ASSERT(*s == 'x');
748 p = s + 1;
749 while (*s != '\0' && *s != ',') {
750 s++;
751 }
752
753 // get the height
754 *h = atoi(p);
755 *ptrS = s;
756 return true;
757}
758
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800759class TestPictureSize : public AfterStartPreview {
760public:
761 void checkOnePicture(int w, int h) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800762 const float rate = 0.9; // byte per pixel limit
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800763 int pixels = w * h;
764
765 CameraParameters param(c->getParameters());
766 param.setPictureSize(w, h);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800767 // disable thumbnail to get more accurate size.
768 param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0);
769 param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800770 c->setParameters(param.flatten());
771
772 cc->clearStat();
773 ASSERT(c->takePicture() == NO_ERROR);
774 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800775 //cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800776 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
777 cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
778 int(pixels * rate));
779 cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
780 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800781 }
782
783 void run() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800784 CameraParameters param(c->getParameters());
785 int w, h;
786 const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
787 while (getNextSize(&s, &w, &h)) {
788 LOGD("checking picture size %dx%d", w, h);
789 checkOnePicture(w, h);
790 }
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800791 }
792};
793
794class TestPreviewCallbackFlag : public AfterConnect {
795public:
796 void run() {
797 sp<MSurface> surface = new MSurface();
798 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
799
800 // Try all flag combinations.
801 for (int v = 0; v < 8; v++) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800802 LOGD("TestPreviewCallbackFlag: flag=%d", v);
803 usleep(100000); // sleep a while to clear the in-flight callbacks.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800804 cc->clearStat();
805 c->setPreviewCallbackFlag(v);
806 ASSERT(c->previewEnabled() == false);
807 ASSERT(c->startPreview() == NO_ERROR);
808 ASSERT(c->previewEnabled() == true);
809 sleep(2);
810 c->stopPreview();
811 if ((v & FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
812 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
813 } else {
814 if ((v & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
815 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
816 } else {
817 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
818 }
819 }
820 }
821 }
822};
823
824class TestRecording : public AfterConnect {
825public:
826 void run() {
827 ASSERT(c->recordingEnabled() == false);
828 sp<MSurface> surface = new MSurface();
829 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
830 c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
831 cc->setReleaser(c.get());
832 c->startRecording();
833 ASSERT(c->recordingEnabled() == true);
834 sleep(2);
835 c->stopRecording();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800836 usleep(100000); // sleep a while to clear the in-flight callbacks.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800837 cc->setReleaser(NULL);
838 cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
839 }
840};
841
842class TestPreviewSize : public AfterStartPreview {
843public:
844 void checkOnePicture(int w, int h) {
845 int size = w*h*3/2; // should read from parameters
846
847 c->stopPreview();
848
849 CameraParameters param(c->getParameters());
850 param.setPreviewSize(w, h);
851 c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
852 c->setParameters(param.flatten());
853
854 c->startPreview();
855
856 cc->clearStat();
857 cc->waitData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 1);
858 cc->assertDataSize(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, size);
859 }
860
861 void run() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800862 CameraParameters param(c->getParameters());
863 int w, h;
864 const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
865 while (getNextSize(&s, &w, &h)) {
866 LOGD("checking preview size %dx%d", w, h);
867 checkOnePicture(w, h);
868 }
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800869 }
870};
871
872void runHolderService() {
873 defaultServiceManager()->addService(
874 String16("CameraServiceTest.Holder"), new HolderService());
875 ProcessState::self()->startThreadPool();
876}
877
878int main(int argc, char **argv)
879{
880 if (argc != 1) {
881 runFunction(argv[1]);
882 return 0;
883 }
884 INFO("CameraServiceTest start");
885 gExecutable = argv[0];
886 runHolderService();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800887 int n = getNumberOfCameras();
888 INFO("%d Cameras available", n);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800889
Chih-Chung Change25cc652010-05-06 16:36:58 +0800890 for (int id = 0; id < n; id++) {
891 INFO("Testing camera %d", id);
892 testConnect(id); flushCommands();
893 testAllowConnectOnceOnly(id); flushCommands();
894 testReconnect(id); flushCommands();
895 testLockUnlock(id); flushCommands();
896 testReconnectFromAnotherProcess(id); flushCommands();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800897
Chih-Chung Change25cc652010-05-06 16:36:58 +0800898 RUN(TestSetPreviewDisplay, id);
899 RUN(TestStartPreview, id);
900 RUN(TestStartPreviewWithoutDisplay, id);
901 RUN(TestAutoFocus, id);
902 RUN(TestStopPreview, id);
903 RUN(TestTakePicture, id);
904 RUN(TestTakeMultiplePictures, id);
905 RUN(TestGetParameters, id);
906 RUN(TestPictureSize, id);
907 RUN(TestPreviewCallbackFlag, id);
908 RUN(TestRecording, id);
909 RUN(TestPreviewSize, id);
910 }
911
912 INFO("CameraServiceTest finished");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800913}