blob: 3c8d55397a95fd15ced044f4e720fa32bd0abb22 [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) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700229 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800230 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) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700241 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800242 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);
Mathias Agopian75181b42010-05-12 18:37:43 -0700301 virtual status_t setBufferCount(int bufferCount);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800302
303 // new functions
304 void clearStat();
305 void waitUntil(int c0, int c1, int c2);
306
307private:
308 // check callback count
309 Condition mCond;
310 Mutex mLock;
311 int registerBuffersCount;
312 int postBufferCount;
313 int unregisterBuffersCount;
314};
315
316status_t MSurface::registerBuffers(const BufferHeap& buffers) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700317 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800318 Mutex::Autolock _l(mLock);
319 ++registerBuffersCount;
320 mCond.signal();
321 return NO_ERROR;
322}
323
324void MSurface::postBuffer(ssize_t offset) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700325 // INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800326 Mutex::Autolock _l(mLock);
327 ++postBufferCount;
328 mCond.signal();
329}
330
331void MSurface::unregisterBuffers() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700332 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800333 Mutex::Autolock _l(mLock);
334 ++unregisterBuffersCount;
335 mCond.signal();
336}
337
338sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700339 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800340 return NULL;
341}
342
Mathias Agopian75181b42010-05-12 18:37:43 -0700343status_t MSurface::setBufferCount(int bufferCount) {
Nick Kralevich942a2fb2010-05-14 10:29:13 -0700344 INFO("%s", __func__);
Mathias Agopian75181b42010-05-12 18:37:43 -0700345 return NULL;
346}
347
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800348void MSurface::clearStat() {
349 Mutex::Autolock _l(mLock);
350 registerBuffersCount = 0;
351 postBufferCount = 0;
352 unregisterBuffersCount = 0;
353}
354
355void MSurface::waitUntil(int c0, int c1, int c2) {
356 INFO("waitUntil: %d %d %d", c0, c1, c2);
357 Mutex::Autolock _l(mLock);
358 while (true) {
359 if (registerBuffersCount >= c0 &&
360 postBufferCount >= c1 &&
361 unregisterBuffersCount >= c2) {
362 break;
363 }
364 mCond.wait(mLock);
365 }
366}
367
Chih-Chung Change1ceec22010-01-21 17:31:06 -0800368sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
369 int32_t orientation) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800370 // Not implemented.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800371 ASSERT(0);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800372 return NULL;
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800373}
374
375//
376// Utilities to use the Holder service
377//
378sp<IHolder> getHolder() {
379 sp<IServiceManager> sm = defaultServiceManager();
380 ASSERT(sm != 0);
381 sp<IBinder> binder = sm->getService(String16("CameraServiceTest.Holder"));
382 ASSERT(binder != 0);
383 sp<IHolder> holder = interface_cast<IHolder>(binder);
384 ASSERT(holder != 0);
385 return holder;
386}
387
388void putTempObject(sp<IBinder> obj) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700389 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800390 getHolder()->put(obj);
391}
392
393sp<IBinder> getTempObject() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700394 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800395 return getHolder()->get();
396}
397
398void clearTempObject() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700399 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800400 getHolder()->clear();
401}
402
403//
404// Get a Camera Service
405//
406sp<ICameraService> getCameraService() {
407 sp<IServiceManager> sm = defaultServiceManager();
408 ASSERT(sm != 0);
409 sp<IBinder> binder = sm->getService(String16("media.camera"));
410 ASSERT(binder != 0);
411 sp<ICameraService> cs = interface_cast<ICameraService>(binder);
412 ASSERT(cs != 0);
413 return cs;
414}
415
Chih-Chung Change25cc652010-05-06 16:36:58 +0800416int getNumberOfCameras() {
417 sp<ICameraService> cs = getCameraService();
418 return cs->getNumberOfCameras();
419}
420
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800421//
422// Various Connect Tests
423//
Chih-Chung Change25cc652010-05-06 16:36:58 +0800424void testConnect(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700425 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800426 sp<ICameraService> cs = getCameraService();
427 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800428 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800429 ASSERT(c != 0);
430 c->disconnect();
431}
432
Chih-Chung Change25cc652010-05-06 16:36:58 +0800433void testAllowConnectOnceOnly(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700434 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800435 sp<ICameraService> cs = getCameraService();
436 // Connect the first client.
437 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800438 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800439 ASSERT(c != 0);
440 // Same client -- ok.
Chih-Chung Change25cc652010-05-06 16:36:58 +0800441 ASSERT(cs->connect(cc, cameraId) != 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800442 // Different client -- not ok.
443 sp<MCameraClient> cc2 = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800444 ASSERT(cs->connect(cc2, cameraId) == 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800445 c->disconnect();
446}
447
448void testReconnectFailed() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700449 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800450 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
Chih-Chung Change25cc652010-05-06 16:36:58 +0800451 sp<MCameraClient> cc = new MCameraClient();
452 ASSERT(c->connect(cc) != NO_ERROR);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800453}
454
455void testReconnectSuccess() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700456 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800457 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
458 sp<MCameraClient> cc = new MCameraClient();
459 ASSERT(c->connect(cc) == NO_ERROR);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800460 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800461}
462
463void testLockFailed() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700464 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800465 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
466 ASSERT(c->lock() != NO_ERROR);
467}
468
469void testLockUnlockSuccess() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700470 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800471 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
472 ASSERT(c->lock() == NO_ERROR);
473 ASSERT(c->unlock() == NO_ERROR);
474}
475
476void testLockSuccess() {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700477 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800478 sp<ICamera> c = interface_cast<ICamera>(getTempObject());
479 ASSERT(c->lock() == NO_ERROR);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800480 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800481}
482
483//
484// Run the connect tests in another process.
485//
486const char *gExecutable;
487
488struct FunctionTableEntry {
489 const char *name;
490 void (*func)();
491};
492
493FunctionTableEntry function_table[] = {
494#define ENTRY(x) {#x, &x}
495 ENTRY(testReconnectFailed),
496 ENTRY(testReconnectSuccess),
497 ENTRY(testLockUnlockSuccess),
498 ENTRY(testLockFailed),
499 ENTRY(testLockSuccess),
500#undef ENTRY
501};
502
503void runFunction(const char *tag) {
504 INFO("runFunction: %s", tag);
505 int entries = sizeof(function_table) / sizeof(function_table[0]);
506 for (int i = 0; i < entries; i++) {
507 if (strcmp(function_table[i].name, tag) == 0) {
508 (*function_table[i].func)();
509 return;
510 }
511 }
512 ASSERT(0);
513}
514
515void runInAnotherProcess(const char *tag) {
516 pid_t pid = fork();
517 if (pid == 0) {
518 execlp(gExecutable, gExecutable, tag, NULL);
519 ASSERT(0);
520 } else {
521 int status;
522 ASSERT_EQ(pid, wait(&status));
523 ASSERT_EQ(0, status);
524 }
525}
526
Chih-Chung Change25cc652010-05-06 16:36:58 +0800527void testReconnect(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700528 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800529 sp<ICameraService> cs = getCameraService();
530 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800531 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800532 ASSERT(c != 0);
533 // Reconnect to the same client -- ok.
534 ASSERT(c->connect(cc) == NO_ERROR);
535 // Reconnect to a different client (but the same pid) -- ok.
536 sp<MCameraClient> cc2 = new MCameraClient();
537 ASSERT(c->connect(cc2) == NO_ERROR);
538 c->disconnect();
539 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
540}
541
Chih-Chung Change25cc652010-05-06 16:36:58 +0800542void testLockUnlock(int cameraId) {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800543 sp<ICameraService> cs = getCameraService();
544 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800545 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800546 ASSERT(c != 0);
547 // We can lock as many times as we want.
548 ASSERT(c->lock() == NO_ERROR);
549 ASSERT(c->lock() == NO_ERROR);
550 // Lock from a different process -- not ok.
551 putTempObject(c->asBinder());
552 runInAnotherProcess("testLockFailed");
553 // Unlock then lock from a different process -- ok.
554 ASSERT(c->unlock() == NO_ERROR);
555 runInAnotherProcess("testLockUnlockSuccess");
556 // Unlock then lock from a different process -- ok.
557 runInAnotherProcess("testLockSuccess");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800558 clearTempObject();
559}
560
Chih-Chung Change25cc652010-05-06 16:36:58 +0800561void testReconnectFromAnotherProcess(int cameraId) {
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700562 INFO("%s", __func__);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800563
564 sp<ICameraService> cs = getCameraService();
565 sp<MCameraClient> cc = new MCameraClient();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800566 sp<ICamera> c = cs->connect(cc, cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800567 ASSERT(c != 0);
568 // Reconnect from a different process -- not ok.
569 putTempObject(c->asBinder());
570 runInAnotherProcess("testReconnectFailed");
571 // Unlock then reconnect from a different process -- ok.
572 ASSERT(c->unlock() == NO_ERROR);
573 runInAnotherProcess("testReconnectSuccess");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800574 clearTempObject();
575}
576
577// We need to flush the command buffer after the reference
578// to ICamera is gone. The sleep is for the server to run
579// the destructor for it.
580static void flushCommands() {
581 IPCThreadState::self()->flushCommands();
582 usleep(200000); // 200ms
583}
584
585// Run a test case
Chih-Chung Change25cc652010-05-06 16:36:58 +0800586#define RUN(class_name, cameraId) do { \
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800587 { \
588 INFO(#class_name); \
589 class_name instance; \
Chih-Chung Change25cc652010-05-06 16:36:58 +0800590 instance.init(cameraId); \
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800591 instance.run(); \
592 } \
593 flushCommands(); \
594} while(0)
595
596// Base test case after the the camera is connected.
597class AfterConnect {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800598public:
599 void init(int cameraId) {
600 cs = getCameraService();
601 cc = new MCameraClient();
602 c = cs->connect(cc, cameraId);
603 ASSERT(c != 0);
604 }
605
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800606protected:
607 sp<ICameraService> cs;
608 sp<MCameraClient> cc;
609 sp<ICamera> c;
610
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800611 ~AfterConnect() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800612 c->disconnect();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800613 c.clear();
614 cc.clear();
615 cs.clear();
616 }
617};
618
619class TestSetPreviewDisplay : public AfterConnect {
620public:
621 void run() {
622 sp<MSurface> surface = new MSurface();
623 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
624 c->disconnect();
625 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
626 }
627};
628
629class TestStartPreview : public AfterConnect {
630public:
631 void run() {
632 sp<MSurface> surface = new MSurface();
633 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
634
635 ASSERT(c->startPreview() == NO_ERROR);
636 ASSERT(c->previewEnabled() == true);
637
638 surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
639 surface->clearStat();
640
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800641 sp<MSurface> another_surface = new MSurface();
642 c->setPreviewDisplay(another_surface); // just to make sure unregisterBuffers
643 // is called.
644 surface->waitUntil(0, 0, 1); // needs unregisterBuffers
Chih-Chung Change25cc652010-05-06 16:36:58 +0800645
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800646 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
647 }
648};
649
Chih-Chung Change25cc652010-05-06 16:36:58 +0800650class TestStartPreviewWithoutDisplay : public AfterConnect {
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800651public:
652 void run() {
653 ASSERT(c->startPreview() == NO_ERROR);
654 ASSERT(c->previewEnabled() == true);
655 c->disconnect();
656 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
657 }
658};
659
660// Base test case after the the camera is connected and the preview is started.
661class AfterStartPreview : public AfterConnect {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800662public:
663 void init(int cameraId) {
664 AfterConnect::init(cameraId);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800665 surface = new MSurface();
666 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
667 ASSERT(c->startPreview() == NO_ERROR);
668 }
669
Chih-Chung Change25cc652010-05-06 16:36:58 +0800670protected:
671 sp<MSurface> surface;
672
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800673 ~AfterStartPreview() {
674 surface.clear();
675 }
676};
677
678class TestAutoFocus : public AfterStartPreview {
679public:
680 void run() {
681 cc->assertNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 0);
682 c->autoFocus();
683 cc->waitNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 1);
684 c->disconnect();
685 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
686 }
687};
688
689class TestStopPreview : public AfterStartPreview {
690public:
691 void run() {
692 ASSERT(c->previewEnabled() == true);
693 c->stopPreview();
694 ASSERT(c->previewEnabled() == false);
695 c->disconnect();
696 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
697 }
698};
699
700class TestTakePicture: public AfterStartPreview {
701public:
702 void run() {
703 ASSERT(c->takePicture() == NO_ERROR);
704 cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
705 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
706 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
707 c->stopPreview();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800708 c->disconnect();
709 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
710 }
711};
712
713class TestTakeMultiplePictures: public AfterStartPreview {
714public:
715 void run() {
716 for (int i = 0; i < 10; i++) {
717 cc->clearStat();
718 ASSERT(c->takePicture() == NO_ERROR);
719 cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
720 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
721 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800722 }
723 c->disconnect();
724 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
725 }
726};
727
728class TestGetParameters: public AfterStartPreview {
729public:
730 void run() {
731 String8 param_str = c->getParameters();
Nick Kralevich1e4dc542010-05-13 15:09:03 -0700732 INFO("%s", static_cast<const char*>(param_str));
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800733 }
734};
735
Chih-Chung Change25cc652010-05-06 16:36:58 +0800736static bool getNextSize(const char **ptrS, int *w, int *h) {
737 const char *s = *ptrS;
738
739 // skip over ','
740 if (*s == ',') s++;
741
742 // remember start position in p
743 const char *p = s;
744 while (*s != '\0' && *s != 'x') {
745 s++;
746 }
747 if (*s == '\0') return false;
748
749 // get the width
750 *w = atoi(p);
751
752 // skip over 'x'
753 ASSERT(*s == 'x');
754 p = s + 1;
755 while (*s != '\0' && *s != ',') {
756 s++;
757 }
758
759 // get the height
760 *h = atoi(p);
761 *ptrS = s;
762 return true;
763}
764
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800765class TestPictureSize : public AfterStartPreview {
766public:
767 void checkOnePicture(int w, int h) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800768 const float rate = 0.9; // byte per pixel limit
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800769 int pixels = w * h;
770
771 CameraParameters param(c->getParameters());
772 param.setPictureSize(w, h);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800773 // disable thumbnail to get more accurate size.
774 param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0);
775 param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800776 c->setParameters(param.flatten());
777
778 cc->clearStat();
779 ASSERT(c->takePicture() == NO_ERROR);
780 cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800781 //cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800782 cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
783 cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
784 int(pixels * rate));
785 cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
786 cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800787 }
788
789 void run() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800790 CameraParameters param(c->getParameters());
791 int w, h;
792 const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
793 while (getNextSize(&s, &w, &h)) {
794 LOGD("checking picture size %dx%d", w, h);
795 checkOnePicture(w, h);
796 }
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800797 }
798};
799
800class TestPreviewCallbackFlag : public AfterConnect {
801public:
802 void run() {
803 sp<MSurface> surface = new MSurface();
804 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
805
806 // Try all flag combinations.
807 for (int v = 0; v < 8; v++) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800808 LOGD("TestPreviewCallbackFlag: flag=%d", v);
809 usleep(100000); // sleep a while to clear the in-flight callbacks.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800810 cc->clearStat();
811 c->setPreviewCallbackFlag(v);
812 ASSERT(c->previewEnabled() == false);
813 ASSERT(c->startPreview() == NO_ERROR);
814 ASSERT(c->previewEnabled() == true);
815 sleep(2);
816 c->stopPreview();
817 if ((v & FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
818 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
819 } else {
820 if ((v & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
821 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
822 } else {
823 cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
824 }
825 }
826 }
827 }
828};
829
830class TestRecording : public AfterConnect {
831public:
832 void run() {
833 ASSERT(c->recordingEnabled() == false);
834 sp<MSurface> surface = new MSurface();
835 ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
836 c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
837 cc->setReleaser(c.get());
838 c->startRecording();
839 ASSERT(c->recordingEnabled() == true);
840 sleep(2);
841 c->stopRecording();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800842 usleep(100000); // sleep a while to clear the in-flight callbacks.
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800843 cc->setReleaser(NULL);
844 cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
845 }
846};
847
848class TestPreviewSize : public AfterStartPreview {
849public:
850 void checkOnePicture(int w, int h) {
851 int size = w*h*3/2; // should read from parameters
852
853 c->stopPreview();
854
855 CameraParameters param(c->getParameters());
856 param.setPreviewSize(w, h);
857 c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
858 c->setParameters(param.flatten());
859
860 c->startPreview();
861
862 cc->clearStat();
863 cc->waitData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 1);
864 cc->assertDataSize(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, size);
865 }
866
867 void run() {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800868 CameraParameters param(c->getParameters());
869 int w, h;
870 const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
871 while (getNextSize(&s, &w, &h)) {
872 LOGD("checking preview size %dx%d", w, h);
873 checkOnePicture(w, h);
874 }
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800875 }
876};
877
878void runHolderService() {
879 defaultServiceManager()->addService(
880 String16("CameraServiceTest.Holder"), new HolderService());
881 ProcessState::self()->startThreadPool();
882}
883
884int main(int argc, char **argv)
885{
886 if (argc != 1) {
887 runFunction(argv[1]);
888 return 0;
889 }
890 INFO("CameraServiceTest start");
891 gExecutable = argv[0];
892 runHolderService();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800893 int n = getNumberOfCameras();
894 INFO("%d Cameras available", n);
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800895
Chih-Chung Change25cc652010-05-06 16:36:58 +0800896 for (int id = 0; id < n; id++) {
897 INFO("Testing camera %d", id);
898 testConnect(id); flushCommands();
899 testAllowConnectOnceOnly(id); flushCommands();
900 testReconnect(id); flushCommands();
901 testLockUnlock(id); flushCommands();
902 testReconnectFromAnotherProcess(id); flushCommands();
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800903
Chih-Chung Change25cc652010-05-06 16:36:58 +0800904 RUN(TestSetPreviewDisplay, id);
905 RUN(TestStartPreview, id);
906 RUN(TestStartPreviewWithoutDisplay, id);
907 RUN(TestAutoFocus, id);
908 RUN(TestStopPreview, id);
909 RUN(TestTakePicture, id);
910 RUN(TestTakeMultiplePictures, id);
911 RUN(TestGetParameters, id);
912 RUN(TestPictureSize, id);
913 RUN(TestPreviewCallbackFlag, id);
914 RUN(TestRecording, id);
915 RUN(TestPreviewSize, id);
916 }
917
918 INFO("CameraServiceTest finished");
Chih-Chung Chang5b0fc3d2009-11-13 12:49:14 +0800919}