move native services under services/

moved surfaceflinger, audioflinger, cameraservice

all native services should now reside in this location.

Change-Id: Iee42b83dd2a94c3bf5107ab0895fe2dfcd5337a8
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
new file mode 100644
index 0000000..3c8d553
--- /dev/null
+++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -0,0 +1,919 @@
+#define LOG_TAG "CameraServiceTest"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <surfaceflinger/ISurface.h>
+#include <camera/Camera.h>
+#include <camera/CameraParameters.h>
+#include <ui/GraphicBuffer.h>
+#include <camera/ICamera.h>
+#include <camera/ICameraClient.h>
+#include <camera/ICameraService.h>
+#include <ui/Overlay.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+using namespace android;
+
+//
+//  Assertion and Logging utilities
+//
+#define INFO(...) \
+    do { \
+        printf(__VA_ARGS__); \
+        printf("\n"); \
+        LOGD(__VA_ARGS__); \
+    } while(0)
+
+void assert_fail(const char *file, int line, const char *func, const char *expr) {
+    INFO("assertion failed at file %s, line %d, function %s:",
+            file, line, func);
+    INFO("%s", expr);
+    abort();
+}
+
+void assert_eq_fail(const char *file, int line, const char *func,
+        const char *expr, int actual) {
+    INFO("assertion failed at file %s, line %d, function %s:",
+            file, line, func);
+    INFO("(expected) %s != (actual) %d", expr, actual);
+    abort();
+}
+
+#define ASSERT(e) \
+    do { \
+        if (!(e)) \
+            assert_fail(__FILE__, __LINE__, __func__, #e); \
+    } while(0)
+
+#define ASSERT_EQ(expected, actual) \
+    do { \
+        int _x = (actual); \
+        if (_x != (expected)) \
+            assert_eq_fail(__FILE__, __LINE__, __func__, #expected, _x); \
+    } while(0)
+
+//
+//  Holder service for pass objects between processes.
+//
+class IHolder : public IInterface {
+protected:
+    enum {
+        HOLDER_PUT = IBinder::FIRST_CALL_TRANSACTION,
+        HOLDER_GET,
+        HOLDER_CLEAR
+    };
+public:
+    DECLARE_META_INTERFACE(Holder);
+
+    virtual void put(sp<IBinder> obj) = 0;
+    virtual sp<IBinder> get() = 0;
+    virtual void clear() = 0;
+};
+
+class BnHolder : public BnInterface<IHolder> {
+    virtual status_t onTransact(uint32_t code,
+                                const Parcel& data,
+                                Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+class BpHolder : public BpInterface<IHolder> {
+public:
+    BpHolder(const sp<IBinder>& impl)
+        : BpInterface<IHolder>(impl) {
+    }
+
+    virtual void put(sp<IBinder> obj) {
+        Parcel data, reply;
+        data.writeStrongBinder(obj);
+        remote()->transact(HOLDER_PUT, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual sp<IBinder> get() {
+        Parcel data, reply;
+        remote()->transact(HOLDER_GET, data, &reply);
+        return reply.readStrongBinder();
+    }
+
+    virtual void clear() {
+        Parcel data, reply;
+        remote()->transact(HOLDER_CLEAR, data, &reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(Holder, "CameraServiceTest.Holder");
+
+status_t BnHolder::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+        case HOLDER_PUT: {
+            put(data.readStrongBinder());
+            return NO_ERROR;
+        } break;
+        case HOLDER_GET: {
+            reply->writeStrongBinder(get());
+            return NO_ERROR;
+        } break;
+        case HOLDER_CLEAR: {
+            clear();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+class HolderService : public BnHolder {
+    virtual void put(sp<IBinder> obj) {
+        mObj = obj;
+    }
+    virtual sp<IBinder> get() {
+        return mObj;
+    }
+    virtual void clear() {
+        mObj.clear();
+    }
+private:
+    sp<IBinder> mObj;
+};
+
+//
+//  A mock CameraClient
+//
+class MCameraClient : public BnCameraClient {
+public:
+    virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
+    virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
+    virtual void dataCallbackTimestamp(nsecs_t timestamp,
+            int32_t msgType, const sp<IMemory>& data);
+
+    // new functions
+    void clearStat();
+    enum OP { EQ, GE, LE, GT, LT };
+    void assertNotify(int32_t msgType, OP op, int count);
+    void assertData(int32_t msgType, OP op, int count);
+    void waitNotify(int32_t msgType, OP op, int count);
+    void waitData(int32_t msgType, OP op, int count);
+    void assertDataSize(int32_t msgType, OP op, int dataSize);
+
+    void setReleaser(ICamera *releaser) {
+        mReleaser = releaser;
+    }
+private:
+    Mutex mLock;
+    Condition mCond;
+    DefaultKeyedVector<int32_t, int> mNotifyCount;
+    DefaultKeyedVector<int32_t, int> mDataCount;
+    DefaultKeyedVector<int32_t, int> mDataSize;
+    bool test(OP op, int v1, int v2);
+    void assertTest(OP op, int v1, int v2);
+
+    ICamera *mReleaser;
+};
+
+void MCameraClient::clearStat() {
+    Mutex::Autolock _l(mLock);
+    mNotifyCount.clear();
+    mDataCount.clear();
+    mDataSize.clear();
+}
+
+bool MCameraClient::test(OP op, int v1, int v2) {
+    switch (op) {
+        case EQ: return v1 == v2;
+        case GT: return v1 > v2;
+        case LT: return v1 < v2;
+        case GE: return v1 >= v2;
+        case LE: return v1 <= v2;
+        default: ASSERT(0); break;
+    }
+    return false;
+}
+
+void MCameraClient::assertTest(OP op, int v1, int v2) {
+    if (!test(op, v1, v2)) {
+        LOGE("assertTest failed: op=%d, v1=%d, v2=%d", op, v1, v2);
+        ASSERT(0);
+    }
+}
+
+void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
+    Mutex::Autolock _l(mLock);
+    int v = mNotifyCount.valueFor(msgType);
+    assertTest(op, v, count);
+}
+
+void MCameraClient::assertData(int32_t msgType, OP op, int count) {
+    Mutex::Autolock _l(mLock);
+    int v = mDataCount.valueFor(msgType);
+    assertTest(op, v, count);
+}
+
+void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
+    Mutex::Autolock _l(mLock);
+    int v = mDataSize.valueFor(msgType);
+    assertTest(op, v, dataSize);
+}
+
+void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
+    INFO("%s", __func__);
+    Mutex::Autolock _l(mLock);
+    ssize_t i = mNotifyCount.indexOfKey(msgType);
+    if (i < 0) {
+        mNotifyCount.add(msgType, 1);
+    } else {
+        ++mNotifyCount.editValueAt(i);
+    }
+    mCond.signal();
+}
+
+void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
+    INFO("%s", __func__);
+    int dataSize = data->size();
+    INFO("data type = %d, size = %d", msgType, dataSize);
+    Mutex::Autolock _l(mLock);
+    ssize_t i = mDataCount.indexOfKey(msgType);
+    if (i < 0) {
+        mDataCount.add(msgType, 1);
+        mDataSize.add(msgType, dataSize);
+    } else {
+        ++mDataCount.editValueAt(i);
+        mDataSize.editValueAt(i) = dataSize;
+    }
+    mCond.signal();
+
+    if (msgType == CAMERA_MSG_VIDEO_FRAME) {
+        ASSERT(mReleaser != NULL);
+        mReleaser->releaseRecordingFrame(data);
+    }
+}
+
+void MCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+        const sp<IMemory>& data) {
+    dataCallback(msgType, data);
+}
+
+void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {
+    INFO("waitNotify: %d, %d, %d", msgType, op, count);
+    Mutex::Autolock _l(mLock);
+    while (true) {
+        int v = mNotifyCount.valueFor(msgType);
+        if (test(op, v, count)) {
+            break;
+        }
+        mCond.wait(mLock);
+    }
+}
+
+void MCameraClient::waitData(int32_t msgType, OP op, int count) {
+    INFO("waitData: %d, %d, %d", msgType, op, count);
+    Mutex::Autolock _l(mLock);
+    while (true) {
+        int v = mDataCount.valueFor(msgType);
+        if (test(op, v, count)) {
+            break;
+        }
+        mCond.wait(mLock);
+    }
+}
+
+//
+//  A mock Surface
+//
+class MSurface : public BnSurface {
+public:
+    virtual status_t registerBuffers(const BufferHeap& buffers);
+    virtual void postBuffer(ssize_t offset);
+    virtual void unregisterBuffers();
+    virtual sp<OverlayRef> createOverlay(
+            uint32_t w, uint32_t h, int32_t format, int32_t orientation);
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
+    virtual status_t setBufferCount(int bufferCount);
+
+    // new functions
+    void clearStat();
+    void waitUntil(int c0, int c1, int c2);
+
+private:
+    // check callback count
+    Condition mCond;
+    Mutex mLock;
+    int registerBuffersCount;
+    int postBufferCount;
+    int unregisterBuffersCount;
+};
+
+status_t MSurface::registerBuffers(const BufferHeap& buffers) {
+    INFO("%s", __func__);
+    Mutex::Autolock _l(mLock);
+    ++registerBuffersCount;
+    mCond.signal();
+    return NO_ERROR;
+}
+
+void MSurface::postBuffer(ssize_t offset) {
+    // INFO("%s", __func__);
+    Mutex::Autolock _l(mLock);
+    ++postBufferCount;
+    mCond.signal();
+}
+
+void MSurface::unregisterBuffers() {
+    INFO("%s", __func__);
+    Mutex::Autolock _l(mLock);
+    ++unregisterBuffersCount;
+    mCond.signal();
+}
+
+sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) {
+    INFO("%s", __func__);
+    return NULL;
+}
+
+status_t MSurface::setBufferCount(int bufferCount) {
+    INFO("%s", __func__);
+    return NULL;
+}
+
+void MSurface::clearStat() {
+    Mutex::Autolock _l(mLock);
+    registerBuffersCount = 0;
+    postBufferCount = 0;
+    unregisterBuffersCount = 0;
+}
+
+void MSurface::waitUntil(int c0, int c1, int c2) {
+    INFO("waitUntil: %d %d %d", c0, c1, c2);
+    Mutex::Autolock _l(mLock);
+    while (true) {
+        if (registerBuffersCount >= c0 &&
+            postBufferCount >= c1 &&
+            unregisterBuffersCount >= c2) {
+            break;
+        }
+        mCond.wait(mLock);
+    }
+}
+
+sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
+        int32_t orientation) {
+    // Not implemented.
+    ASSERT(0);
+    return NULL;
+}
+
+//
+//  Utilities to use the Holder service
+//
+sp<IHolder> getHolder() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    ASSERT(sm != 0);
+    sp<IBinder> binder = sm->getService(String16("CameraServiceTest.Holder"));
+    ASSERT(binder != 0);
+    sp<IHolder> holder = interface_cast<IHolder>(binder);
+    ASSERT(holder != 0);
+    return holder;
+}
+
+void putTempObject(sp<IBinder> obj) {
+    INFO("%s", __func__);
+    getHolder()->put(obj);
+}
+
+sp<IBinder> getTempObject() {
+    INFO("%s", __func__);
+    return getHolder()->get();
+}
+
+void clearTempObject() {
+    INFO("%s", __func__);
+    getHolder()->clear();
+}
+
+//
+//  Get a Camera Service
+//
+sp<ICameraService> getCameraService() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    ASSERT(sm != 0);
+    sp<IBinder> binder = sm->getService(String16("media.camera"));
+    ASSERT(binder != 0);
+    sp<ICameraService> cs = interface_cast<ICameraService>(binder);
+    ASSERT(cs != 0);
+    return cs;
+}
+
+int getNumberOfCameras() {
+    sp<ICameraService> cs = getCameraService();
+    return cs->getNumberOfCameras();
+}
+
+//
+// Various Connect Tests
+//
+void testConnect(int cameraId) {
+    INFO("%s", __func__);
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc, cameraId);
+    ASSERT(c != 0);
+    c->disconnect();
+}
+
+void testAllowConnectOnceOnly(int cameraId) {
+    INFO("%s", __func__);
+    sp<ICameraService> cs = getCameraService();
+    // Connect the first client.
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc, cameraId);
+    ASSERT(c != 0);
+    // Same client -- ok.
+    ASSERT(cs->connect(cc, cameraId) != 0);
+    // Different client -- not ok.
+    sp<MCameraClient> cc2 = new MCameraClient();
+    ASSERT(cs->connect(cc2, cameraId) == 0);
+    c->disconnect();
+}
+
+void testReconnectFailed() {
+    INFO("%s", __func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    sp<MCameraClient> cc = new MCameraClient();
+    ASSERT(c->connect(cc) != NO_ERROR);
+}
+
+void testReconnectSuccess() {
+    INFO("%s", __func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    sp<MCameraClient> cc = new MCameraClient();
+    ASSERT(c->connect(cc) == NO_ERROR);
+    c->disconnect();
+}
+
+void testLockFailed() {
+    INFO("%s", __func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    ASSERT(c->lock() != NO_ERROR);
+}
+
+void testLockUnlockSuccess() {
+    INFO("%s", __func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    ASSERT(c->lock() == NO_ERROR);
+    ASSERT(c->unlock() == NO_ERROR);
+}
+
+void testLockSuccess() {
+    INFO("%s", __func__);
+    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
+    ASSERT(c->lock() == NO_ERROR);
+    c->disconnect();
+}
+
+//
+// Run the connect tests in another process.
+//
+const char *gExecutable;
+
+struct FunctionTableEntry {
+    const char *name;
+    void (*func)();
+};
+
+FunctionTableEntry function_table[] = {
+#define ENTRY(x) {#x, &x}
+    ENTRY(testReconnectFailed),
+    ENTRY(testReconnectSuccess),
+    ENTRY(testLockUnlockSuccess),
+    ENTRY(testLockFailed),
+    ENTRY(testLockSuccess),
+#undef ENTRY
+};
+
+void runFunction(const char *tag) {
+    INFO("runFunction: %s", tag);
+    int entries = sizeof(function_table) / sizeof(function_table[0]);
+    for (int i = 0; i < entries; i++) {
+        if (strcmp(function_table[i].name, tag) == 0) {
+            (*function_table[i].func)();
+            return;
+        }
+    }
+    ASSERT(0);
+}
+
+void runInAnotherProcess(const char *tag) {
+    pid_t pid = fork();
+    if (pid == 0) {
+        execlp(gExecutable, gExecutable, tag, NULL);
+        ASSERT(0);
+    } else {
+        int status;
+        ASSERT_EQ(pid, wait(&status));
+        ASSERT_EQ(0, status);
+    }
+}
+
+void testReconnect(int cameraId) {
+    INFO("%s", __func__);
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc, cameraId);
+    ASSERT(c != 0);
+    // Reconnect to the same client -- ok.
+    ASSERT(c->connect(cc) == NO_ERROR);
+    // Reconnect to a different client (but the same pid) -- ok.
+    sp<MCameraClient> cc2 = new MCameraClient();
+    ASSERT(c->connect(cc2) == NO_ERROR);
+    c->disconnect();
+    cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+}
+
+void testLockUnlock(int cameraId) {
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc, cameraId);
+    ASSERT(c != 0);
+    // We can lock as many times as we want.
+    ASSERT(c->lock() == NO_ERROR);
+    ASSERT(c->lock() == NO_ERROR);
+    // Lock from a different process -- not ok.
+    putTempObject(c->asBinder());
+    runInAnotherProcess("testLockFailed");
+    // Unlock then lock from a different process -- ok.
+    ASSERT(c->unlock() == NO_ERROR);
+    runInAnotherProcess("testLockUnlockSuccess");
+    // Unlock then lock from a different process -- ok.
+    runInAnotherProcess("testLockSuccess");
+    clearTempObject();
+}
+
+void testReconnectFromAnotherProcess(int cameraId) {
+    INFO("%s", __func__);
+
+    sp<ICameraService> cs = getCameraService();
+    sp<MCameraClient> cc = new MCameraClient();
+    sp<ICamera> c = cs->connect(cc, cameraId);
+    ASSERT(c != 0);
+    // Reconnect from a different process -- not ok.
+    putTempObject(c->asBinder());
+    runInAnotherProcess("testReconnectFailed");
+    // Unlock then reconnect from a different process -- ok.
+    ASSERT(c->unlock() == NO_ERROR);
+    runInAnotherProcess("testReconnectSuccess");
+    clearTempObject();
+}
+
+// We need to flush the command buffer after the reference
+// to ICamera is gone. The sleep is for the server to run
+// the destructor for it.
+static void flushCommands() {
+    IPCThreadState::self()->flushCommands();
+    usleep(200000);  // 200ms
+}
+
+// Run a test case
+#define RUN(class_name, cameraId) do { \
+    { \
+        INFO(#class_name); \
+        class_name instance; \
+        instance.init(cameraId); \
+        instance.run(); \
+    } \
+    flushCommands(); \
+} while(0)
+
+// Base test case after the the camera is connected.
+class AfterConnect {
+public:
+    void init(int cameraId) {
+        cs = getCameraService();
+        cc = new MCameraClient();
+        c = cs->connect(cc, cameraId);
+        ASSERT(c != 0);
+    }
+
+protected:
+    sp<ICameraService> cs;
+    sp<MCameraClient> cc;
+    sp<ICamera> c;
+
+    ~AfterConnect() {
+        c->disconnect();
+        c.clear();
+        cc.clear();
+        cs.clear();
+    }
+};
+
+class TestSetPreviewDisplay : public AfterConnect {
+public:
+    void run() {
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestStartPreview : public AfterConnect {
+public:
+    void run() {
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+
+        ASSERT(c->startPreview() == NO_ERROR);
+        ASSERT(c->previewEnabled() == true);
+
+        surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
+        surface->clearStat();
+
+        sp<MSurface> another_surface = new MSurface();
+        c->setPreviewDisplay(another_surface);  // just to make sure unregisterBuffers
+                                                // is called.
+        surface->waitUntil(0, 0, 1);  // needs unregisterBuffers
+
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestStartPreviewWithoutDisplay : public AfterConnect {
+public:
+    void run() {
+        ASSERT(c->startPreview() == NO_ERROR);
+        ASSERT(c->previewEnabled() == true);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+// Base test case after the the camera is connected and the preview is started.
+class AfterStartPreview : public AfterConnect {
+public:
+    void init(int cameraId) {
+        AfterConnect::init(cameraId);
+        surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+        ASSERT(c->startPreview() == NO_ERROR);
+    }
+
+protected:
+    sp<MSurface> surface;
+
+    ~AfterStartPreview() {
+        surface.clear();
+    }
+};
+
+class TestAutoFocus : public AfterStartPreview {
+public:
+    void run() {
+        cc->assertNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 0);
+        c->autoFocus();
+        cc->waitNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 1);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestStopPreview : public AfterStartPreview {
+public:
+    void run() {
+        ASSERT(c->previewEnabled() == true);
+        c->stopPreview();
+        ASSERT(c->previewEnabled() == false);
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestTakePicture: public AfterStartPreview {
+public:
+    void run() {
+        ASSERT(c->takePicture() == NO_ERROR);
+        cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
+        cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
+        cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
+        c->stopPreview();
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestTakeMultiplePictures: public AfterStartPreview {
+public:
+    void run() {
+        for (int i = 0; i < 10; i++) {
+            cc->clearStat();
+            ASSERT(c->takePicture() == NO_ERROR);
+            cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
+            cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
+            cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
+        }
+        c->disconnect();
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+};
+
+class TestGetParameters: public AfterStartPreview {
+public:
+    void run() {
+        String8 param_str = c->getParameters();
+        INFO("%s", static_cast<const char*>(param_str));
+    }
+};
+
+static bool getNextSize(const char **ptrS, int *w, int *h) {
+    const char *s = *ptrS;
+
+    // skip over ','
+    if (*s == ',') s++;
+
+    // remember start position in p
+    const char *p = s;
+    while (*s != '\0' && *s != 'x') {
+        s++;
+    }
+    if (*s == '\0') return false;
+
+    // get the width
+    *w = atoi(p);
+
+    // skip over 'x'
+    ASSERT(*s == 'x');
+    p = s + 1;
+    while (*s != '\0' && *s != ',') {
+        s++;
+    }
+
+    // get the height
+    *h = atoi(p);
+    *ptrS = s;
+    return true;
+}
+
+class TestPictureSize : public AfterStartPreview {
+public:
+    void checkOnePicture(int w, int h) {
+        const float rate = 0.9;  // byte per pixel limit
+        int pixels = w * h;
+
+        CameraParameters param(c->getParameters());
+        param.setPictureSize(w, h);
+        // disable thumbnail to get more accurate size.
+        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0);
+        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);
+        c->setParameters(param.flatten());
+
+        cc->clearStat();
+        ASSERT(c->takePicture() == NO_ERROR);
+        cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
+        //cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
+        cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
+        cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
+                int(pixels * rate));
+        cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
+        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
+    }
+
+    void run() {
+        CameraParameters param(c->getParameters());
+        int w, h;
+        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
+        while (getNextSize(&s, &w, &h)) {
+            LOGD("checking picture size %dx%d", w, h);
+            checkOnePicture(w, h);
+        }
+    }
+};
+
+class TestPreviewCallbackFlag : public AfterConnect {
+public:
+    void run() {
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+
+        // Try all flag combinations.
+        for (int v = 0; v < 8; v++) {
+            LOGD("TestPreviewCallbackFlag: flag=%d", v);
+            usleep(100000); // sleep a while to clear the in-flight callbacks.
+            cc->clearStat();
+            c->setPreviewCallbackFlag(v);
+            ASSERT(c->previewEnabled() == false);
+            ASSERT(c->startPreview() == NO_ERROR);
+            ASSERT(c->previewEnabled() == true);
+            sleep(2);
+            c->stopPreview();
+            if ((v & FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
+                cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
+            } else {
+                if ((v & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
+                    cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
+                } else {
+                    cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
+                }
+            }
+        }
+    }
+};
+
+class TestRecording : public AfterConnect {
+public:
+    void run() {
+        ASSERT(c->recordingEnabled() == false);
+        sp<MSurface> surface = new MSurface();
+        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
+        c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        cc->setReleaser(c.get());
+        c->startRecording();
+        ASSERT(c->recordingEnabled() == true);
+        sleep(2);
+        c->stopRecording();
+        usleep(100000); // sleep a while to clear the in-flight callbacks.
+        cc->setReleaser(NULL);
+        cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
+    }
+};
+
+class TestPreviewSize : public AfterStartPreview {
+public:
+    void checkOnePicture(int w, int h) {
+        int size = w*h*3/2;  // should read from parameters
+
+        c->stopPreview();
+
+        CameraParameters param(c->getParameters());
+        param.setPreviewSize(w, h);
+        c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        c->setParameters(param.flatten());
+
+        c->startPreview();
+
+        cc->clearStat();
+        cc->waitData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 1);
+        cc->assertDataSize(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, size);
+    }
+
+    void run() {
+        CameraParameters param(c->getParameters());
+        int w, h;
+        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
+        while (getNextSize(&s, &w, &h)) {
+            LOGD("checking preview size %dx%d", w, h);
+            checkOnePicture(w, h);
+        }
+    }
+};
+
+void runHolderService() {
+    defaultServiceManager()->addService(
+            String16("CameraServiceTest.Holder"), new HolderService());
+    ProcessState::self()->startThreadPool();
+}
+
+int main(int argc, char **argv)
+{
+    if (argc != 1) {
+        runFunction(argv[1]);
+        return 0;
+    }
+    INFO("CameraServiceTest start");
+    gExecutable = argv[0];
+    runHolderService();
+    int n = getNumberOfCameras();
+    INFO("%d Cameras available", n);
+
+    for (int id = 0; id < n; id++) {
+        INFO("Testing camera %d", id);
+        testConnect(id);                              flushCommands();
+        testAllowConnectOnceOnly(id);                 flushCommands();
+        testReconnect(id);                            flushCommands();
+        testLockUnlock(id);                           flushCommands();
+        testReconnectFromAnotherProcess(id);          flushCommands();
+
+        RUN(TestSetPreviewDisplay, id);
+        RUN(TestStartPreview, id);
+        RUN(TestStartPreviewWithoutDisplay, id);
+        RUN(TestAutoFocus, id);
+        RUN(TestStopPreview, id);
+        RUN(TestTakePicture, id);
+        RUN(TestTakeMultiplePictures, id);
+        RUN(TestGetParameters, id);
+        RUN(TestPictureSize, id);
+        RUN(TestPreviewCallbackFlag, id);
+        RUN(TestRecording, id);
+        RUN(TestPreviewSize, id);
+    }
+
+    INFO("CameraServiceTest finished");
+}