am af05c912: am a8c06116: Merge "Remove remnants of HWC 0.x"

* commit 'af05c912e1afa1f7d7b3f4b1d8b3034427abc37b':
  Remove remnants of HWC 0.x
diff --git a/tests/camera2/Android.mk b/tests/camera2/Android.mk
index c378e12..a13ca79 100644
--- a/tests/camera2/Android.mk
+++ b/tests/camera2/Android.mk
@@ -3,20 +3,31 @@
 
 LOCAL_SRC_FILES:= \
 	camera2.cpp \
-	camera2_utils.cpp
+	camera2_utils.cpp \
+	main.cpp \
+	CameraMetadataTests.cpp \
+	CameraModuleTests.cpp \
+	CameraStreamTests.cpp \
+	CameraFrameTests.cpp \
+	CameraBurstTests.cpp \
+	ForkedTests.cpp \
+	TestForkerEventListener.cpp \
+	TestSettings.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
 	libutils \
+	libcutils \
 	libstlport \
 	libhardware \
 	libcamera_metadata \
+	libcameraservice \
 	libgui \
 	libsync \
-	libui
+	libui \
+	libdl
 
 LOCAL_STATIC_LIBRARIES := \
-	libgtest \
-	libgtest_main
+	libgtest
 
 LOCAL_C_INCLUDES += \
 	bionic \
@@ -24,6 +35,10 @@
 	external/gtest/include \
 	external/stlport/stlport \
 	system/media/camera/include \
+	frameworks/av/services/camera/libcameraservice \
+	frameworks/native/include \
+
+LOCAL_CFLAGS += -Wall -Wextra -include FutureMetadata.h
 
 LOCAL_MODULE:= camera2_test
 LOCAL_MODULE_TAGS := tests
diff --git a/tests/camera2/CameraBurstTests.cpp b/tests/camera2/CameraBurstTests.cpp
new file mode 100644
index 0000000..e39970c
--- /dev/null
+++ b/tests/camera2/CameraBurstTests.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#define LOG_TAG "CameraBurstTest"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <cmath>
+
+#include "CameraStreamFixture.h"
+#include "TestExtensions.h"
+
+#define CAMERA_FRAME_TIMEOUT    1000000000 //nsecs (1 secs)
+#define CAMERA_HEAP_COUNT       2 //HALBUG: 1 means registerBuffers fails
+#define CAMERA_BURST_DEBUGGING  0
+#define CAMERA_FRAME_BURST_COUNT 10
+
+/* constants for the exposure test */
+#define CAMERA_EXPOSURE_DOUBLE  2
+#define CAMERA_EXPOSURE_DOUBLING_THRESHOLD 1.0f
+#define CAMERA_EXPOSURE_DOUBLING_COUNT 4
+#define CAMERA_EXPOSURE_FORMAT HAL_PIXEL_FORMAT_YCrCb_420_SP
+#define CAMERA_EXPOSURE_STARTING 100000 // 1/10ms, up to 51.2ms with 10 steps
+
+#if CAMERA_BURST_DEBUGGING
+#define dout std::cout
+#else
+#define dout if (0) std::cout
+#endif
+
+using namespace android;
+using namespace android::camera2;
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+static CameraStreamParams STREAM_PARAMETERS = {
+    /*mFormat*/     CAMERA_EXPOSURE_FORMAT,
+    /*mHeapCount*/  CAMERA_HEAP_COUNT
+};
+
+class CameraBurstTest
+    : public ::testing::Test,
+      public CameraStreamFixture {
+
+public:
+    CameraBurstTest() : CameraStreamFixture(STREAM_PARAMETERS) {
+        TEST_EXTENSION_FORKING_CONSTRUCTOR;
+
+        if (HasFatalFailure()) {
+            return;
+        }
+
+        CreateStream();
+    }
+
+    ~CameraBurstTest() {
+        TEST_EXTENSION_FORKING_DESTRUCTOR;
+
+        if (mDevice.get()) {
+            mDevice->waitUntilDrained();
+        }
+        DeleteStream();
+    }
+
+    virtual void SetUp() {
+        TEST_EXTENSION_FORKING_SET_UP;
+    }
+    virtual void TearDown() {
+        TEST_EXTENSION_FORKING_TEAR_DOWN;
+    }
+
+    /* this assumes the format is YUV420sp */
+    long long TotalBrightness(const CpuConsumer::LockedBuffer& imgBuffer,
+                              int *underexposed,
+                              int *overexposed) const {
+
+        const uint8_t* buf = imgBuffer.data;
+        size_t stride = imgBuffer.stride;
+
+        /* iterate over the Y plane only */
+        long long acc = 0;
+
+        *underexposed = 0;
+        *overexposed = 0;
+
+        for (size_t y = 0; y < imgBuffer.height; ++y) {
+            for (size_t x = 0; x < imgBuffer.width; ++x) {
+                const uint8_t p = buf[y * stride + x];
+
+                if (p == 0) {
+                    if (underexposed) {
+                        ++*underexposed;
+                    }
+                    continue;
+                } else if (p == 255) {
+                    if (overexposed) {
+                        ++*overexposed;
+                    }
+                    continue;
+                }
+
+                acc += p;
+            }
+        }
+
+        return acc;
+    }
+};
+
+TEST_F(CameraBurstTest, ManualExposureControl) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    // Range of valid exposure times, in nanoseconds
+    int64_t minExp, maxExp;
+    {
+        camera_metadata_ro_entry exposureTimeRange =
+            GetStaticEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE);
+
+        ASSERT_EQ(2u, exposureTimeRange.count);
+        minExp = exposureTimeRange.data.i64[0];
+        maxExp = exposureTimeRange.data.i64[1];
+    }
+
+    dout << "Min exposure is " << minExp;
+    dout << " max exposure is " << maxExp << std::endl;
+
+    // Calculate some set of valid exposure times for each request
+    int64_t exposures[CAMERA_FRAME_BURST_COUNT];
+    exposures[0] = CAMERA_EXPOSURE_STARTING;
+    for (int i = 1; i < CAMERA_FRAME_BURST_COUNT; ++i) {
+        exposures[i] = exposures[i-1] * CAMERA_EXPOSURE_DOUBLE;
+    }
+    // Our calculated exposure times should be in [minExp, maxExp]
+    EXPECT_LE(minExp, exposures[0])
+        << "Minimum exposure range is too high, wanted at most "
+        << exposures[0] << "ns";
+    EXPECT_GE(maxExp, exposures[CAMERA_FRAME_BURST_COUNT-1])
+        << "Maximum exposure range is too low, wanted at least "
+        << exposures[CAMERA_FRAME_BURST_COUNT-1] << "ns";
+
+    // Create a preview request, turning off all 3A
+    CameraMetadata previewRequest;
+    ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+                                                &previewRequest));
+    {
+        Vector<uint8_t> outputStreamIds;
+        outputStreamIds.push(mStreamId);
+        ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+                                            outputStreamIds));
+
+        // Disable all 3A routines
+        uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+        ASSERT_EQ(OK, previewRequest.update(ANDROID_CONTROL_MODE,
+                                            &cmOff, 1));
+        if (CAMERA_BURST_DEBUGGING) {
+            int frameCount = 0;
+            ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_FRAME_COUNT,
+                                                &frameCount, 1));
+        }
+    }
+
+    if (CAMERA_BURST_DEBUGGING) {
+        previewRequest.dump(STDOUT_FILENO);
+    }
+
+    // Submit capture requests
+    for (int i = 0; i < CAMERA_FRAME_BURST_COUNT; ++i) {
+        CameraMetadata tmpRequest = previewRequest;
+        ASSERT_EQ(OK, tmpRequest.update(ANDROID_SENSOR_EXPOSURE_TIME,
+                                        &exposures[i], 1));
+        ALOGV("Submitting capture request %d with exposure %lld", i,
+            exposures[i]);
+        dout << "Capture request " << i << " exposure is "
+             << (exposures[i]/1e6f) << std::endl;
+        ASSERT_EQ(OK, mDevice->capture(tmpRequest));
+    }
+
+    dout << "Buffer dimensions " << mWidth << "x" << mHeight << std::endl;
+
+    float brightnesses[CAMERA_FRAME_BURST_COUNT];
+    // Get each frame (metadata) and then the buffer. Calculate brightness.
+    for (int i = 0; i < CAMERA_FRAME_BURST_COUNT; ++i) {
+        ALOGV("Reading capture request %d with exposure %lld", i, exposures[i]);
+        ASSERT_EQ(OK, mDevice->waitForNextFrame(CAMERA_FRAME_TIMEOUT));
+        ALOGV("Reading capture request-1 %d", i);
+        CameraMetadata frameMetadata;
+        ASSERT_EQ(OK, mDevice->getNextFrame(&frameMetadata));
+        ALOGV("Reading capture request-2 %d", i);
+
+        ASSERT_EQ(OK, mFrameListener->waitForFrame(CAMERA_FRAME_TIMEOUT));
+        ALOGV("We got the frame now");
+
+        CpuConsumer::LockedBuffer imgBuffer;
+        ASSERT_EQ(OK, mCpuConsumer->lockNextBuffer(&imgBuffer));
+
+        int underexposed, overexposed;
+        long long brightness = TotalBrightness(imgBuffer, &underexposed,
+                                               &overexposed);
+        float avgBrightness = brightness * 1.0f /
+                              (mWidth * mHeight - (underexposed + overexposed));
+        ALOGV("Total brightness for frame %d was %lld (underexposed %d, "
+              "overexposed %d), avg %f", i, brightness, underexposed,
+              overexposed, avgBrightness);
+        dout << "Average brightness (frame " << i << ") was " << avgBrightness
+             << " (underexposed " << underexposed << ", overexposed "
+             << overexposed << ")" << std::endl;
+
+        ASSERT_EQ(OK, mCpuConsumer->unlockBuffer(imgBuffer));
+
+        brightnesses[i] = avgBrightness;
+    }
+
+    // Calculate max consecutive frame exposure doubling
+    float prev = brightnesses[0];
+    int doubling_count = 1;
+    int max_doubling_count = 0;
+    for (int i = 1; i < CAMERA_FRAME_BURST_COUNT; ++i) {
+        if (fabs(brightnesses[i] - prev*CAMERA_EXPOSURE_DOUBLE)
+            <= CAMERA_EXPOSURE_DOUBLING_THRESHOLD) {
+            doubling_count++;
+        }
+        else {
+            max_doubling_count = std::max(max_doubling_count, doubling_count);
+            doubling_count = 1;
+        }
+        prev = brightnesses[i];
+    }
+
+    dout << "max doubling count: " << max_doubling_count << std::endl;
+
+    EXPECT_LE(CAMERA_EXPOSURE_DOUBLING_COUNT, max_doubling_count)
+      << "average brightness should double at least "
+      << CAMERA_EXPOSURE_DOUBLING_COUNT
+      << " times over each consecutive frame as the exposure is doubled";
+}
+
+}
+}
+}
+
diff --git a/tests/camera2/CameraFrameTests.cpp b/tests/camera2/CameraFrameTests.cpp
new file mode 100644
index 0000000..13d1b17
--- /dev/null
+++ b/tests/camera2/CameraFrameTests.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#define LOG_TAG "CameraFrameTest"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "hardware/hardware.h"
+#include "hardware/camera2.h"
+
+#include "Camera2Device.h"
+#include "utils/StrongPointer.h"
+
+#include <gui/CpuConsumer.h>
+#include <gui/SurfaceTextureClient.h>
+
+#include <unistd.h>
+
+#include "CameraStreamFixture.h"
+#include "TestExtensions.h"
+
+#define CAMERA_FRAME_TIMEOUT    1000000000 //nsecs (1 secs)
+#define CAMERA_HEAP_COUNT       2 //HALBUG: 1 means registerBuffers fails
+#define CAMERA_FRAME_DEBUGGING  0
+
+using namespace android;
+using namespace android::camera2;
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+static CameraStreamParams STREAM_PARAMETERS = {
+    /*mFormat*/     HAL_PIXEL_FORMAT_YCrCb_420_SP,
+    /*mHeapCount*/  CAMERA_HEAP_COUNT
+};
+
+class CameraFrameTest
+    : public ::testing::TestWithParam<int>,
+      public CameraStreamFixture {
+
+public:
+    CameraFrameTest() : CameraStreamFixture(STREAM_PARAMETERS) {
+        TEST_EXTENSION_FORKING_CONSTRUCTOR;
+
+        if (!HasFatalFailure()) {
+            CreateStream();
+        }
+    }
+
+    ~CameraFrameTest() {
+        TEST_EXTENSION_FORKING_DESTRUCTOR;
+
+        if (mDevice.get()) {
+            mDevice->waitUntilDrained();
+        }
+    }
+
+    virtual void SetUp() {
+        TEST_EXTENSION_FORKING_SET_UP;
+    }
+    virtual void TearDown() {
+        TEST_EXTENSION_FORKING_TEAR_DOWN;
+    }
+
+protected:
+
+};
+
+TEST_P(CameraFrameTest, GetFrame) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    /* Submit a PREVIEW type request, then wait until we get the frame back */
+    CameraMetadata previewRequest;
+    ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+                                                &previewRequest));
+    {
+        Vector<uint8_t> outputStreamIds;
+        outputStreamIds.push(mStreamId);
+        ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+                                            outputStreamIds));
+        if (CAMERA_FRAME_DEBUGGING) {
+            int frameCount = 0;
+            ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_FRAME_COUNT,
+                                                &frameCount, 1));
+        }
+    }
+
+    if (CAMERA_FRAME_DEBUGGING) {
+        previewRequest.dump(STDOUT_FILENO);
+    }
+
+    for (int i = 0; i < GetParam(); ++i) {
+        ALOGV("Submitting capture request %d", i);
+        CameraMetadata tmpRequest = previewRequest;
+        ASSERT_EQ(OK, mDevice->capture(tmpRequest));
+    }
+
+    for (int i = 0; i < GetParam(); ++i) {
+        ALOGV("Reading capture request %d", i);
+        ASSERT_EQ(OK, mDevice->waitForNextFrame(CAMERA_FRAME_TIMEOUT));
+
+        CameraMetadata frameMetadata;
+        ASSERT_EQ(OK, mDevice->getNextFrame(&frameMetadata));
+
+        // wait for buffer to be available
+        ASSERT_EQ(OK, mFrameListener->waitForFrame(CAMERA_FRAME_TIMEOUT));
+        ALOGV("We got the frame now");
+
+        // mark buffer consumed so producer can re-dequeue it
+        CpuConsumer::LockedBuffer imgBuffer;
+        ASSERT_EQ(OK, mCpuConsumer->lockNextBuffer(&imgBuffer));
+        ASSERT_EQ(OK, mCpuConsumer->unlockBuffer(imgBuffer));
+    }
+
+}
+
+//FIXME: dont hardcode stream params, and also test multistream
+INSTANTIATE_TEST_CASE_P(FrameParameterCombinations, CameraFrameTest,
+    testing::Range(1, 10));
+
+
+}
+}
+}
+
diff --git a/tests/camera2/CameraMetadataTests.cpp b/tests/camera2/CameraMetadataTests.cpp
new file mode 100644
index 0000000..d02d104
--- /dev/null
+++ b/tests/camera2/CameraMetadataTests.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "CameraMetadataTestFunctional"
+#include "cutils/log.h"
+#include "cutils/properties.h"
+#include "utils/Errors.h"
+
+#include "gtest/gtest.h"
+#include "system/camera_metadata.h"
+#include "hardware/hardware.h"
+#include "hardware/camera2.h"
+
+#include "Camera2Device.h"
+#include "utils/StrongPointer.h"
+
+#include <gui/CpuConsumer.h>
+#include <gui/SurfaceTextureClient.h>
+
+#include <string>
+
+#include "CameraStreamFixture.h"
+#include "TestExtensions.h"
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+//FIXME: dont hardcode
+static CameraStreamParams METADATA_STREAM_PARAMETERS = {
+    /*mFormat*/     HAL_PIXEL_FORMAT_YCrCb_420_SP,
+    /*mHeapCount*/  2
+};
+
+class CameraMetadataTest
+    : public ::testing::Test,
+      public CameraStreamFixture {
+
+public:
+    CameraMetadataTest()
+    : CameraStreamFixture(METADATA_STREAM_PARAMETERS) {
+        TEST_EXTENSION_FORKING_CONSTRUCTOR;
+    }
+
+    ~CameraMetadataTest() {
+        TEST_EXTENSION_FORKING_DESTRUCTOR;
+    }
+
+    int GetTypeFromTag(uint32_t tag) const {
+        return get_camera_metadata_tag_type(tag);
+    }
+
+    int GetTypeFromStaticTag(uint32_t tag) const {
+        const CameraMetadata& staticInfo = mDevice->info();
+        camera_metadata_ro_entry entry = staticInfo.find(tag);
+        return entry.type;
+    }
+
+protected:
+
+};
+
+TEST_F(CameraMetadataTest, types) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    //FIXME: set this up in an external file of some sort (xml?)
+    {
+        char value[PROPERTY_VALUE_MAX];
+        property_get("ro.build.id", value, "");
+        std::string str_value(value);
+
+        if (str_value == "manta")
+        {
+            EXPECT_EQ(TYPE_BYTE,
+                GetTypeFromStaticTag(ANDROID_QUIRKS_TRIGGER_AF_WITH_AUTO));
+            EXPECT_EQ(TYPE_BYTE,
+                GetTypeFromStaticTag(ANDROID_QUIRKS_USE_ZSL_FORMAT));
+            EXPECT_EQ(TYPE_BYTE,
+                GetTypeFromStaticTag(ANDROID_QUIRKS_METERING_CROP_REGION));
+        }
+    }
+
+    /*
+    TODO:
+    go through all static metadata and make sure all fields we expect
+    that are there, ARE there.
+
+    dont worry about the type as its enforced by the metadata api
+    we can probably check the range validity though
+    */
+
+    if (0) {
+        camera_metadata_ro_entry entry;
+        EXPECT_EQ(TYPE_BYTE,     entry.type);
+        EXPECT_EQ(TYPE_INT32,    entry.type);
+        EXPECT_EQ(TYPE_FLOAT,    entry.type);
+        EXPECT_EQ(TYPE_INT64,    entry.type);
+        EXPECT_EQ(TYPE_DOUBLE,   entry.type);
+        EXPECT_EQ(TYPE_RATIONAL, entry.type);
+    }
+}
+
+}
+}
+}
diff --git a/tests/camera2/CameraModuleFixture.h b/tests/camera2/CameraModuleFixture.h
new file mode 100644
index 0000000..cd8ddc4
--- /dev/null
+++ b/tests/camera2/CameraModuleFixture.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_HAL_CAMERA2_TESTS_MODULE_FIXTURE__
+#define __ANDROID_HAL_CAMERA2_TESTS_MODULE_FIXTURE__
+
+#include <gtest/gtest.h>
+
+#include "hardware/hardware.h"
+#include "hardware/camera2.h"
+
+#include "Camera2Device.h"
+#include "camera2_utils.h"
+#include "TestExtensions.h"
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+template <bool InfoQuirk = false>
+struct CameraModuleFixture {
+
+    CameraModuleFixture(int CameraID = -1) {
+        TEST_EXTENSION_FORKING_CONSTRUCTOR;
+
+        mCameraID = CameraID;
+    }
+
+    ~CameraModuleFixture() {
+        TEST_EXTENSION_FORKING_DESTRUCTOR;
+    }
+
+    camera_metadata_ro_entry GetStaticEntry(uint32_t tag) const {
+        const CameraMetadata& staticInfo = mDevice->info();
+        camera_metadata_ro_entry entry = staticInfo.find(tag);
+        return entry;
+    }
+
+    void SetUp() {
+        TEST_EXTENSION_FORKING_SET_UP;
+
+        ASSERT_LE(0, hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+            (const hw_module_t **)&mModule)) << "Could not load camera module";
+        ASSERT_NE((void*)0, mModule);
+
+        mNumberOfCameras = mModule->get_number_of_cameras();
+        ASSERT_LE(0, mNumberOfCameras);
+
+        ASSERT_EQ(
+            CAMERA_MODULE_API_VERSION_2_0, mModule->common.module_api_version)
+            << "Wrong module API version";
+
+        /* For using this fixture in other tests only */
+        SetUpMixin();
+    }
+
+    void TearDown() {
+        TEST_EXTENSION_FORKING_TEAR_DOWN;
+
+        TearDownMixin();
+
+        /* important: device must be destructed before closing module,
+           since it calls back into HAL */
+        mDevice.clear();
+
+        if (!TEST_EXTENSION_FORKING_ENABLED) {
+            ASSERT_EQ(0, HWModuleHelpers::closeModule(&mModule->common))
+                << "Failed to close camera HAL module";
+        }
+    }
+
+private:
+
+    void SetUpMixin() {
+        /* For using this fixture in other tests only */
+        if (mCameraID != -1) {
+            EXPECT_LE(0, mCameraID);
+            EXPECT_LT(mCameraID, mNumberOfCameras);
+
+            /* HALBUG (Exynos5); crashes if trying to initialize
+               before calling get_camera_info */
+            if (InfoQuirk) {
+                struct camera_info info;
+                ASSERT_EQ(OK, mModule->get_camera_info(mCameraID, &info));
+            }
+
+            mDevice = new Camera2Device(mCameraID);
+            ASSERT_EQ(OK, mDevice->initialize(mModule))
+                << "Failed to initialize device " << mCameraID;
+        }
+    }
+
+    void TearDownMixin() {
+
+    }
+
+protected:
+    int mNumberOfCameras;
+    camera_module_t *mModule;
+    sp<Camera2Device> mDevice;
+
+private:
+    int mCameraID;
+};
+
+
+}
+}
+}
+
+#endif
diff --git a/tests/camera2/CameraModuleTests.cpp b/tests/camera2/CameraModuleTests.cpp
new file mode 100644
index 0000000..fc6fd36
--- /dev/null
+++ b/tests/camera2/CameraModuleTests.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#define LOG_TAG "CameraModuleTest"
+#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "hardware/hardware.h"
+#include "hardware/camera2.h"
+
+#include "Camera2Device.h"
+#include "utils/StrongPointer.h"
+#include "CameraModuleFixture.h"
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+class CameraModuleTest : public ::testing::Test,
+                                  public CameraModuleFixture<> {
+
+public:
+    CameraModuleTest() {
+        CameraModuleFixture::SetUp();
+    }
+
+    ~CameraModuleTest() {
+        CameraModuleFixture::TearDown();
+    }
+
+    status_t initializeDevice(int cameraId) {
+
+        // ignore HAL1s. count as test pass
+        status_t stat;
+        if (isDeviceVersionHal2(cameraId, &stat) && stat == OK) {
+            stat = mDevice->initialize(mModule);
+        }
+
+        return stat;
+    }
+
+    int getDeviceVersion(int cameraId, status_t* status) {
+        camera_info info;
+        *status = mModule->get_camera_info(cameraId, &info);
+
+        return info.device_version;
+    }
+
+    bool isDeviceVersionHal2(int cameraId, status_t* status) {
+        return getDeviceVersion(cameraId, status)
+               >= CAMERA_DEVICE_API_VERSION_2_0;
+    }
+};
+
+TEST_F(CameraModuleTest, LoadModule) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    for (int i = 0; i < mNumberOfCameras; ++i) {
+        mDevice = new Camera2Device(i);
+
+        ASSERT_EQ(OK, initializeDevice(i))
+            << "Failed to initialize device " << i;
+        mDevice.clear();
+    }
+
+}
+
+TEST_F(CameraModuleTest, LoadModuleBadIndices) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    int idx[] = { -1, mNumberOfCameras, mNumberOfCameras + 1 };
+
+    for (unsigned i = 0; i < sizeof(idx)/sizeof(idx[0]); ++i) {
+        mDevice = new Camera2Device(idx[i]);
+        status_t deviceInitializeCode = initializeDevice(idx[i]);
+        EXPECT_NE(OK, deviceInitializeCode);
+        EXPECT_EQ(-ENODEV, deviceInitializeCode)
+            << "Incorrect error code when trying to initialize invalid index "
+            << idx[i];
+        mDevice.clear();
+    }
+}
+
+TEST_F(CameraModuleTest, GetCameraInfo) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    for (int i = 0; i < mNumberOfCameras; ++i) {
+        struct camera_info info;
+        ASSERT_EQ(OK, mModule->get_camera_info(i, &info));
+    }
+
+}
+
+TEST_F(CameraModuleTest, GetCameraInfoBadIndices) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    int idx[] = { -1, mNumberOfCameras, mNumberOfCameras + 1 };
+    for (unsigned i = 0; i < sizeof(idx)/sizeof(idx[0]); ++i) {
+        struct camera_info info;
+        EXPECT_NE(OK, mModule->get_camera_info(idx[i], &info));
+        EXPECT_EQ(-ENODEV, mModule->get_camera_info(idx[i], &info))
+            << "Incorrect error code for get_camera_info idx= "
+            << idx[i];
+    }
+}
+
+/**
+ * TODO: Additional test to add: open two cameras at once.
+ *       (is allowed to fail, at least for now, but should not blow up)
+ *     - open same device multiple times
+ *     - close same device multiple times
+ */
+
+
+
+
+}
+}
+}
+
diff --git a/tests/camera2/CameraStreamFixture.h b/tests/camera2/CameraStreamFixture.h
new file mode 100644
index 0000000..569b9d1
--- /dev/null
+++ b/tests/camera2/CameraStreamFixture.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_HAL_CAMERA2_TESTS_STREAM_FIXTURE__
+#define __ANDROID_HAL_CAMERA2_TESTS_STREAM_FIXTURE__
+
+#include <gtest/gtest.h>
+#include <iostream>
+
+#include <gui/CpuConsumer.h>
+#include <gui/SurfaceTextureClient.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#include "CameraModuleFixture.h"
+#include "TestExtensions.h"
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+struct CameraStreamParams {
+    int mFormat;
+    int mHeapCount;
+};
+
+inline void PrintTo(const CameraStreamParams& p, ::std::ostream* os) {
+    *os <<  "{ ";
+    *os <<  "Format: "    << p.mFormat    << ", ";
+    *os <<  "HeapCount: " << p.mHeapCount;
+    *os << " }";
+}
+
+class CameraStreamFixture
+    : public CameraModuleFixture</*InfoQuirk*/true> {
+
+public:
+    CameraStreamFixture(CameraStreamParams p)
+    : CameraModuleFixture(TestSettings::DeviceId()) {
+        TEST_EXTENSION_FORKING_CONSTRUCTOR;
+
+        mParam = p;
+
+        SetUp();
+    }
+
+    ~CameraStreamFixture() {
+        TEST_EXTENSION_FORKING_DESTRUCTOR;
+
+        TearDown();
+    }
+
+private:
+
+    void SetUp() {
+        TEST_EXTENSION_FORKING_SET_UP;
+
+        CameraModuleFixture::SetUp();
+
+        CameraStreamParams p = mParam;
+        sp<Camera2Device> device = mDevice;
+
+        /* use an arbitrary w,h */
+        {
+            const int tag = ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES;
+
+            const android::camera2::CameraMetadata& staticInfo = device->info();
+            camera_metadata_ro_entry entry = staticInfo.find(tag);
+            ASSERT_NE(0u, entry.count)
+                << "Missing tag android.scaler.availableProcessedSizes";
+
+            ASSERT_LE(2u, entry.count);
+            /* this seems like it would always be the smallest w,h
+               but we actually make no contract that it's sorted asc */;
+            mWidth = entry.data.i32[0];
+            mHeight = entry.data.i32[1];
+        }
+    }
+    void TearDown() {
+        TEST_EXTENSION_FORKING_TEAR_DOWN;
+
+        // important: shut down HAL before releasing streams
+        CameraModuleFixture::TearDown();
+
+        mNativeWindow.clear();
+        mCpuConsumer.clear();
+        mFrameListener.clear();
+    }
+
+protected:
+    struct FrameListener : public ConsumerBase::FrameAvailableListener {
+
+        FrameListener() {
+            mPendingFrames = 0;
+        }
+
+        // CpuConsumer::FrameAvailableListener implementation
+        virtual void onFrameAvailable() {
+            ALOGV("Frame now available (start)");
+
+            Mutex::Autolock lock(mMutex);
+            mPendingFrames++;
+            mCondition.signal();
+
+            ALOGV("Frame now available (end)");
+        }
+
+        status_t waitForFrame(nsecs_t timeout) {
+            status_t res;
+            Mutex::Autolock lock(mMutex);
+            while (mPendingFrames == 0) {
+                res = mCondition.waitRelative(mMutex, timeout);
+                if (res != OK) return res;
+            }
+            mPendingFrames--;
+            return OK;
+        }
+
+    private:
+        Mutex mMutex;
+        Condition mCondition;
+        int mPendingFrames;
+    };
+
+    void CreateStream() {
+        sp<Camera2Device> device = mDevice;
+        CameraStreamParams p = mParam;
+
+        mCpuConsumer = new CpuConsumer(p.mHeapCount);
+        mCpuConsumer->setName(String8("CameraStreamTest::mCpuConsumer"));
+
+        mNativeWindow = new SurfaceTextureClient(
+            mCpuConsumer->getProducerInterface());
+
+        ASSERT_EQ(OK,
+            device->createStream(mNativeWindow,
+                mWidth, mHeight, p.mFormat, /*size (for jpegs)*/0,
+                &mStreamId));
+
+        ASSERT_NE(-1, mStreamId);
+
+        // do not make 'this' a FrameListener or the lifetime policy will clash
+        mFrameListener = new FrameListener();
+        mCpuConsumer->setFrameAvailableListener(mFrameListener);
+    }
+
+    void DeleteStream() {
+        ASSERT_EQ(OK, mDevice->deleteStream(mStreamId));
+    }
+
+    int mWidth;
+    int mHeight;
+
+    int mStreamId;
+
+    android::sp<FrameListener>       mFrameListener;
+    android::sp<CpuConsumer>         mCpuConsumer;
+    android::sp<ANativeWindow>       mNativeWindow;
+
+
+private:
+    CameraStreamParams mParam;
+};
+
+}
+}
+}
+
+#endif
diff --git a/tests/camera2/CameraStreamTests.cpp b/tests/camera2/CameraStreamTests.cpp
new file mode 100644
index 0000000..b076296
--- /dev/null
+++ b/tests/camera2/CameraStreamTests.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <iomanip>
+#include <gtest/gtest.h>
+
+#define LOG_TAG "CameraStreamTest"
+#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "hardware/hardware.h"
+#include "hardware/camera2.h"
+
+#include "Camera2Device.h"
+#include "utils/StrongPointer.h"
+
+#include <gui/CpuConsumer.h>
+#include <gui/SurfaceTextureClient.h>
+
+#include "CameraStreamFixture.h"
+#include "TestExtensions.h"
+
+using namespace android;
+using namespace android::camera2;
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+class CameraStreamTest
+    : public ::testing::TestWithParam<CameraStreamParams>,
+      public CameraStreamFixture {
+
+public:
+    CameraStreamTest() : CameraStreamFixture(GetParam()) {
+        TEST_EXTENSION_FORKING_CONSTRUCTOR;
+    }
+
+    ~CameraStreamTest() {
+        TEST_EXTENSION_FORKING_DESTRUCTOR;
+    }
+
+    virtual void SetUp() {
+        TEST_EXTENSION_FORKING_SET_UP;
+    }
+    virtual void TearDown() {
+        TEST_EXTENSION_FORKING_TEAR_DOWN;
+    }
+
+protected:
+
+};
+
+TEST_P(CameraStreamTest, CreateStream) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    /** Make sure the format requested is supported. PASS this test if it's not
+      * not supported.
+      *
+      * TODO: would be nice of not running this test in the first place
+      *       somehow.
+      */
+    {
+        camera_metadata_ro_entry availableFormats =
+            GetStaticEntry(ANDROID_SCALER_AVAILABLE_FORMATS);
+
+        bool hasFormat = false;
+        for (size_t i = 0; i < availableFormats.count; ++i) {
+            if (availableFormats.data.i32[i] == GetParam().mFormat) {
+                hasFormat = true;
+                break;
+            }
+        }
+
+        if (!hasFormat) {
+            const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+            std::cerr << "Skipping test "
+                      << test_info->test_case_name() << "."
+                      << test_info->name()
+                      << " because the format was not available: 0x"
+                      << std::hex << GetParam().mFormat << std::endl;
+            return;
+        }
+    }
+
+    ASSERT_NO_FATAL_FAILURE(CreateStream());
+    ASSERT_NO_FATAL_FAILURE(DeleteStream());
+}
+
+//TODO: use a combinatoric generator
+static CameraStreamParams TestParameters[] = {
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+        /*mHeapCount*/ 1
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+        /*mHeapCount*/ 2
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+        /*mHeapCount*/ 3
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_YCrCb_420_SP, // NV21
+        /*mHeapCount*/ 1
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_YCrCb_420_SP,
+        /*mHeapCount*/ 2
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_YCrCb_420_SP,
+        /*mHeapCount*/ 3
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_YV12,
+        /*mHeapCount*/ 1
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_YV12,
+        /*mHeapCount*/ 2
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_YV12,
+        /*mHeapCount*/ 3
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_RAW_SENSOR,
+        /*mHeapCount*/ 1
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_RAW_SENSOR,
+        /*mHeapCount*/ 2
+    },
+    {
+        /*mFormat*/    HAL_PIXEL_FORMAT_RAW_SENSOR,
+        /*mHeapCount*/ 3
+    },
+};
+
+INSTANTIATE_TEST_CASE_P(StreamParameterCombinations, CameraStreamTest,
+    testing::ValuesIn(TestParameters));
+
+
+}
+}
+}
+
diff --git a/tests/camera2/ForkedTests.cpp b/tests/camera2/ForkedTests.cpp
new file mode 100644
index 0000000..315233e
--- /dev/null
+++ b/tests/camera2/ForkedTests.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "TestExtensions.h"
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+// Intentionally disabled since 2 of these tests are supposed to fail
+class DISABLED_ForkedTest : public ::testing::Test {
+
+    virtual void SetUp() {
+        TEST_EXTENSION_FORKING_SET_UP;
+    }
+
+    virtual void TearDown() {
+        TEST_EXTENSION_FORKING_TEAR_DOWN;
+    }
+};
+
+// intentionally fail
+TEST_F(DISABLED_ForkedTest, FailCrash) {
+    TEST_EXTENSION_FORKING_INIT;
+
+    //intentionally crash
+    *(int*)0 = 0xDEADBEEF;
+}
+
+TEST_F(DISABLED_ForkedTest, SucceedNormal) {
+    TEST_EXTENSION_FORKING_INIT;
+
+    EXPECT_TRUE(true);
+}
+
+// intentionally fail
+TEST_F(DISABLED_ForkedTest, FailNormal) {
+    TEST_EXTENSION_FORKING_INIT;
+
+    EXPECT_TRUE(false);
+}
+
+}
+}
+}
+
diff --git a/tests/camera2/FutureMetadata.h b/tests/camera2/FutureMetadata.h
new file mode 100644
index 0000000..58ea698
--- /dev/null
+++ b/tests/camera2/FutureMetadata.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Rename select master metadata 2.0 symbols to metadata symbols in jb-mr1-dev
+ * - this avoids having to bring in cross-repo changes
+ */
+
+#ifndef __ANDROID_HAL_CAMERA2_TESTS_FUTURE_METADATA__
+#define __ANDROID_HAL_CAMERA2_TESTS_FUTURE_METADATA__
+
+#define ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE ANDROID_SENSOR_EXPOSURE_TIME_RANGE
+#define ANDROID_CONTROL_MODE_OFF ANDROID_CONTROL_OFF
+
+#endif
diff --git a/tests/camera2/TestExtensions.h b/tests/camera2/TestExtensions.h
new file mode 100644
index 0000000..2af587d
--- /dev/null
+++ b/tests/camera2/TestExtensions.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_HAL_CAMERA2_TESTS_EXTENSIONS__
+#define __ANDROID_HAL_CAMERA2_TESTS_EXTENSIONS__
+
+#include "TestForkerEventListener.h"
+#include "TestSettings.h"
+
+// Use at the beginning of each Test::SetUp() impl
+#define TEST_EXTENSION_FORKING_SET_UP                                       \
+    do {                                                                    \
+        if (TEST_EXTENSION_FORKING_ENABLED) {                               \
+            if (!TestForkerEventListener::mIsForked) {                      \
+                return;                                                     \
+            }                                                               \
+        }                                                                   \
+    } while (false)                                                         \
+
+// Use at the beginning of each Test::TearDown() impl
+#define TEST_EXTENSION_FORKING_TEAR_DOWN   TEST_EXTENSION_FORKING_SET_UP
+
+// Use at the beginning of each Test::Test constructor
+#define TEST_EXTENSION_FORKING_CONSTRUCTOR TEST_EXTENSION_FORKING_SET_UP
+
+// Use at the beginning of each Test::~Test destructor
+#define TEST_EXTENSION_FORKING_DESTRUCTOR  TEST_EXTENSION_FORKING_TEAR_DOWN
+
+// Use at the beginning of each test body, e.g. TEST(x,y), TEST_F(x,y), etc
+#define TEST_EXTENSION_FORKING_INIT                                         \
+    do {                                                                    \
+        TEST_EXTENSION_FORKING_SET_UP;                                      \
+        if (HasFatalFailure()) return;                                      \
+    } while(false)                                                          \
+
+// Are we running each test by forking it?
+#define TEST_EXTENSION_FORKING_ENABLED                                      \
+    (android::camera2::tests::TestSettings::ForkingEnabled())
+
+
+
+#endif
+
diff --git a/tests/camera2/TestForkerEventListener.cpp b/tests/camera2/TestForkerEventListener.cpp
new file mode 100644
index 0000000..9416db2
--- /dev/null
+++ b/tests/camera2/TestForkerEventListener.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+#include "TestForkerEventListener.h"
+#include "TestExtensions.h"
+
+#define DEBUG_TEST_FORKER_EVENT_LISTENER 0
+
+#define RETURN_CODE_PASSED 0
+#define RETURN_CODE_FAILED 1
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+bool TestForkerEventListener::mIsForked         = false;
+
+TestForkerEventListener::TestForkerEventListener() {
+    mIsForked = false;
+    mHasSucceeded = true;
+    mTermSignal = 0;
+}
+
+// Called before a test starts.
+void TestForkerEventListener::OnTestStart(const ::testing::TestInfo&) {
+
+    if (!TEST_EXTENSION_FORKING_ENABLED) {
+        return;
+    }
+
+    pid_t childPid = fork();
+    if (childPid != 0) {
+        int status;
+        waitpid(childPid, &status, /*options*/0);
+
+        // terminated normally?
+        mHasSucceeded = WIFEXITED(status);
+        // terminate with return code 0 = test passed, 1 = test failed
+        if (mHasSucceeded) {
+          mHasSucceeded = WEXITSTATUS(status) == RETURN_CODE_PASSED;
+        } else if (WIFSIGNALED(status)) {
+          mTermSignal = WTERMSIG(status);
+        }
+
+        /* the test is then skipped by inserting the various
+        TEST_EXTENSION_ macros in TestExtensions.h */
+
+    } else {
+        mIsForked = true;
+    }
+}
+
+// Called after a failed assertion or a SUCCEED() invocation.
+void TestForkerEventListener::OnTestPartResult(
+    const ::testing::TestPartResult& test_part_result) {
+
+    if (DEBUG_TEST_FORKER_EVENT_LISTENER) {
+        printf("%s in %s:%d\n%s\n",
+             test_part_result.failed() ? "*** Failure" : "Success",
+             test_part_result.file_name(),
+             test_part_result.line_number(),
+             test_part_result.summary());
+    }
+}
+
+// Called after a test ends.
+void TestForkerEventListener::OnTestEnd(const ::testing::TestInfo& test_info) {
+
+    if (!TEST_EXTENSION_FORKING_ENABLED) {
+        return;
+    }
+
+    if (mIsForked) {
+        exit(test_info.result()->Passed()
+            ? RETURN_CODE_PASSED : RETURN_CODE_FAILED);
+    } else if (!mHasSucceeded && mTermSignal != 0) {
+
+      printf("*** Test %s.%s crashed with signal = %s\n",
+             test_info.test_case_name(), test_info.name(),
+             strsignal(mTermSignal));
+    }
+
+    //TODO: overload the default event listener to suppress this message
+    // dynamically (e.g. by skipping OnTestPartResult after OnTestEnd )
+
+    // trigger a test failure if the child has failed
+    if (!mHasSucceeded) {
+        ADD_FAILURE();
+    }
+    mTermSignal = 0;
+}
+
+
+}
+}
+}
+
diff --git a/tests/camera2/TestForkerEventListener.h b/tests/camera2/TestForkerEventListener.h
new file mode 100644
index 0000000..347a06b
--- /dev/null
+++ b/tests/camera2/TestForkerEventListener.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_HAL_CAMERA2_TESTS_FORKER_EVENT_LISTENER__
+#define __ANDROID_HAL_CAMERA2_TESTS_FORKER_EVENT_LISTENER__
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+// Fork before each test runs.
+class TestForkerEventListener : public ::testing::EmptyTestEventListener {
+
+public:
+
+    TestForkerEventListener();
+
+private:
+
+    // Called before a test starts.
+    virtual void OnTestStart(const ::testing::TestInfo& test_info);
+
+    // Called after a failed assertion or a SUCCEED() invocation.
+    virtual void OnTestPartResult(
+        const ::testing::TestPartResult& test_part_result);
+
+    // Called after a test ends.
+    virtual void OnTestEnd(const ::testing::TestInfo& test_info);
+
+    bool mHasSucceeded;
+    int mTermSignal;
+
+public:
+    // do not read directly. use TEST_EXTENSION macros instead
+    static bool mIsForked;
+};
+
+}
+}
+}
+
+#endif
diff --git a/tests/camera2/TestSettings.cpp b/tests/camera2/TestSettings.cpp
new file mode 100644
index 0000000..f07adc8
--- /dev/null
+++ b/tests/camera2/TestSettings.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdlib>
+#include <getopt.h>
+#include <cstring>
+#include <iostream>
+
+#include "TestSettings.h"
+
+#include "TestForkerEventListener.h"
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+bool TestSettings::mForkingDisabled     = false;
+int  TestSettings::mDeviceId            = 0;
+char* const* TestSettings::mArgv;
+
+// --forking-disabled, false by default
+bool TestSettings::ForkingDisabled() {
+    return mForkingDisabled;
+}
+
+// reverse of --forking-disabled (not a flag), true by default
+bool TestSettings::ForkingEnabled() {
+    return !ForkingDisabled();
+}
+
+// --device-id, 0 by default
+int TestSettings::DeviceId() {
+    return mDeviceId;
+}
+
+// returns false if usage should be printed and we should exit early
+bool TestSettings::ParseArgs(int argc, char* const argv[])
+{
+    {
+        char *env = getenv("CAMERA2_TEST_FORKING_DISABLED");
+        if (env) {
+            mForkingDisabled = atoi(env);
+        }
+
+        env = getenv("CAMERA2_TEST_DEVICE_ID");
+        if (env) {
+            mDeviceId = atoi(env);
+        }
+    }
+
+    bool printHelp = false;
+    bool unknownArgs = false;
+
+    opterr = 0; // do not print errors for unknown arguments
+    while (true) {
+        int c;
+        int option_index = 0;
+
+        static struct option long_options[] = {
+            /* name              has_arg          flag val */
+            {"forking-disabled", optional_argument, 0,  0  },
+            {"device-id",        required_argument, 0,  0  },
+            {"help",             no_argument,       0, 'h' },
+            {0,                  0,                 0,  0  }
+        };
+
+        // Note: '+' in optstring means do not mutate argv
+        c = getopt_long(argc, argv, "+h", long_options, &option_index);
+
+        if (c == -1) { // All arguments exhausted
+            break;
+        }
+        if (c == '?') { // Argument not in option lists
+            const char *arg = argv[optind-1];
+            // Anything beginning with gtest_ will get handled by gtest
+            if (strstr(arg, "--gtest_") != arg) {
+                std::cerr << "Unknown argument: " << arg << std::endl;
+                unknownArgs = true;
+            }
+            continue;
+        }
+
+        switch (c) {
+        case 0: // long option
+            switch (option_index) {
+            case 0: {
+                const char *arg = optarg ?: "1";
+                mForkingDisabled = atoi(arg);
+                break;
+            }
+            case 1: {
+                mDeviceId = atoi(optarg);
+                break;
+            }
+            default:
+                std::cerr << "Unknown long option: " << option_index << std::endl;
+                break;
+            }
+            break; // case 0
+        case 'h': // help
+            printHelp = true;
+            break;
+        default: // case '?'
+            std::cerr << "Unknown option: " << optarg << std::endl;
+        }
+    }
+
+    if (unknownArgs) {
+        std::cerr << std::endl;
+    }
+
+    mArgv = argv;
+
+    if (printHelp || unknownArgs) {
+        return false;
+    }
+
+    std::cerr << "Forking Disabled: "
+              << (mForkingDisabled ? "yes" : "no") << std::endl;
+
+    std::cerr << "Device ID: " << mDeviceId << std::endl;
+
+    return true;
+}
+
+// print usage/help list of commands (non-gtest)
+void TestSettings::PrintUsage() {
+    std::cerr << "Usage: " << mArgv[0] << " [OPTIONS]" << std::endl;
+    std::cerr << std::endl;
+
+    std::cerr << "Main modes of operation:"
+              << std::endl;
+    std::cerr << "   --forking-disabled[=1]  don't fork process before "
+              << std::endl
+              << "                           running a new test."
+              << std::endl
+              << "                           (default enabled)"
+              << std::endl;
+    std::cerr << "   --device-id=ID          specify a different camera ID"
+              << std::endl
+              << "                           (default 0)"
+              << std::endl;
+
+    std::cerr << "   -h, --help              print this help listing"
+              << std::endl;
+
+
+    std::cerr << std::endl;
+}
+
+}
+}
+}
+
diff --git a/tests/camera2/TestSettings.h b/tests/camera2/TestSettings.h
new file mode 100644
index 0000000..6164de5
--- /dev/null
+++ b/tests/camera2/TestSettings.h
@@ -0,0 +1,56 @@
+/*
+:qa
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_HAL_CAMERA2_TESTS_SETTINGS__
+#define __ANDROID_HAL_CAMERA2_TESTS_SETTINGS__
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+class TestSettings {
+
+public:
+    // --forking-disabled, false by default
+    static bool ForkingDisabled();
+
+    // reverse of --forking-disabled (not a flag), true by default
+    static bool ForkingEnabled();
+
+    // --device-id, 0 by default
+    static int DeviceId();
+
+    // returns false if usage should be printed and we should exit early
+    static bool ParseArgs(int argc, char* const argv[]);
+
+    // print usage/help list of commands (non-gtest)
+    static void PrintUsage();
+
+private:
+    TestSettings();
+    ~TestSettings();
+
+    static bool mForkingDisabled;
+    static int  mDeviceId;
+    static char* const* mArgv;
+};
+
+}
+}
+}
+
+#endif
diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp
index f43513e..3580b9b 100644
--- a/tests/camera2/camera2.cpp
+++ b/tests/camera2/camera2.cpp
@@ -15,7 +15,7 @@
  */
 
 #define LOG_TAG "Camera2_test"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
 #include <gtest/gtest.h>
@@ -28,12 +28,15 @@
 #include <system/camera_metadata.h>
 
 #include "camera2_utils.h"
+#include "TestExtensions.h"
 
 namespace android {
+namespace camera2 {
+namespace tests {
 
 class Camera2Test: public testing::Test {
   public:
-    static void SetUpTestCase() {
+    void SetUpModule() {
         int res;
 
         hw_module_t *module = NULL;
@@ -103,6 +106,11 @@
         }
     }
 
+    void TearDownModule() {
+        hw_module_t *module = reinterpret_cast<hw_module_t*>(sCameraModule);
+        ASSERT_EQ(0, HWModuleHelpers::closeModule(module));
+    }
+
     static const camera_module_t *getCameraModule() {
         return sCameraModule;
     }
@@ -275,21 +283,51 @@
         *count = availableSizes.count;
     }
 
+    status_t waitUntilDrained() {
+        static const uint32_t kSleepTime = 50000; // 50 ms
+        static const uint32_t kMaxSleepTime = 10000000; // 10 s
+        ALOGV("%s: Camera %d: Starting wait", __FUNCTION__, mId);
+
+        // TODO: Set up notifications from HAL, instead of sleeping here
+        uint32_t totalTime = 0;
+        while (mDevice->ops->get_in_progress_count(mDevice) > 0) {
+            usleep(kSleepTime);
+            totalTime += kSleepTime;
+            if (totalTime > kMaxSleepTime) {
+                ALOGE("%s: Waited %d us, %d requests still in flight", __FUNCTION__,
+                        mDevice->ops->get_in_progress_count(mDevice), totalTime);
+                return TIMED_OUT;
+            }
+        }
+        ALOGV("%s: Camera %d: HAL is idle", __FUNCTION__, mId);
+        return OK;
+    }
+
     virtual void SetUp() {
+        TEST_EXTENSION_FORKING_SET_UP;
+
+        SetUpModule();
+
         const ::testing::TestInfo* const testInfo =
                 ::testing::UnitTest::GetInstance()->current_test_info();
+        (void)testInfo;
 
-        ALOGV("*** Starting test %s in test case %s", testInfo->name(), testInfo->test_case_name());
+        ALOGV("*** Starting test %s in test case %s", testInfo->name(),
+              testInfo->test_case_name());
         mDevice = NULL;
     }
 
     virtual void TearDown() {
+        TEST_EXTENSION_FORKING_TEAR_DOWN;
+
         for (unsigned int i = 0; i < mStreams.size(); i++) {
             delete mStreams[i];
         }
         if (mDevice != NULL) {
             closeCameraDevice(mDevice);
         }
+
+        TearDownModule();
     }
 
     camera2_device    *mDevice;
@@ -317,6 +355,9 @@
 
 
 TEST_F(Camera2Test, OpenClose) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
     status_t res;
 
     for (int id = 0; id < getNumCameras(); id++) {
@@ -331,6 +372,9 @@
 }
 
 TEST_F(Camera2Test, Capture1Raw) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
     status_t res;
 
     for (int id = 0; id < getNumCameras(); id++) {
@@ -384,6 +428,10 @@
         add_camera_metadata_entry(request,
                 ANDROID_SENSOR_SENSITIVITY,
                 (void**)&sensitivity, 1);
+        uint8_t requestType = ANDROID_REQUEST_TYPE_CAPTURE;
+        add_camera_metadata_entry(request,
+                ANDROID_REQUEST_TYPE,
+                (void**)&requestType, 1);
 
         uint32_t hourOfDay = 12;
         add_camera_metadata_entry(request,
@@ -436,6 +484,7 @@
         res = rawConsumer->unlockBuffer(buffer);
         ASSERT_EQ(NO_ERROR, res);
 
+        ASSERT_EQ(OK, waitUntilDrained());
         ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId));
 
         res = closeCameraDevice(mDevice);
@@ -445,6 +494,9 @@
 }
 
 TEST_F(Camera2Test, CaptureBurstRaw) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
     status_t res;
 
     for (int id = 0; id < getNumCameras(); id++) {
@@ -494,6 +546,10 @@
         add_camera_metadata_entry(request,
                 ANDROID_SENSOR_SENSITIVITY,
                 (void**)&sensitivity, 1);
+        uint8_t requestType = ANDROID_REQUEST_TYPE_CAPTURE;
+        add_camera_metadata_entry(request,
+                ANDROID_REQUEST_TYPE,
+                (void**)&requestType, 1);
 
         uint32_t hourOfDay = 12;
         add_camera_metadata_entry(request,
@@ -577,6 +633,9 @@
 }
 
 TEST_F(Camera2Test, ConstructDefaultRequests) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
     status_t res;
 
     for (int id = 0; id < getNumCameras(); id++) {
@@ -660,6 +719,10 @@
         add_camera_metadata_entry(request,
                 ANDROID_SENSOR_SENSITIVITY,
                 (void**)&sensitivity, 1);
+        uint8_t requestType = ANDROID_REQUEST_TYPE_CAPTURE;
+        add_camera_metadata_entry(request,
+                ANDROID_REQUEST_TYPE,
+                (void**)&requestType, 1);
 
         uint32_t hourOfDay = 12;
         add_camera_metadata_entry(request,
@@ -712,6 +775,7 @@
         res = jpegConsumer->unlockBuffer(buffer);
         ASSERT_EQ(NO_ERROR, res);
 
+        ASSERT_EQ(OK, waitUntilDrained());
         ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId));
 
         res = closeCameraDevice(mDevice);
@@ -720,5 +784,6 @@
     }
 }
 
-
+} // namespace tests
+} // namespace camera2
 } // namespace android
diff --git a/tests/camera2/camera2_utils.cpp b/tests/camera2/camera2_utils.cpp
index cefe29a..166ac52 100644
--- a/tests/camera2/camera2_utils.cpp
+++ b/tests/camera2/camera2_utils.cpp
@@ -21,8 +21,11 @@
 
 #include "utils/Log.h"
 #include "camera2_utils.h"
+#include <dlfcn.h>
 
 namespace android {
+namespace camera2 {
+namespace tests {
 
 /**
  * MetadataQueue
@@ -578,4 +581,22 @@
     mCondition.signal();
 }
 
+int HWModuleHelpers::closeModule(hw_module_t* module) {
+    int status;
+
+    if (!module) {
+        return -EINVAL;
+    }
+
+    status = dlclose(module->dso);
+    if (status != 0) {
+        char const *err_str = dlerror();
+        ALOGE("%s dlclose failed, error: %s", __func__, err_str ?: "unknown");
+    }
+
+    return status;
+}
+
+} // namespace tests
+} // namespace camera2
 } // namespace android
diff --git a/tests/camera2/camera2_utils.h b/tests/camera2/camera2_utils.h
index 7822f5b..757044b 100644
--- a/tests/camera2/camera2_utils.h
+++ b/tests/camera2/camera2_utils.h
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#ifndef __ANDROID_HAL_CAMERA2_TESTS_UTILS__
+#define __ANDROID_HAL_CAMERA2_TESTS_UTILS__
+
 // Utility classes for camera2 HAL testing
 
 #include <system/camera_metadata.h>
@@ -27,6 +30,8 @@
 #include <utils/Condition.h>
 
 namespace android {
+namespace camera2 {
+namespace tests {
 
 /**
  * Queue class for both sending requests to a camera2 device, and for receiving
@@ -233,4 +238,13 @@
     Condition mCondition;
 };
 
+struct HWModuleHelpers {
+    /* attempt to unload the library with dlclose */
+    static int closeModule(hw_module_t* module);
+};
+
 }
+}
+}
+
+#endif
diff --git a/tests/camera2/main.cpp b/tests/camera2/main.cpp
new file mode 100644
index 0000000..e0ebbe9
--- /dev/null
+++ b/tests/camera2/main.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include "TestForkerEventListener.h"
+#include "TestSettings.h"
+
+using android::camera2::tests::TestForkerEventListener;
+using android::camera2::tests::TestSettings;
+
+int main(int argc, char **argv) {
+
+    bool printUsage = !TestSettings::ParseArgs(argc, argv);
+
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (printUsage) {
+        TestSettings::PrintUsage();
+        return 0;
+    }
+
+    // Gets hold of the event listener list.
+    ::testing::TestEventListeners& listeners =
+        ::testing::UnitTest::GetInstance()->listeners();
+    // Adds a listener to the end.  Google Test takes the ownership.
+    listeners.Append(new TestForkerEventListener());
+
+    int ret = RUN_ALL_TESTS();
+
+    return ret;
+}