Simplify EVS HAL and move to "agressive opens"

This adapts the API implementation to allow a duplicate "open" operation
to automatically close any previous connections to the device.  This
works around a binder level issue that can cause destructors triggered
by remote clients to be delivered out of order to the server.

This was originally change ag/1969959 on master, but has been
recreated on oc-dev (cherry-picking was broken at the time).
The original master change will be abandoned in favor of this getting
merged down from oc-dev.

Test:  Run Vts test (added in following change)
Change-Id: I7b417998e59a4d592fbb91811c4101f39097c5dd
diff --git a/automotive/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal
index 1b55d1f..dbcaf92 100644
--- a/automotive/evs/1.0/IEvsCamera.hal
+++ b/automotive/evs/1.0/IEvsCamera.hal
@@ -28,10 +28,10 @@
     /**
      * Returns the ID of this camera.
      *
-     * Returns the string id of this camera. This must be the same value as reported in
-     * the camera_id field of the CameraDesc structure by EvsEnumerator::getCamerList().
+     * Returns the description of this camera. This must be the same value as reported
+     * by EvsEnumerator::getCamerList().
      */
-    getId() generates (string cameraId);
+    getCameraInfo() generates (CameraDesc info);
 
     /**
      * Specifies the depth of the buffer chain the camera is asked to support.
diff --git a/automotive/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal
index bbad428..12541f3 100644
--- a/automotive/evs/1.0/IEvsDisplay.hal
+++ b/automotive/evs/1.0/IEvsDisplay.hal
@@ -27,7 +27,7 @@
     /**
      * Returns basic information about the EVS display provided by the system.
      *
-     * See the description of the DisplayDesc structure below for details.
+     * See the description of the DisplayDesc structure for details.
      */
      getDisplayInfo() generates (DisplayDesc info);
 
diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal
index 334430b..98d117a 100644
--- a/automotive/evs/1.0/IEvsEnumerator.hal
+++ b/automotive/evs/1.0/IEvsEnumerator.hal
@@ -31,14 +31,14 @@
      */
     getCameraList() generates (vec<CameraDesc> cameras);
 
-
     /**
      * Get the IEvsCamera associated with a cameraId from a CameraDesc
      *
      * Given a camera's unique cameraId from ca CameraDesc, returns
-     * the ICamera interface assocaited with the specified camera.
-     * When done using the camera, it must be returned by calling
-     * closeCamera on the ICamera interface.
+     * the ICamera interface associated with the specified camera.
+     * When done using the camera, the caller may release it by calling closeCamera().
+     * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the
+     * resources may not be released right away due to asynchronos behavior in the hardware binder.
      */
     openCamera(string cameraId) generates (IEvsCamera carCamera);
 
@@ -57,6 +57,9 @@
      * There can be at most one EVS display object for the system and this function
      * requests access to it. If the EVS display is not available or is already in use,
      * a null pointer is returned.
+     * When done using the display, the caller may release it by calling closeDisplay().
+     * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the
+     * resources may not be released right away due to asynchronos behavior in the hardware binder.
      */
     openDisplay() generates (IEvsDisplay display);
 
@@ -64,7 +67,7 @@
      * Return the specified IEvsDisplay interface as no longer in use
      *
      * When the IEvsDisplay object is no longer required, it must be released.
-     * NOTE: All buffer must have been returned to the display before making this call.
+     * NOTE: All buffers must have been returned to the display before making this call.
      */
     closeDisplay(IEvsDisplay display);
 
diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp
index 8b214e3..2574e86 100644
--- a/automotive/evs/1.0/default/Android.bp
+++ b/automotive/evs/1.0/default/Android.bp
@@ -23,4 +23,9 @@
         "liblog",
         "libutils",
     ],
+
+    cflags: [
+        "-O0",
+        "-g",
+    ],
 }
diff --git a/automotive/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp
index c4436ee..148b796 100644
--- a/automotive/evs/1.0/default/EvsCamera.cpp
+++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "android.hardware.automotive.evs@1.0-service"
 
 #include "EvsCamera.h"
+#include "EvsEnumerator.h"
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
@@ -30,18 +31,15 @@
 namespace implementation {
 
 
-// These are the special camera names for which we'll initialize custom test data
+// Special camera names for which we'll initialize alternate test data
 const char EvsCamera::kCameraName_Backup[]    = "backup";
-const char EvsCamera::kCameraName_RightTurn[] = "Right Turn";
+
 
 // Arbitrary limit on number of graphics buffers allowed to be allocated
 // Safeguards against unreasonable resource consumption and provides a testable limit
 const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
 
 
-// TODO(b/31632518):  Need to get notification when our client dies so we can close the camera.
-// As it stands, if the client dies suddenly, the buffer may be stranded.
-
 EvsCamera::EvsCamera(const char *id) :
         mFramesAllowed(0),
         mFramesInUse(0),
@@ -53,22 +51,14 @@
 
     // Set up dummy data for testing
     if (mDescription.cameraId == kCameraName_Backup) {
-        mDescription.hints                  = static_cast<uint32_t>(UsageHint::USAGE_HINT_REVERSE);
-        mDescription.vendorFlags            = 0xFFFFFFFF;   // Arbitrary value
-        mDescription.defaultHorResolution   = 320;          // 1/2 NTSC/VGA
-        mDescription.defaultVerResolution   = 240;          // 1/2 NTSC/VGA
-    } else if (mDescription.cameraId == kCameraName_RightTurn) {
-        // Nothing but the name and the usage hint
-        mDescription.hints                  = static_cast<uint32_t>(UsageHint::USAGE_HINT_RIGHT_TURN);
+        mWidth  = 640;          // full NTSC/VGA
+        mHeight = 480;          // full NTSC/VGA
+        mDescription.vendorFlags = 0xFFFFFFFF;   // Arbitrary value
     } else {
-        // Leave empty for a minimalist camera description without even a hint
+        mWidth  = 320;          // 1/2 NTSC/VGA
+        mHeight = 240;          // 1/2 NTSC/VGA
     }
 
-
-    // Set our buffer properties
-    mWidth  = (mDescription.defaultHorResolution) ? mDescription.defaultHorResolution : 640;
-    mHeight = (mDescription.defaultVerResolution) ? mDescription.defaultVerResolution : 480;
-
     mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
     mUsage  = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
               GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
@@ -77,32 +67,49 @@
 
 EvsCamera::~EvsCamera() {
     ALOGD("EvsCamera being destroyed");
-    std::lock_guard<std::mutex> lock(mAccessLock);
+    forceShutdown();
+}
+
+
+//
+// This gets called if another caller "steals" ownership of the camera
+//
+void EvsCamera::forceShutdown()
+{
+    ALOGD("EvsCamera forceShutdown");
 
     // Make sure our output stream is cleaned up
     // (It really should be already)
     stopVideoStream();
 
+    // Claim the lock while we work on internal state
+    std::lock_guard <std::mutex> lock(mAccessLock);
+
     // Drop all the graphics buffers we've been using
-    GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
-    for (auto&& rec : mBuffers) {
-        if (rec.inUse) {
-            ALOGE("Error - releasing buffer despite remote ownership");
+    if (mBuffers.size() > 0) {
+        GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+        for (auto&& rec : mBuffers) {
+            if (rec.inUse) {
+                ALOGE("Error - releasing buffer despite remote ownership");
+            }
+            alloc.free(rec.handle);
+            rec.handle = nullptr;
         }
-        alloc.free(rec.handle);
-        rec.handle = nullptr;
+        mBuffers.clear();
     }
 
-    ALOGD("EvsCamera destroyed");
+    // Put this object into an unrecoverable error state since somebody else
+    // is going to own the underlying camera now
+    mStreamState = DEAD;
 }
 
 
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
-Return<void> EvsCamera::getId(getId_cb id_cb) {
-    ALOGD("getId");
+Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
+    ALOGD("getCameraInfo");
 
-    id_cb(mDescription.cameraId);
-
+    // Send back our self description
+    _hidl_cb(mDescription);
     return Void();
 }
 
@@ -111,6 +118,12 @@
     ALOGD("setMaxFramesInFlight");
     std::lock_guard<std::mutex> lock(mAccessLock);
 
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (mStreamState == DEAD) {
+        ALOGE("ignoring setMaxFramesInFlight call when camera has been lost.");
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
     // We cannot function without at least one video buffer to send data
     if (bufferCount < 1) {
         ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
@@ -130,6 +143,11 @@
     ALOGD("startVideoStream");
     std::lock_guard<std::mutex> lock(mAccessLock);
 
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (mStreamState == DEAD) {
+        ALOGE("ignoring startVideoStream call when camera has been lost.");
+        return EvsResult::OWNERSHIP_LOST;
+    }
     if (mStreamState != STOPPED) {
         ALOGE("ignoring startVideoStream call when a stream is already running.");
         return EvsResult::STREAM_ALREADY_RUNNING;
@@ -207,6 +225,7 @@
         lock.lock();
 
         mStreamState = STOPPED;
+        mStream = nullptr;
         ALOGD("Stream marked STOPPED.");
     }
 
@@ -232,6 +251,12 @@
     ALOGD("setExtendedInfo");
     std::lock_guard<std::mutex> lock(mAccessLock);
 
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (mStreamState == DEAD) {
+        ALOGE("ignoring setExtendedInfo call when camera has been lost.");
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
     // We don't store any device specific information in this implementation
     return EvsResult::INVALID_ARG;
 }
@@ -358,7 +383,9 @@
 
     while (true) {
         bool timeForFrame = false;
-        // Lock scope
+        nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Lock scope for updating shared state
         {
             std::lock_guard<std::mutex> lock(mAccessLock);
 
@@ -427,8 +454,15 @@
             }
         }
 
-        // We arbitrarily choose to generate frames at 10 fps (1/10 * uSecPerSec)
-        usleep(100000);
+        // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
+        static const int kTargetFrameRate = 12;
+        static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
+        const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        const nsecs_t workTimeUs = (now - startTime) / 1000;
+        const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
+        if (sleepDurationUs > 0) {
+            usleep(sleepDurationUs);
+        }
     }
 
     // If we've been asked to stop, send one last NULL frame to signal the actual end of stream
diff --git a/automotive/evs/1.0/default/EvsCamera.h b/automotive/evs/1.0/default/EvsCamera.h
index ee91ca4..ff6eb39 100644
--- a/automotive/evs/1.0/default/EvsCamera.h
+++ b/automotive/evs/1.0/default/EvsCamera.h
@@ -32,54 +32,50 @@
 namespace implementation {
 
 
+// From EvsEnumerator.h
+class EvsEnumerator;
+
+
 class EvsCamera : public IEvsCamera {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
-    Return<void> getId(getId_cb id_cb) override;
-
+    Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb)  override;
     Return <EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
-
     Return <EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream>& stream) override;
-
     Return<void> doneWithFrame(const BufferDesc& buffer) override;
-
     Return<void> stopVideoStream() override;
-
     Return <int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
-
     Return <EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
 
     // Implementation details
-    EvsCamera(const char* id);
-
+    EvsCamera(const char *id);
     virtual ~EvsCamera() override;
+    void forceShutdown();   // This gets called if another caller "steals" ownership of the camera
 
     const CameraDesc& getDesc() { return mDescription; };
 
     static const char kCameraName_Backup[];
-    static const char kCameraName_RightTurn[];
 
 private:
     // These three functions are expected to be called while mAccessLock is held
     bool setAvailableFrames_Locked(unsigned bufferCount);
-
     unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
-
     unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
 
     void generateFrames();
-
     void fillTestFrame(const BufferDesc& buff);
 
-    CameraDesc mDescription = {};  // The properties of this camera
+    sp<EvsEnumerator> mEnumerator;  // The enumerator object that created this camera
+
+    CameraDesc mDescription = {};   // The properties of this camera
 
     std::thread mCaptureThread;     // The thread we'll use to synthesize frames
 
-    uint32_t mWidth = 0;        // Horizontal pixel count in the buffers
-    uint32_t mHeight = 0;        // Vertical pixel count in the buffers
-    uint32_t mFormat = 0;        // Values from android_pixel_format_t [TODO: YUV?  Leave opaque?]
-    uint32_t mUsage = 0;        // Values from from Gralloc.h
-    uint32_t mStride = 0;        // Bytes per line in the buffers
+    uint32_t mWidth  = 0;       // Horizontal pixel count in the buffers
+    uint32_t mHeight = 0;       // Vertical pixel count in the buffers
+    uint32_t mFormat = 0;       // Values from android_pixel_format_t [TODO: YUV?  Leave opaque?]
+    uint32_t mUsage  = 0;       // Values from from Gralloc.h
+    uint32_t mStride = 0;       // Bytes per line in the buffers
 
     sp <IEvsCameraStream> mStream = nullptr;  // The callback used to deliver each frame
 
@@ -98,10 +94,11 @@
         STOPPED,
         RUNNING,
         STOPPING,
+        DEAD,
     };
     StreamStateValues mStreamState;
 
-    // Syncrhonization necessary to deconflict mCaptureThread from the main service thread
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
     std::mutex mAccessLock;
 };
 
diff --git a/automotive/evs/1.0/default/EvsDisplay.cpp b/automotive/evs/1.0/default/EvsDisplay.cpp
index a1a76d0..9ad332a 100644
--- a/automotive/evs/1.0/default/EvsDisplay.cpp
+++ b/automotive/evs/1.0/default/EvsDisplay.cpp
@@ -30,12 +30,6 @@
 namespace implementation {
 
 
-// TODO(b/31632518):  Need to get notification when our client dies so we can close the camera.
-// As it stands, if the client dies suddently, the buffer may be stranded.
-// As possible work around would be to give the client a HIDL object to exclusively hold
-// and use it's destructor to perform some work in the server side.
-
-
 EvsDisplay::EvsDisplay() {
     ALOGD("EvsDisplay instantiated");
 
@@ -43,34 +37,55 @@
     // NOTE:  These are arbitrary values chosen for testing
     mInfo.displayId             = "Mock Display";
     mInfo.vendorFlags           = 3870;
-    mInfo.defaultHorResolution  = 320;
-    mInfo.defaultVerResolution  = 240;
+
+    // Assemble the buffer description we'll use for our render target
+    mBuffer.width       = 320;
+    mBuffer.height      = 240;
+    mBuffer.format      = HAL_PIXEL_FORMAT_RGBA_8888;
+    mBuffer.usage       = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
+    mBuffer.bufferId    = 0x3870;  // Arbitrary magic number for self recognition
+    mBuffer.pixelSize   = 4;
 }
 
 
 EvsDisplay::~EvsDisplay() {
     ALOGD("EvsDisplay being destroyed");
+    forceShutdown();
+}
+
+
+/**
+ * This gets called if another caller "steals" ownership of the display
+ */
+void EvsDisplay::forceShutdown()
+{
+    ALOGD("EvsDisplay forceShutdown");
     std::lock_guard<std::mutex> lock(mAccessLock);
 
-    // Report if we're going away while a buffer is outstanding
-    if (mFrameBusy) {
-        ALOGE("EvsDisplay going down while client is holding a buffer");
-    }
-
-    // Make sure we release our frame buffer
+    // If the buffer isn't being held by a remote client, release it now as an
+    // optimization to release the resources more quickly than the destructor might
+    // get called.
     if (mBuffer.memHandle) {
+        // Report if we're going away while a buffer is outstanding
+        if (mFrameBusy) {
+            ALOGE("EvsDisplay going down while client is holding a buffer");
+        }
+
         // Drop the graphics buffer we've been using
         GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
         alloc.free(mBuffer.memHandle);
         mBuffer.memHandle = nullptr;
     }
-    ALOGD("EvsDisplay destroyed");
+
+    // Put this object into an unrecoverable error state since somebody else
+    // is going to own the display now.
+    mRequestedState = DisplayState::DEAD;
 }
 
 
 /**
  * Returns basic information about the EVS display provided by the system.
- * See the description of the DisplayDesc structure below for details.
+ * See the description of the DisplayDesc structure for details.
  */
 Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb)  {
     ALOGD("getDisplayInfo");
@@ -94,6 +109,11 @@
     ALOGD("setDisplayState");
     std::lock_guard<std::mutex> lock(mAccessLock);
 
+    if (mRequestedState == DisplayState::DEAD) {
+        // This object no longer owns the display -- it's been superceeded!
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
     // Ensure we recognize the requested state so we don't go off the rails
     if (state < DisplayState::NUM_STATES) {
         // Record the requested state
@@ -119,10 +139,7 @@
     ALOGD("getDisplayState");
     std::lock_guard<std::mutex> lock(mAccessLock);
 
-    // At the moment, we treat the requested state as immediately active
-    DisplayState currentState = mRequestedState;
-
-    return currentState;
+    return mRequestedState;
 }
 
 
@@ -137,15 +154,16 @@
     ALOGD("getTargetBuffer");
     std::lock_guard<std::mutex> lock(mAccessLock);
 
+    if (mRequestedState == DisplayState::DEAD) {
+        ALOGE("Rejecting buffer request from object that lost ownership of the display.");
+        BufferDesc nullBuff = {};
+        _hidl_cb(nullBuff);
+        return Void();
+    }
+
     // If we don't already have a buffer, allocate one now
     if (!mBuffer.memHandle) {
-        // Assemble the buffer description we'll use for our render target
-        mBuffer.width       = mInfo.defaultHorResolution;
-        mBuffer.height      = mInfo.defaultVerResolution;
-        mBuffer.format      = HAL_PIXEL_FORMAT_RGBA_8888;
-        mBuffer.usage       = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
-        mBuffer.bufferId    = 0x3870;  // Arbitrary magic number for self recognition
-
+        // Allocate the buffer that will hold our displayable image
         buffer_handle_t handle = nullptr;
         GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
         status_t result = alloc.allocate(mBuffer.width, mBuffer.height,
@@ -220,6 +238,11 @@
 
     mFrameBusy = false;
 
+    // If we've been displaced by another owner of the display, then we can't do anything else
+    if (mRequestedState == DisplayState::DEAD) {
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
     // If we were waiting for a new frame, this is it!
     if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
         mRequestedState = DisplayState::VISIBLE;
@@ -248,8 +271,8 @@
 
         // Check the test pixels
         bool frameLooksGood = true;
-        for (unsigned row = 0; row < mInfo.defaultVerResolution; row++) {
-            for (unsigned col = 0; col < mInfo.defaultHorResolution; col++) {
+        for (unsigned row = 0; row < mBuffer.height; row++) {
+            for (unsigned col = 0; col < mBuffer.width; col++) {
                 // Index into the row to check the pixel at this column.
                 // We expect 0xFF in the LSB channel, a vertical gradient in the
                 // second channel, a horitzontal gradient in the third channel, and
diff --git a/automotive/evs/1.0/default/EvsDisplay.h b/automotive/evs/1.0/default/EvsDisplay.h
index fcf4a06..ebd6446 100644
--- a/automotive/evs/1.0/default/EvsDisplay.h
+++ b/automotive/evs/1.0/default/EvsDisplay.h
@@ -27,6 +27,7 @@
 namespace V1_0 {
 namespace implementation {
 
+
 class EvsDisplay : public IEvsDisplay {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
@@ -40,6 +41,8 @@
     EvsDisplay();
     virtual ~EvsDisplay() override;
 
+    void forceShutdown();   // This gets called if another caller "steals" ownership of the display
+
 private:
     DisplayDesc     mInfo           = {};
     BufferDesc      mBuffer         = {};       // A graphics buffer into which we'll store images
diff --git a/automotive/evs/1.0/default/EvsEnumerator.cpp b/automotive/evs/1.0/default/EvsEnumerator.cpp
index e54f699..731e21b 100644
--- a/automotive/evs/1.0/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.0/default/EvsEnumerator.cpp
@@ -28,33 +28,36 @@
 namespace implementation {
 
 
-// TODO(b/31632518):  Need to get notification when our client dies so we can close the camera.
-// As it stands, if the client dies suddenly, the camera will be stuck "open".
-// NOTE:  Display should already be safe by virtue of holding only a weak pointer.
+// NOTE:  All members values are static so that all clients operate on the same state
+//        That is to say, this is effectively a singleton despite the fact that HIDL
+//        constructs a new instance for each client.
+std::list<EvsEnumerator::CameraRecord>   EvsEnumerator::sCameraList;
+wp<EvsDisplay>                           EvsEnumerator::sActiveDisplay;
 
 
 EvsEnumerator::EvsEnumerator() {
     ALOGD("EvsEnumerator created");
 
     // Add sample camera data to our list of cameras
-    // NOTE:  The id strings trigger special initialization inside the EvsCamera constructor
-    mCameraList.emplace_back( new EvsCamera(EvsCamera::kCameraName_Backup),    false );
-    mCameraList.emplace_back( new EvsCamera("LaneView"),                       false );
-    mCameraList.emplace_back( new EvsCamera(EvsCamera::kCameraName_RightTurn), false );
+    // In a real driver, this would be expected to can the available hardware
+    sCameraList.emplace_back(EvsCamera::kCameraName_Backup);
+    sCameraList.emplace_back("LaneView");
+    sCameraList.emplace_back("right turn");
 }
 
+
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
 Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb)  {
     ALOGD("getCameraList");
 
-    const unsigned numCameras = mCameraList.size();
+    const unsigned numCameras = sCameraList.size();
 
     // Build up a packed array of CameraDesc for return
     // NOTE:  Only has to live until the callback returns
     std::vector<CameraDesc> descriptions;
     descriptions.reserve(numCameras);
-    for (const auto& cam : mCameraList) {
-        descriptions.push_back( cam.pCamera->getDesc() );
+    for (const auto& cam : sCameraList) {
+        descriptions.push_back( cam.desc );
     }
 
     // Encapsulate our camera descriptions in the HIDL vec type
@@ -68,97 +71,137 @@
     return Void();
 }
 
+
 Return<sp<IEvsCamera>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
     ALOGD("openCamera");
 
     // Find the named camera
     CameraRecord *pRecord = nullptr;
-    for (auto &&cam : mCameraList) {
-        if (cam.pCamera->getDesc().cameraId == cameraId) {
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.cameraId == cameraId) {
             // Found a match!
             pRecord = &cam;
             break;
         }
     }
 
+    // Is this a recognized camera id?
     if (!pRecord) {
         ALOGE("Requested camera %s not found", cameraId.c_str());
         return nullptr;
-    } else if (pRecord->inUse) {
-        ALOGE("Cannot open camera %s which is already in use", cameraId.c_str());
-        return nullptr;
-    } else {
-        pRecord->inUse = true;
-        return(pRecord->pCamera);
     }
+
+    // Has this camera already been instantiated by another caller?
+    sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+    if (pActiveCamera != nullptr) {
+        ALOGW("Killing previous camera because of new caller");
+        closeCamera(pActiveCamera);
+    }
+
+    // Construct a camera instance for the caller
+    pActiveCamera = new EvsCamera(cameraId);
+    pRecord->activeInstance = pActiveCamera;
+    if (pActiveCamera == nullptr) {
+        ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+    }
+
+    return pActiveCamera;
 }
 
-Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& camera) {
+
+Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& pCamera) {
     ALOGD("closeCamera");
 
-    if (camera == nullptr) {
-        ALOGE("Ignoring call to closeCamera with null camera pointer");
-    } else {
-        // Find this camera in our list
-        auto it = std::find_if(mCameraList.begin(),
-                               mCameraList.end(),
-                               [camera](const CameraRecord& rec) {
-                                   return (rec.pCamera == camera);
-                               });
-        if (it == mCameraList.end()) {
-            ALOGE("Ignoring close on unrecognized camera");
-        } else {
-            // Make sure the camera has stopped streaming
-            camera->stopVideoStream();
+    if (pCamera == nullptr) {
+        ALOGE("Ignoring call to closeCamera with null camera ptr");
+        return Void();
+    }
 
-            it->inUse = false;
+    // Get the camera id so we can find it in our list
+    std::string cameraId;
+    pCamera->getCameraInfo([&cameraId](CameraDesc desc) {
+// TODO(b/36532780) Should we able to just use a simple assignment?
+//                             cameraId = desc.cameraId;
+                               cameraId.assign(desc.cameraId.c_str());
+                           }
+    );
+
+    // Find the named camera
+    CameraRecord *pRecord = nullptr;
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.cameraId == cameraId) {
+            // Found a match!
+            pRecord = &cam;
+            break;
+        }
+    }
+
+    // Is the display being destroyed actually the one we think is active?
+    if (!pRecord) {
+        ALOGE("Asked to close a camera who's name isn't recognized");
+    } else {
+        sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+
+        if (pActiveCamera == nullptr) {
+            ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed");
+        } else if (pActiveCamera != pCamera) {
+            // This can happen if the camera was aggressively reopened, orphaning this previous instance
+            ALOGW("Ignoring close of previously orphaned camera - why did a client steal?");
+        } else {
+            // Drop the active camera
+            pActiveCamera->forceShutdown();
+            pRecord->activeInstance = nullptr;
         }
     }
 
     return Void();
 }
 
+
 Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
     ALOGD("openDisplay");
 
-    // If we already have a display active, then this request must be denied
-    sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote();
+    // If we already have a display active, then we need to shut it down so we can
+    // give exclusive access to the new caller.
+    sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
     if (pActiveDisplay != nullptr) {
-        ALOGW("Rejecting openDisplay request the display is already in use.");
-        return nullptr;
-    } else {
-        // Create a new display interface and return it
-        pActiveDisplay = new EvsDisplay();
-        mActiveDisplay = pActiveDisplay;
-        ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
-        return pActiveDisplay;
+        ALOGW("Killing previous display because of new caller");
+        closeDisplay(pActiveDisplay);
     }
+
+    // Create a new display interface and return it
+    pActiveDisplay = new EvsDisplay();
+    sActiveDisplay = pActiveDisplay;
+
+    ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
+    return pActiveDisplay;
 }
 
-Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& display) {
+
+Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& pDisplay) {
     ALOGD("closeDisplay");
 
     // Do we still have a display object we think should be active?
-    sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote();
-
+    sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
     if (pActiveDisplay == nullptr) {
-        ALOGE("Ignoring closeDisplay when there is no active display.");
-    } else if (display != pActiveDisplay) {
-        ALOGE("Ignoring closeDisplay on a display we didn't issue");
-        ALOGI("Got %p while active display is %p.", display.get(), pActiveDisplay.get());
+        ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed");
+    } else if (sActiveDisplay != pDisplay) {
+        ALOGW("Ignoring close of previously orphaned display - why did a client steal?");
     } else {
         // Drop the active display
-        mActiveDisplay = nullptr;
+        pActiveDisplay->forceShutdown();
+        sActiveDisplay = nullptr;
     }
 
     return Void();
 }
 
+
 Return<DisplayState> EvsEnumerator::getDisplayState()  {
     ALOGD("getDisplayState");
 
     // Do we still have a display object we think should be active?
-    sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote();
+    sp<IEvsDisplay> pActiveDisplay = sActiveDisplay.promote();
     if (pActiveDisplay != nullptr) {
         return pActiveDisplay->getDisplayState();
     } else {
diff --git a/automotive/evs/1.0/default/EvsEnumerator.h b/automotive/evs/1.0/default/EvsEnumerator.h
index 3d6e264..6b70f9b 100644
--- a/automotive/evs/1.0/default/EvsEnumerator.h
+++ b/automotive/evs/1.0/default/EvsEnumerator.h
@@ -22,7 +22,6 @@
 
 #include <list>
 
-#include "EvsCamera.h"
 
 namespace android {
 namespace hardware {
@@ -31,6 +30,11 @@
 namespace V1_0 {
 namespace implementation {
 
+
+class EvsCamera;    // from EvsCamera.h
+class EvsDisplay;   // from EvsDisplay.h
+
+
 class EvsEnumerator : public IEvsEnumerator {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
@@ -45,14 +49,18 @@
     EvsEnumerator();
 
 private:
+    // NOTE:  All members values are static so that all clients operate on the same state
+    //        That is to say, this is effectively a singleton despite the fact that HIDL
+    //        constructs a new instance for each client.
     struct CameraRecord {
-        sp<EvsCamera>   pCamera;
-        bool            inUse;
-        CameraRecord(EvsCamera* p, bool b) : pCamera(p), inUse(b) {}
-    };
-    std::list<CameraRecord> mCameraList;
+        CameraDesc          desc;
+        wp<EvsCamera>       activeInstance;
 
-    wp<IEvsDisplay>         mActiveDisplay; // Weak pointer -> object destructs if client dies
+        CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; }
+    };
+    static std::list<CameraRecord> sCameraList;
+
+    static wp<EvsDisplay>          sActiveDisplay; // Weak pointer. Object destructs if client dies.
 };
 
 } // namespace implementation
diff --git a/automotive/evs/1.0/types.hal b/automotive/evs/1.0/types.hal
index 0ce39d1..7cebf6d 100644
--- a/automotive/evs/1.0/types.hal
+++ b/automotive/evs/1.0/types.hal
@@ -18,40 +18,14 @@
 
 
 /**
- * Bit flags indicating suggested uses for a given EVS camera
- *
- * The values in the UsageHint bit field provide a generic expression of how a
- * given camera is intended to be used. The values for these flags support
- * existing use cases, and are used by the default EVS application to select
- * appropriate cameras for display based on observed vehicle state (such as
- * turn signal activation or selection of reverse gear). When implementing
- * their own specialized EVS Applications, OEMs are free to use these flags
- * and/or the opaque vendor_flags to drive their own vehicle specific logic.
- */
-enum UsageHint : uint32_t {
-    USAGE_HINT_REVERSE      = 0x00000001,
-    USAGE_HINT_LEFT_TURN    = 0x00000002,
-    USAGE_HINT_RIGHT_TURN   = 0x00000004,
-};
-
-
-/**
  * Structure describing the basic properties of an EVS camera
  *
  * The HAL is responsible for filling out this structure for each
- * EVS camera in the system. Attention should be given to the field
- * of view, direction of view, and location parameters as these may
- * be used to (if available) to project overlay graphics into the
- * scene by an EVS application.
- * Any of these values for which the HAL does not have reasonable values
- * should be set to ZERO.
+ * EVS camera in the system.
  */
 struct CameraDesc {
-    string              cameraId;
-    bitfield<UsageHint> hints;                  // Mask of usage hints
-    uint32_t            vendorFlags;            // Opaque value from driver
-    uint32_t            defaultHorResolution;   // Units of pixels
-    uint32_t            defaultVerResolution;   // Units of pixels
+    string      cameraId;
+    uint32_t    vendorFlags;    // Opaque value from driver
 };
 
 
@@ -65,9 +39,7 @@
  */
 struct DisplayDesc {
     string      displayId;
-    uint32_t    vendorFlags;                // Opaque value from driver
-    uint32_t    defaultHorResolution;       // Units of pixels
-    uint32_t    defaultVerResolution;       // Units of pixels
+    uint32_t    vendorFlags;    // Opaque value from driver
 };
 
 
@@ -86,7 +58,8 @@
 struct BufferDesc {
     uint32_t    width;      // Units of pixels
     uint32_t    height;     // Units of pixels
-    uint32_t    stride;     // Units of bytes
+    uint32_t    stride;     // Units of pixels to match gralloc
+    uint32_t    pixelSize;  // Units of bytes
     uint32_t    format;     // May contain values from android_pixel_format_t
     uint32_t    usage;      // May contain values from from Gralloc.h
     uint32_t    bufferId;   // Opaque value from driver
@@ -108,6 +81,7 @@
     NOT_VISIBLE,            // Display is inhibited
     VISIBLE_ON_NEXT_FRAME,  // Will become visible with next frame
     VISIBLE,                // Display is currently active
+    DEAD,                   // Driver is in an undefined state.  Interface should be closed.
     NUM_STATES              // Must be last
 };
 
@@ -118,5 +92,6 @@
     INVALID_ARG,
     STREAM_ALREADY_RUNNING,
     BUFFER_NOT_AVAILABLE,
+    OWNERSHIP_LOST,
     UNDERLYING_SERVICE_ERROR,
 };