Merge "Remove BoardConfig variables - BOARD_EGL_CFG"
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index c6dfa37..0fc2bce 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -711,7 +711,8 @@
 }
 
 void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
-    std::vector<std::string> am = {"/system/bin/am", "broadcast", "--user", "0", "-a", action};
+    std::vector<std::string> am = {
+        "/system/bin/cmd", "activity", "broadcast", "--user", "0", "-a", action};
 
     am.insert(am.end(), args.begin(), args.end());
 
diff --git a/include/batteryservice/BatteryService.h b/include/batteryservice/BatteryService.h
index 30d7317..80ab7f3 100644
--- a/include/batteryservice/BatteryService.h
+++ b/include/batteryservice/BatteryService.h
@@ -26,13 +26,15 @@
 
 #include "BatteryServiceConstants.h"
 
-// must be kept in sync with definitions in BatteryProperty.java
+// must be kept in sync with definitions in
+// frameworks/base/core/java/android/os/BatteryManager.java
 enum {
-    BATTERY_PROP_CHARGE_COUNTER = 1, // equals BatteryProperty.CHARGE_COUNTER constant
-    BATTERY_PROP_CURRENT_NOW = 2, // equals BatteryProperty.CURRENT_NOW constant
-    BATTERY_PROP_CURRENT_AVG = 3, // equals BatteryProperty.CURRENT_AVG constant
-    BATTERY_PROP_CAPACITY = 4, // equals BatteryProperty.CAPACITY constant
-    BATTERY_PROP_ENERGY_COUNTER = 5, // equals BatteryProperty.ENERGY_COUNTER constant
+    BATTERY_PROP_CHARGE_COUNTER = 1, // equals BATTERY_PROPERTY_CHARGE_COUNTER
+    BATTERY_PROP_CURRENT_NOW = 2, // equals BATTERY_PROPERTY_CURRENT_NOW
+    BATTERY_PROP_CURRENT_AVG = 3, // equals BATTERY_PROPERTY_CURRENT_AVERAGE
+    BATTERY_PROP_CAPACITY = 4, // equals BATTERY_PROPERTY_CAPACITY
+    BATTERY_PROP_ENERGY_COUNTER = 5, // equals BATTERY_PROPERTY_ENERGY_COUNTER
+    BATTERY_PROP_BATTERY_STATUS = 6, // equals BATTERY_PROPERTY_BATTERY_STATUS
 };
 
 struct BatteryProperties {
diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h
index c5ead20..0da61ee 100644
--- a/include/binder/ProcessInfoService.h
+++ b/include/binder/ProcessInfoService.h
@@ -35,6 +35,8 @@
     ProcessInfoService();
 
     status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states);
+    status_t getProcessStatesScoresImpl(size_t length, /*in*/ int32_t* pids,
+            /*out*/ int32_t* states, /*out*/ int32_t *scores);
     void updateBinderLocked();
 
     static const int BINDER_ATTEMPT_LIMIT = 5;
@@ -55,6 +57,21 @@
                 /*out*/ states);
     }
 
+    /**
+     * For each PID in the given "pids" input array, write the current process state
+     * for that process into the "states" output array, or
+     * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID
+     * exists. OoM scores will also be written in the "scores" output array.
+     * Please also note that clients calling this method need to have
+     * "GET_PROCESS_STATE_AND_OOM_SCORE" permission.
+     *
+     * Returns NO_ERROR if this operation was successful, or a negative error code otherwise.
+     */
+    static status_t getProcessStatesScoresFromPids(size_t length, /*in*/ int32_t* pids,
+            /*out*/ int32_t* states, /*out*/ int32_t *scores) {
+        return ProcessInfoService::getInstance().getProcessStatesScoresImpl(
+                length, /*in*/ pids, /*out*/ states, /*out*/ scores);
+    }
 };
 
 // ----------------------------------------------------------------------
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index ab676cc..55637a9 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -17,9 +17,6 @@
 #ifndef ANDROID_GUI_BUFFERITEM_H
 #define ANDROID_GUI_BUFFERITEM_H
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
 #include <ui/FenceTime.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
index b19a1ac..9e18907 100644
--- a/include/gui/GraphicBufferAlloc.h
+++ b/include/gui/GraphicBufferAlloc.h
@@ -35,8 +35,8 @@
     virtual ~GraphicBufferAlloc();
     virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
             uint32_t height, PixelFormat format, uint32_t layerCount,
-            uint32_t usage, std::string requestorName,
-            status_t* error) override;
+            uint64_t producerUsage, uint64_t consumerUsage,
+            std::string requestorName, status_t* error) override;
 };
 
 
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
index 2a7690a..1e578cc 100644
--- a/include/gui/IGraphicBufferAlloc.h
+++ b/include/gui/IGraphicBufferAlloc.h
@@ -38,14 +38,29 @@
     /* Create a new GraphicBuffer for the client to use.
      */
     virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t layerCount, uint32_t usage,
-            std::string requestorName, status_t* error) = 0;
+            PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+            uint64_t consumerUsage, std::string requestorName,
+            status_t* error) = 0;
 
     sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
             PixelFormat format, uint32_t layerCount, uint32_t usage,
             status_t* error) {
-        return createGraphicBuffer(w, h, format, layerCount, usage, "<Unknown>",
-                error);
+        return createGraphicBuffer(w, h, format, layerCount, usage,
+                usage, "<Unknown>", error);
+    }
+
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t layerCount, uint32_t usage,
+            std::string requestorName, status_t* error) {
+        return createGraphicBuffer(w, h, format, layerCount, usage,
+                usage, requestorName, error);
+    }
+
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+            uint64_t consumerUsage, status_t* error) {
+        return createGraphicBuffer(w, h, format, layerCount, producerUsage,
+                consumerUsage, "<Unknown>", error);
     }
 };
 
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 8af4d46..9870ba0 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -28,9 +28,7 @@
 #include <binder/IInterface.h>
 
 #include <ui/FrameStats.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-#include <gui/ISurfaceComposerClient.h>
+#include <ui/PixelFormat.h>
 
 #include <vector>
 
@@ -43,7 +41,9 @@
 struct DisplayStatInfo;
 class HdrCapabilities;
 class IDisplayEventConnection;
-class IMemoryHeap;
+class IGraphicBufferAlloc;
+class IGraphicBufferProducer;
+class ISurfaceComposerClient;
 class Rect;
 enum class FrameEvent;
 
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 750e653..60203f7 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -17,17 +17,17 @@
 #ifndef ANDROID_GUI_SURFACE_H
 #define ANDROID_GUI_SURFACE_H
 
+#include <binder/Parcelable.h>
+
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferQueue.h>
+#include <gui/BufferQueueDefs.h>
 
 #include <ui/ANativeObjectBase.h>
 #include <ui/Region.h>
 
-#include <binder/Parcelable.h>
-
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
 #include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
 
 struct ANativeWindow_Buffer;
 
@@ -251,7 +251,7 @@
     virtual int attachBuffer(ANativeWindowBuffer*);
 
 protected:
-    enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
+    enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
 
     void querySupportedTimestampsLocked() const;
diff --git a/include/private/gui/ComposerService.h b/include/private/gui/ComposerService.h
index ff2f9bf..50bd742 100644
--- a/include/private/gui/ComposerService.h
+++ b/include/private/gui/ComposerService.h
@@ -28,7 +28,6 @@
 
 // ---------------------------------------------------------------------------
 
-class IMemoryHeap;
 class ISurfaceComposer;
 
 // ---------------------------------------------------------------------------
diff --git a/include/ui/Gralloc1.h b/include/ui/Gralloc1.h
index 64dacd7..640e29c 100644
--- a/include/ui/Gralloc1.h
+++ b/include/ui/Gralloc1.h
@@ -88,8 +88,6 @@
 
     std::shared_ptr<Descriptor> createDescriptor();
 
-    gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
-
     gralloc1_error_t allocate(
             const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
             std::vector<buffer_handle_t>* outBuffers);
@@ -102,6 +100,19 @@
 
     gralloc1_error_t release(buffer_handle_t buffer);
 
+    gralloc1_error_t getDimensions(buffer_handle_t buffer,
+            uint32_t* outWidth, uint32_t* outHeight);
+    gralloc1_error_t getFormat(buffer_handle_t buffer,
+            int32_t* outFormat);
+    gralloc1_error_t getLayerCount(buffer_handle_t buffer,
+            uint32_t* outLayerCount);
+    gralloc1_error_t getProducerUsage(buffer_handle_t buffer,
+            uint64_t* outProducerUsage);
+    gralloc1_error_t getConsumerUsage(buffer_handle_t buffer,
+            uint64_t* outConsumerUsage);
+    gralloc1_error_t getBackingStore(buffer_handle_t buffer,
+            uint64_t* outBackingStore);
+    gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
     gralloc1_error_t getNumFlexPlanes(buffer_handle_t buffer,
             uint32_t* outNumPlanes);
 
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
index 2508ce9..fcd2245 100644
--- a/include/ui/Gralloc1On0Adapter.h
+++ b/include/ui/Gralloc1On0Adapter.h
@@ -325,7 +325,7 @@
         auto usage = GRALLOC1_CONSUMER_USAGE_NONE;
         auto error = callBufferFunction(device, bufferHandle,
                 &Buffer::getConsumerUsage, &usage);
-        if (error != GRALLOC1_ERROR_NONE) {
+        if (error == GRALLOC1_ERROR_NONE) {
             *outUsage = static_cast<uint64_t>(usage);
         }
         return error;
@@ -336,7 +336,7 @@
         auto usage = GRALLOC1_PRODUCER_USAGE_NONE;
         auto error = callBufferFunction(device, bufferHandle,
                 &Buffer::getProducerUsage, &usage);
-        if (error != GRALLOC1_ERROR_NONE) {
+        if (error == GRALLOC1_ERROR_NONE) {
             *outUsage = static_cast<uint64_t>(usage);
         }
         return error;
diff --git a/include/ui/GrallocMapper.h b/include/ui/GrallocMapper.h
index f533dfb..5a23b68 100644
--- a/include/ui/GrallocMapper.h
+++ b/include/ui/GrallocMapper.h
@@ -45,17 +45,23 @@
     Error retain(buffer_handle_t handle) const;
     void release(buffer_handle_t handle) const;
 
+    Error getDimensions(buffer_handle_t handle,
+            uint32_t* outWidth, uint32_t* outHeight) const;
+    Error getFormat(buffer_handle_t handle, int32_t* outFormat) const;
+    Error getLayerCount(buffer_handle_t handle, uint32_t* outLayerCount) const;
+    Error getProducerUsage(buffer_handle_t handle,
+            uint64_t* outProducerUsage) const;
+    Error getConsumerUsage(buffer_handle_t handle,
+            uint64_t* outConsumerUsage) const;
+    Error getBackingStore(buffer_handle_t handle,
+            uint64_t* outBackingStore) const;
     Error getStride(buffer_handle_t handle, uint32_t* outStride) const;
 
-    Error lock(buffer_handle_t handle,
-            uint64_t producerUsageMask,
-            uint64_t consumerUsageMask,
-            const IMapper::Rect& accessRegion,
+    Error lock(buffer_handle_t handle, uint64_t producerUsage,
+            uint64_t consumerUsage, const IMapper::Rect& accessRegion,
             int acquireFence, void** outData) const;
-    Error lock(buffer_handle_t handle,
-            uint64_t producerUsageMask,
-            uint64_t consumerUsageMask,
-            const IMapper::Rect& accessRegion,
+    Error lock(buffer_handle_t handle, uint64_t producerUsage,
+            uint64_t consumerUsage, const IMapper::Rect& accessRegion,
             int acquireFence, FlexLayout* outLayout) const;
     int unlock(buffer_handle_t handle) const;
 
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 1bbcee2..54f4cd3 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -81,6 +81,11 @@
             uint32_t inLayerCount, uint32_t inUsage,
             std::string requestorName = "<Unknown>");
 
+    // creates w * h buffer with a layer count using gralloc1
+    GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+            uint32_t inLayerCount, uint64_t inProducerUsage,
+            uint64_t inConsumerUsage, std::string requestorName = "<Unknown>");
+
     // create a buffer from an existing handle
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
             uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
@@ -122,6 +127,8 @@
     status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd);
     status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr,
             int fenceFd);
+    status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
+            const Rect& rect, void** vaddr, int fenceFd);
     status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr,
             int fenceFd);
     status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
@@ -166,7 +173,8 @@
     const GraphicBuffer& operator = (const GraphicBuffer& rhs) const;
 
     status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inLayerCount, uint32_t inUsage, std::string requestorName);
+            uint32_t inLayerCount, uint64_t inProducerUsage,
+            uint64_t inConsumerUsage, std::string requestorName);
 
     void free_handle();
 
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 16967d4..2ccc44b 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -65,8 +65,8 @@
     static inline GraphicBufferAllocator& get() { return getInstance(); }
 
     status_t allocate(uint32_t w, uint32_t h, PixelFormat format,
-            uint32_t layerCount, uint32_t usage, buffer_handle_t* handle,
-            uint32_t* stride, uint64_t graphicBufferId,
+            uint32_t layerCount, uint64_t producerUsage, uint64_t consumerUsage,
+            buffer_handle_t* handle, uint32_t* stride, uint64_t graphicBufferId,
             std::string requestorName);
 
     status_t free(buffer_handle_t handle);
@@ -81,7 +81,8 @@
         uint32_t stride;
         PixelFormat format;
         uint32_t layerCount;
-        uint32_t usage;
+        uint64_t producerUsage;
+        uint64_t consumerUsage;
         size_t size;
         std::string requestorName;
     };
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index b6de1b2..8e93f72 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -44,6 +44,25 @@
 
     status_t unregisterBuffer(buffer_handle_t handle);
 
+    status_t getDimensions(buffer_handle_t handle,
+            uint32_t* outWidth, uint32_t* outHeight) const;
+
+    status_t getFormat(buffer_handle_t handle, int32_t* outFormat) const;
+
+    status_t getLayerCount(buffer_handle_t handle,
+            uint32_t* outLayerCount) const;
+
+    status_t getProducerUsage(buffer_handle_t handle,
+            uint64_t* outProducerUsage) const;
+
+    status_t getConsumerUsage(buffer_handle_t handle,
+            uint64_t* outConsumerUsage) const;
+
+    status_t getBackingStore(buffer_handle_t handle,
+            uint64_t* outBackingStore) const;
+
+    status_t getStride(buffer_handle_t handle, uint32_t* outStride) const;
+
     status_t lock(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, void** vaddr);
 
@@ -55,6 +74,10 @@
     status_t lockAsync(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd);
 
+    status_t lockAsync(buffer_handle_t handle,
+            uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
+            void** vaddr, int fenceFd);
+
     status_t lockAsyncYCbCr(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr,
             int fenceFd);
diff --git a/include/gui/GraphicsEnv.h b/include/ui/GraphicsEnv.h
similarity index 94%
rename from include/gui/GraphicsEnv.h
rename to include/ui/GraphicsEnv.h
index 4c7366f..7817076 100644
--- a/include/gui/GraphicsEnv.h
+++ b/include/ui/GraphicsEnv.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_GRAPHICS_ENV_H
-#define ANDROID_GUI_GRAPHICS_ENV_H 1
+#ifndef ANDROID_UI_GRAPHICS_ENV_H
+#define ANDROID_UI_GRAPHICS_ENV_H 1
 
 #include <string>
 
@@ -56,4 +56,4 @@
  */
 extern "C" android_namespace_t* android_getDriverNamespace();
 
-#endif // ANDROID_GUI_GRAPHICS_ENV_H
+#endif // ANDROID_UI_GRAPHICS_ENV_H
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
index fb28643..8939d9c 100644
--- a/libs/binder/ProcessInfoService.cpp
+++ b/libs/binder/ProcessInfoService.cpp
@@ -57,6 +57,40 @@
     return TIMED_OUT;
 }
 
+status_t ProcessInfoService::getProcessStatesScoresImpl(size_t length,
+        /*in*/ int32_t* pids, /*out*/ int32_t* states,
+        /*out*/ int32_t *scores) {
+    status_t err = NO_ERROR;
+    sp<IProcessInfoService> pis;
+    mProcessInfoLock.lock();
+    pis = mProcessInfoService;
+    mProcessInfoLock.unlock();
+
+    for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) {
+
+        if (pis != NULL) {
+            err = pis->getProcessStatesAndOomScoresFromPids(length,
+                    /*in*/ pids, /*out*/ states, /*out*/ scores);
+            if (err == NO_ERROR) return NO_ERROR; // success
+            if (IInterface::asBinder(pis)->isBinderAlive()) return err;
+        }
+        sleep(1);
+
+        mProcessInfoLock.lock();
+        if (pis == mProcessInfoService) {
+            updateBinderLocked();
+        }
+        pis = mProcessInfoService;
+        mProcessInfoLock.unlock();
+    }
+
+    ALOGW("%s: Could not retrieve process states and scores "
+            "from ProcessInfoService after %d retries.", __FUNCTION__,
+            BINDER_ATTEMPT_LIMIT);
+
+    return TIMED_OUT;
+}
+
 void ProcessInfoService::updateBinderLocked() {
     const sp<IServiceManager> sm(defaultServiceManager());
     if (sm != NULL) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3815bdc..cb17da4 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -77,7 +77,6 @@
         "FrameTimestamps.cpp",
         "GLConsumer.cpp",
         "GraphicBufferAlloc.cpp",
-        "GraphicsEnv.cpp",
         "GuiConfig.cpp",
         "IDisplayEventConnection.cpp",
         "IGraphicBufferAlloc.cpp",
@@ -100,7 +99,6 @@
     ],
 
     shared_libs: [
-        "libnativeloader",
         "libsync",
         "libbinder",
         "libcutils",
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
index 30f5e53..f2d3677 100644
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ b/libs/gui/GraphicBufferAlloc.cpp
@@ -33,9 +33,10 @@
 
 sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
         uint32_t height, PixelFormat format, uint32_t layerCount,
-        uint32_t usage, std::string requestorName, status_t* error) {
+        uint64_t producerUsage, uint64_t consumerUsage,
+        std::string requestorName, status_t* error) {
     sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
-            width, height, format, layerCount, usage,
+            width, height, format, layerCount, producerUsage, consumerUsage,
             std::move(requestorName)));
     status_t err = graphicBuffer->initCheck();
     *error = err;
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index a3d3b74..21a0dd5 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -46,14 +46,16 @@
 
     virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
             uint32_t height, PixelFormat format, uint32_t layerCount,
-            uint32_t usage, std::string requestorName, status_t* error) {
+            uint64_t producerUsage, uint64_t consumerUsage,
+            std::string requestorName, status_t* error) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
         data.writeUint32(width);
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
         data.writeUint32(layerCount);
-        data.writeUint32(usage);
+        data.writeUint64(producerUsage);
+        data.writeUint64(consumerUsage);
         if (requestorName.empty()) {
             requestorName += "[PID ";
             requestorName += std::to_string(getpid());
@@ -108,12 +110,14 @@
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
             uint32_t layerCount = data.readUint32();
-            uint32_t usage = data.readUint32();
+            uint64_t producerUsage = data.readUint64();
+            uint64_t consumerUsage = data.readUint64();
             status_t error = NO_ERROR;
             std::string requestorName;
             data.readUtf8FromUtf16(&requestorName);
             sp<GraphicBuffer> result = createGraphicBuffer(width, height,
-                    format, layerCount, usage, requestorName, &error);
+                    format, layerCount, producerUsage, consumerUsage,
+                    requestorName, &error);
             reply->writeInt32(error);
             if (result != 0) {
                 reply->write(*result);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2a327da..5a2c3db 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,10 +25,11 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
-#include <gui/BitTube.h>
 #include <gui/IDisplayEventConnection.h>
-#include <gui/ISurfaceComposer.h>
+#include <gui/IGraphicBufferAlloc.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/ISurfaceComposerClient.h>
 
 #include <private/gui/LayerState.h>
 
@@ -44,8 +45,6 @@
 
 namespace android {
 
-class IDisplayEventConnection;
-
 class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
 {
 public:
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index c2ed91a..c663620 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -30,12 +30,11 @@
 #include <ui/Region.h>
 #include <ui/DisplayStatInfo.h>
 
+#include <gui/BufferItem.h>
 #include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 
+#include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
 namespace android {
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 4cd0d3a..67efb84 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -55,6 +55,7 @@
         "GraphicBuffer.cpp",
         "GraphicBufferAllocator.cpp",
         "GraphicBufferMapper.cpp",
+        "GraphicsEnv.cpp",
         "HdrCapabilities.cpp",
         "PixelFormat.cpp",
         "Rect.cpp",
@@ -65,6 +66,7 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "libnativeloader",
         "libbinder",
         "libcutils",
         "libhardware",
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
index 367d1ce..0083f58 100644
--- a/libs/ui/Gralloc1.cpp
+++ b/libs/ui/Gralloc1.cpp
@@ -140,12 +140,6 @@
     return descriptor;
 }
 
-gralloc1_error_t Device::getStride(buffer_handle_t buffer, uint32_t* outStride)
-{
-    int32_t intError = mFunctions.getStride(mDevice, buffer, outStride);
-    return static_cast<gralloc1_error_t>(intError);
-}
-
 static inline bool allocationSucceded(gralloc1_error_t error)
 {
     return error == GRALLOC1_ERROR_NONE || error == GRALLOC1_ERROR_NOT_SHARED;
@@ -225,6 +219,99 @@
     return static_cast<gralloc1_error_t>(intError);
 }
 
+gralloc1_error_t Device::getDimensions(buffer_handle_t buffer,
+        uint32_t* outWidth, uint32_t* outHeight)
+{
+    uint32_t width = 0;
+    uint32_t height = 0;
+    int32_t intError = mFunctions.getDimensions(mDevice, buffer, &width,
+            &height);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outWidth = width;
+        *outHeight = height;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::getFormat(buffer_handle_t buffer,
+        int32_t* outFormat)
+{
+    int32_t format = 0;
+    int32_t intError = mFunctions.getFormat(mDevice, buffer, &format);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outFormat = format;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::getLayerCount(buffer_handle_t buffer,
+        uint32_t* outLayerCount)
+{
+    if (hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
+        uint32_t layerCount = 0;
+        int32_t intError = mFunctions.getLayerCount(mDevice, buffer,
+                &layerCount);
+        auto error = static_cast<gralloc1_error_t>(intError);
+        if (error == GRALLOC1_ERROR_NONE) {
+            *outLayerCount = layerCount;
+        }
+        return error;
+    } else {
+        // Layered buffers are not supported on this device.
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+}
+
+gralloc1_error_t Device::getProducerUsage(buffer_handle_t buffer,
+        uint64_t* outProducerUsage)
+{
+    uint64_t usage = 0;
+    int32_t intError = mFunctions.getProducerUsage(mDevice, buffer, &usage);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outProducerUsage = usage;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::getConsumerUsage(buffer_handle_t buffer,
+        uint64_t* outConsumerUsage)
+{
+    uint64_t usage = 0;
+    int32_t intError = mFunctions.getConsumerUsage(mDevice, buffer, &usage);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outConsumerUsage = usage;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::getBackingStore(buffer_handle_t buffer,
+        uint64_t* outBackingStore)
+{
+    uint64_t store = 0;
+    int32_t intError = mFunctions.getBackingStore(mDevice, buffer, &store);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outBackingStore = store;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::getStride(buffer_handle_t buffer,
+        uint32_t* outStride)
+{
+    uint32_t stride = 0;
+    int32_t intError = mFunctions.getStride(mDevice, buffer, &stride);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outStride = stride;
+    }
+    return error;
+}
+
 gralloc1_error_t Device::getNumFlexPlanes(buffer_handle_t buffer,
         uint32_t* outNumPlanes)
 {
@@ -244,7 +331,7 @@
         const sp<Fence>& acquireFence)
 {
     ALOGV("Calling lock(%p)", buffer);
-    return lockHelper(mFunctions.lock.pfn, buffer, producerUsage,
+    return lockHelper(mFunctions.lock, buffer, producerUsage,
             consumerUsage, accessRegion, outData, acquireFence);
 }
 
@@ -256,7 +343,7 @@
         const sp<Fence>& acquireFence)
 {
     ALOGV("Calling lockFlex(%p)", buffer);
-    return lockHelper(mFunctions.lockFlex.pfn, buffer, producerUsage,
+    return lockHelper(mFunctions.lockFlex, buffer, producerUsage,
             consumerUsage, accessRegion, outData, acquireFence);
 }
 
@@ -268,7 +355,7 @@
         const sp<Fence>& acquireFence)
 {
     ALOGV("Calling lockYCbCr(%p)", buffer);
-    return lockHelper(mFunctions.lockYCbCr.pfn, buffer, producerUsage,
+    return lockHelper(mFunctions.lockYCbCr, buffer, producerUsage,
             consumerUsage, accessRegion, outData, acquireFence);
 }
 
diff --git a/libs/ui/GrallocMapper.cpp b/libs/ui/GrallocMapper.cpp
index 7ee01ad..b9e9040 100644
--- a/libs/ui/GrallocMapper.cpp
+++ b/libs/ui/GrallocMapper.cpp
@@ -51,6 +51,115 @@
             "release(%p) failed with %d", handle, error);
 }
 
+Error Mapper::getDimensions(buffer_handle_t handle,
+        uint32_t* outWidth, uint32_t* outHeight) const
+{
+    Error error = kDefaultError;
+    mMapper->getDimensions(handle,
+            [&](const auto& tmpError, const auto& tmpWidth,
+                    const auto& tmpHeight)
+            {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outWidth = tmpWidth;
+                *outHeight = tmpHeight;
+            });
+
+    return error;
+}
+
+Error Mapper::getFormat(buffer_handle_t handle, int32_t* outFormat) const
+{
+    Error error = kDefaultError;
+    mMapper->getFormat(handle,
+            [&](const auto& tmpError, const auto& tmpFormat)
+            {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outFormat = static_cast<int32_t>(tmpFormat);
+            });
+
+    return error;
+}
+
+Error Mapper::getLayerCount(buffer_handle_t handle,
+        uint32_t* outLayerCount) const
+{
+    Error error = kDefaultError;
+    mMapper->getLayerCount(handle,
+            [&](const auto& tmpError, const auto& tmpLayerCount)
+            {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outLayerCount = tmpLayerCount;
+            });
+
+    return error;
+}
+
+Error Mapper::getProducerUsage(buffer_handle_t handle,
+    uint64_t* outProducerUsage) const
+{
+    Error error = kDefaultError;
+    mMapper->getProducerUsageMask(handle,
+            [&](const auto& tmpError, const auto& tmpProducerUsage)
+            {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outProducerUsage = tmpProducerUsage;
+            });
+
+    return error;
+}
+
+Error Mapper::getConsumerUsage(buffer_handle_t handle,
+        uint64_t* outConsumerUsage) const
+{
+    Error error = kDefaultError;
+    mMapper->getConsumerUsageMask(handle,
+            [&](const auto& tmpError, const auto& tmpConsumerUsage)
+            {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outConsumerUsage = tmpConsumerUsage;
+            });
+
+    return error;
+}
+
+Error Mapper::getBackingStore(buffer_handle_t handle,
+        uint64_t* outBackingStore) const
+{
+    Error error = kDefaultError;
+    mMapper->getBackingStore(handle,
+            [&](const auto& tmpError, const auto& tmpStore)
+            {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outBackingStore = tmpStore;
+            });
+
+    return error;
+}
+
 Error Mapper::getStride(buffer_handle_t handle, uint32_t* outStride) const
 {
     Error error = kDefaultError;
@@ -69,8 +178,8 @@
 }
 
 Error Mapper::lock(buffer_handle_t handle,
-        uint64_t producerUsageMask,
-        uint64_t consumerUsageMask,
+        uint64_t producerUsage,
+        uint64_t consumerUsage,
         const IMapper::Rect& accessRegion,
         int acquireFence, void** outData) const
 {
@@ -84,7 +193,7 @@
     }
 
     Error error = kDefaultError;
-    mMapper->lock(handle, producerUsageMask, consumerUsageMask,
+    mMapper->lock(handle, producerUsage, consumerUsage,
             accessRegion, acquireFenceHandle,
             [&](const auto& tmpError, const auto& tmpData)
             {
@@ -104,8 +213,8 @@
 }
 
 Error Mapper::lock(buffer_handle_t handle,
-        uint64_t producerUsageMask,
-        uint64_t consumerUsageMask,
+        uint64_t producerUsage,
+        uint64_t consumerUsage,
         const IMapper::Rect& accessRegion,
         int acquireFence, FlexLayout* outLayout) const
 {
@@ -119,7 +228,7 @@
     }
 
     Error error = kDefaultError;
-    mMapper->lockFlex(handle, producerUsageMask, consumerUsageMask,
+    mMapper->lockFlex(handle, producerUsage, consumerUsage,
             accessRegion, acquireFenceHandle,
             [&](const auto& tmpError, const auto& tmpLayout)
             {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 07164a4..d29bae1 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -67,13 +67,13 @@
     layerCount =
     usage  = 0;
     handle = NULL;
-    mInitCheck = initSize(inWidth, inHeight, inFormat, 1, inUsage,
+    mInitCheck = initSize(inWidth, inHeight, inFormat, 1, inUsage, inUsage,
             std::move(requestorName));
 }
 
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
-        std::string requestorName)
+        PixelFormat inFormat, uint32_t inLayerCount, uint64_t producerUsage,
+        uint64_t consumerUsage, std::string requestorName)
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
 {
@@ -84,8 +84,8 @@
     layerCount =
     usage  = 0;
     handle = NULL;
-    mInitCheck = initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
-            std::move(requestorName));
+    mInitCheck = initSize(inWidth, inHeight, inFormat, inLayerCount,
+            producerUsage, consumerUsage, std::move(requestorName));
 }
 
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
@@ -177,7 +177,7 @@
         allocator.free(handle);
         handle = 0;
     }
-    return initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+    return initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, inUsage,
             "[Reallocation]");
 }
 
@@ -193,19 +193,20 @@
 }
 
 status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
-        std::string requestorName)
+        PixelFormat inFormat, uint32_t inLayerCount, uint64_t inProducerUsage,
+        uint64_t inConsumerUsage, std::string requestorName)
 {
     GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
     uint32_t outStride = 0;
     status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
-            inUsage, &handle, &outStride, mId, std::move(requestorName));
+            inProducerUsage, inConsumerUsage, &handle, &outStride, mId,
+            std::move(requestorName));
     if (err == NO_ERROR) {
         width = static_cast<int>(inWidth);
         height = static_cast<int>(inHeight);
         format = inFormat;
         layerCount = inLayerCount;
-        usage = static_cast<int>(inUsage);
+        usage = static_cast<int>(inProducerUsage | inConsumerUsage);
         stride = static_cast<int>(outStride);
     }
     return err;
@@ -268,6 +269,12 @@
 status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect,
         void** vaddr, int fenceFd)
 {
+    return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd);
+}
+
+status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage,
+        uint64_t inConsumerUsage, const Rect& rect, void** vaddr, int fenceFd)
+{
     if (rect.left < 0 || rect.right  > width ||
         rect.top  < 0 || rect.bottom > height) {
         ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -275,8 +282,8 @@
                 width, height);
         return BAD_VALUE;
     }
-    status_t res = getBufferMapper().lockAsync(handle, inUsage, rect, vaddr,
-            fenceFd);
+    status_t res = getBufferMapper().lockAsync(handle, inProducerUsage,
+            inConsumerUsage, rect, vaddr, fenceFd);
     return res;
 }
 
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 07ad4c1..b14110e 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -63,15 +63,19 @@
     for (size_t i=0 ; i<c ; i++) {
         const alloc_rec_t& rec(list.valueAt(i));
         if (rec.size) {
-            snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%08x | %s\n",
+            snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
+                    ", 0x%" PRIx64 " | %s\n",
                     list.keyAt(i), rec.size/1024.0,
                     rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
-                    rec.usage, rec.requestorName.c_str());
+                    rec.producerUsage, rec.consumerUsage,
+                    rec.requestorName.c_str());
         } else {
-            snprintf(buffer, SIZE, "%10p: unknown     | %4u (%4u) x %4u | %4u | %8X | 0x%08x | %s\n",
+            snprintf(buffer, SIZE, "%10p: unknown     | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
+                    ", 0x%" PRIx64 " | %s\n",
                     list.keyAt(i),
                     rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
-                    rec.usage, rec.requestorName.c_str());
+                    rec.producerUsage, rec.consumerUsage,
+                    rec.requestorName.c_str());
         }
         result.append(buffer);
         total += rec.size;
@@ -102,7 +106,8 @@
 public:
     HalBuffer(const Gralloc2::Allocator* allocator,
             uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t layerCount, uint32_t usage)
+            PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+            uint64_t consumerUsage)
         : mAllocator(allocator), mBufferValid(false)
     {
         Gralloc2::IAllocatorClient::BufferDescriptorInfo info = {};
@@ -110,14 +115,16 @@
         info.height = height;
         info.format = static_cast<Gralloc2::PixelFormat>(format);
         info.layerCount = layerCount;
-        info.producerUsageMask = usage;
-        info.consumerUsageMask = usage;
+        info.producerUsageMask = producerUsage;
+        info.consumerUsageMask = consumerUsage;
 
         Gralloc2::BufferDescriptor descriptor;
         auto error = mAllocator->createBufferDescriptor(info, &descriptor);
         if (error != Gralloc2::Error::NONE) {
-            ALOGE("Failed to create desc (%u x %u) layerCount %u format %d usage %u: %d",
-                    width, height, layerCount, format, usage, error);
+            ALOGE("Failed to create desc (%u x %u) layerCount %u format %d producerUsage %" PRIx64
+                    " consumerUsage %" PRIx64 ": %d",
+                    width, height, layerCount, format, producerUsage,
+                    consumerUsage, error);
             return;
         }
 
@@ -127,8 +134,10 @@
         }
 
         if (error != Gralloc2::Error::NONE) {
-            ALOGE("Failed to allocate (%u x %u) layerCount %u format %d usage %u: %d",
-                    width, height, layerCount, format, usage, error);
+            ALOGE("Failed to allocate (%u x %u) layerCount %u format %d producerUsage %" PRIx64
+                    " consumerUsage %" PRIx64 ": %d",
+                    width, height, layerCount, format, producerUsage,
+                    consumerUsage, error);
             mAllocator->destroyBufferDescriptor(descriptor);
             return;
         }
@@ -195,9 +204,9 @@
 } // namespace
 
 status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t layerCount, uint32_t usage,
-        buffer_handle_t* handle, uint32_t* stride, uint64_t graphicBufferId,
-        std::string requestorName)
+        PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+        uint64_t consumerUsage, buffer_handle_t* handle, uint32_t* stride,
+        uint64_t graphicBufferId, std::string requestorName)
 {
     ATRACE_CALL();
 
@@ -210,13 +219,10 @@
     if (layerCount < 1)
         layerCount = 1;
 
-    // Filter out any usage bits that should not be passed to the gralloc module
-    usage &= GRALLOC_USAGE_ALLOC_MASK;
-
     gralloc1_error_t error;
     if (mAllocator->valid()) {
         HalBuffer buffer(mAllocator.get(), width, height, format, layerCount,
-                usage);
+                producerUsage, consumerUsage);
         if (!buffer.exportHandle(mMapper, handle, stride)) {
             return NO_MEMORY;
         }
@@ -247,22 +253,26 @@
             return BAD_VALUE;
         }
         error = descriptor->setProducerUsage(
-                static_cast<gralloc1_producer_usage_t>(usage));
+                static_cast<gralloc1_producer_usage_t>(producerUsage));
         if (error != GRALLOC1_ERROR_NONE) {
-            ALOGE("Failed to set producer usage to %u: %d", usage, error);
+            ALOGE("Failed to set producer usage to %" PRIx64 ": %d",
+                    producerUsage, error);
             return BAD_VALUE;
         }
         error = descriptor->setConsumerUsage(
-                static_cast<gralloc1_consumer_usage_t>(usage));
+                static_cast<gralloc1_consumer_usage_t>(consumerUsage));
         if (error != GRALLOC1_ERROR_NONE) {
-            ALOGE("Failed to set consumer usage to %u: %d", usage, error);
+            ALOGE("Failed to set consumer usage to %" PRIx64 ": %d",
+                    consumerUsage, error);
             return BAD_VALUE;
         }
 
         error = mDevice->allocate(descriptor, graphicBufferId, handle);
         if (error != GRALLOC1_ERROR_NONE) {
-            ALOGE("Failed to allocate (%u x %u) layerCount %u format %d usage %u: %d",
-                    width, height, layerCount, format, usage, error);
+            ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
+                    "producerUsage %" PRIx64 " consumerUsage %" PRIx64 ": %d",
+                    width, height, layerCount, format, producerUsage,
+                    consumerUsage, error);
             return NO_MEMORY;
         }
 
@@ -282,7 +292,8 @@
         rec.stride = *stride;
         rec.format = format;
         rec.layerCount = layerCount;
-        rec.usage = usage;
+        rec.producerUsage = producerUsage;
+        rec.consumerUsage = consumerUsage;
         rec.size = static_cast<size_t>(height * (*stride) * bpp);
         rec.requestorName = std::move(requestorName);
         list.add(*handle, rec);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 1ff934b..b0ed2df 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -117,6 +117,140 @@
     return outRect;
 }
 
+
+status_t GraphicBufferMapper::getDimensions(buffer_handle_t handle,
+        uint32_t* outWidth, uint32_t* outHeight) const
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error;
+    if (mMapper->valid()) {
+        mMapper->getDimensions(handle, outWidth, outHeight);
+        error = GRALLOC1_ERROR_NONE;
+    } else {
+        error = mDevice->getDimensions(handle, outWidth, outHeight);
+    }
+
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getDimensions(%p, ...): failed %d",
+            handle, error);
+
+    return error;
+}
+
+status_t GraphicBufferMapper::getFormat(buffer_handle_t handle,
+        int32_t* outFormat) const
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error;
+    if (mMapper->valid()) {
+        mMapper->getFormat(handle, outFormat);
+        error = GRALLOC1_ERROR_NONE;
+    } else {
+        error = mDevice->getFormat(handle, outFormat);
+    }
+
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getFormat(%p, ...): failed %d",
+            handle, error);
+
+    return error;
+}
+
+status_t GraphicBufferMapper::getLayerCount(buffer_handle_t handle,
+        uint32_t* outLayerCount) const
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error;
+    if (mMapper->valid()) {
+        mMapper->getLayerCount(handle, outLayerCount);
+        error = GRALLOC1_ERROR_NONE;
+    } else {
+        error = mDevice->getLayerCount(handle, outLayerCount);
+    }
+
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getLayerCount(%p, ...): failed %d",
+            handle, error);
+
+    return error;
+}
+
+status_t GraphicBufferMapper::getProducerUsage(buffer_handle_t handle,
+        uint64_t* outProducerUsage) const
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error;
+    if (mMapper->valid()) {
+        mMapper->getProducerUsage(handle, outProducerUsage);
+        error = GRALLOC1_ERROR_NONE;
+    } else {
+        error = mDevice->getProducerUsage(handle, outProducerUsage);
+    }
+
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE,
+            "getProducerUsage(%p, ...): failed %d", handle, error);
+
+    return error;
+}
+
+status_t GraphicBufferMapper::getConsumerUsage(buffer_handle_t handle,
+        uint64_t* outConsumerUsage) const
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error;
+    if (mMapper->valid()) {
+        mMapper->getConsumerUsage(handle, outConsumerUsage);
+        error = GRALLOC1_ERROR_NONE;
+    } else {
+        error = mDevice->getConsumerUsage(handle, outConsumerUsage);
+    }
+
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE,
+            "getConsumerUsage(%p, ...): failed %d", handle, error);
+
+    return error;
+}
+
+status_t GraphicBufferMapper::getBackingStore(buffer_handle_t handle,
+        uint64_t* outBackingStore) const
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error;
+    if (mMapper->valid()) {
+        mMapper->getBackingStore(handle, outBackingStore);
+        error = GRALLOC1_ERROR_NONE;
+    } else {
+        error = mDevice->getBackingStore(handle, outBackingStore);
+    }
+
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE,
+            "getBackingStore(%p, ...): failed %d", handle, error);
+
+    return error;
+}
+
+status_t GraphicBufferMapper::getStride(buffer_handle_t handle,
+        uint32_t* outStride) const
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error;
+    if (mMapper->valid()) {
+        mMapper->getStride(handle, outStride);
+        error = GRALLOC1_ERROR_NONE;
+    } else {
+        error = mDevice->getStride(handle, outStride);
+    }
+
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getStride(%p, ...): failed %d",
+            handle, error);
+
+    return error;
+}
+
 status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
         const Rect& bounds, void** vaddr)
 {
@@ -143,6 +277,13 @@
 status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
         uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
 {
+    return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd);
+}
+
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
+        uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
+        void** vaddr, int fenceFd)
+{
     ATRACE_CALL();
 
     gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
@@ -151,12 +292,13 @@
         const Gralloc2::IMapper::Rect& accessRect =
             *reinterpret_cast<Gralloc2::IMapper::Rect*>(&accessRegion);
         error = static_cast<gralloc1_error_t>(mMapper->lock(
-                    handle, usage, usage, accessRect, fenceFd, vaddr));
+                    handle, producerUsage, consumerUsage, accessRect,
+                    fenceFd, vaddr));
     } else {
         sp<Fence> fence = new Fence(fenceFd);
         error = mDevice->lock(handle,
-                static_cast<gralloc1_producer_usage_t>(usage),
-                static_cast<gralloc1_consumer_usage_t>(usage),
+                static_cast<gralloc1_producer_usage_t>(producerUsage),
+                static_cast<gralloc1_consumer_usage_t>(consumerUsage),
                 &accessRegion, vaddr, fence);
     }
 
diff --git a/libs/gui/GraphicsEnv.cpp b/libs/ui/GraphicsEnv.cpp
similarity index 98%
rename from libs/gui/GraphicsEnv.cpp
rename to libs/ui/GraphicsEnv.cpp
index 68f0f98..1d20424 100644
--- a/libs/gui/GraphicsEnv.cpp
+++ b/libs/ui/GraphicsEnv.cpp
@@ -16,7 +16,7 @@
 
 //#define LOG_NDEBUG 1
 #define LOG_TAG "GraphicsEnv"
-#include <gui/GraphicsEnv.h>
+#include <ui/GraphicsEnv.h>
 
 #include <mutex>
 
diff --git a/libs/vr/libgvr/Android.mk b/libs/vr/libgvr/Android.mk
index be78605..0daf2ea 100644
--- a/libs/vr/libgvr/Android.mk
+++ b/libs/vr/libgvr/Android.mk
@@ -19,10 +19,9 @@
 
 # Java platform library for the system implementation of the GVR API.
 include $(CLEAR_VARS)
-LOCAL_MODULE := gvr_platform
-LOCAL_MODULE_STEM := com.google.vr.gvr.platform
+LOCAL_MODULE := com.google.vr.gvr.platform
 LOCAL_REQUIRED_MODULES := libgvr_system_loader libgvr_system
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
 include $(BUILD_JAVA_LIBRARY)
 
 # Library to perform dlopen on the actual platform library.
diff --git a/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java b/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java
index 5c5cc62..381175c 100644
--- a/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java
+++ b/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java
@@ -1,32 +1,38 @@
 package com.google.vr.gvr.platform;
 
+import android.os.SystemProperties;
+
 /**
  * Auxiliary class to load the system implementation of the GVR API.
+ * @hide
  */
 public class Loader {
 
-  /**
-   * Opens a shared library containing the system implementation for the GVR
-   * API and returns the handle to it.
-   *
-   * @return A Long object describing the handle returned by dlopen.
-   */
-  public static Long loadLibrary() {
-    // Note: we cannot safely do caller verifications here, so instead we do
-    // them in the service side. This means that private API symbols will be
-    // visible to any app adding the appropriate <uses-library> in their
-    // manifest, but any requests to such APIs will fail if not done from a
-    // trusted package like VrCore.
-    //
-    // Trusted packages are defined by (package name, signature) pairs in within
-    // a system service, and both must match.
+    private static final String VR_MODE_BOOT = "ro.boot.vr";
 
-    // Load a thin JNI library that runs dlopen on request.
-    System.loadLibrary("gvr_system_loader");
+    /**
+     * Opens a shared library containing the system implementation for the GVR API and returns the
+     * handle to it.
+     *
+     * @return A Long object describing the handle returned by dlopen.
+     */
+    public static Long loadLibrary() {
+        // Note: caller verifications cannot be safely done here. Any app can find and use this API.
+        // Any sensitive functions must have appropriate checks on the service side.
 
-    // Performs dlopen on the library and returns the handle.
-    return nativeLoadLibrary("libgvr_system.so");
-  }
+        // Load a thin JNI library that runs dlopen on request.
+        System.loadLibrary("gvr_system_loader");
 
-  private static native long nativeLoadLibrary(String library);
+        // Performs dlopen on the library and returns the handle.
+        return nativeLoadLibrary("libgvr_system.so");
+    }
+
+    /**
+     * Returns true if this device boots directly in VR mode.
+     */
+    public static boolean getVrBoot() {
+        return SystemProperties.getBoolean(VR_MODE_BOOT, false);
+    }
+
+    private static native long nativeLoadLibrary(String library);
 }
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index e1729f8..7c821bf 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -381,6 +381,15 @@
   ATRACE_NAME("DisplaySurface::OnPostConsumer");
   std::lock_guard<std::mutex> autolock(lock_);
 
+  if (!IsVisible()) {
+    ALOGD_IF(TRACE,
+             "DisplaySurface::OnPostConsumer: Discarding buffer_id=%d on "
+             "invisible surface.",
+             consumer->id());
+    consumer->Discard();
+    return;
+  }
+
   if (posted_buffers_.IsFull()) {
     ALOGE("Error: posted buffers full, overwriting");
     posted_buffers_.PopBack();
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index cc08209..7402000 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -104,7 +104,6 @@
       display_transform_(HWC_TRANSFORM_NONE),
       display_surfaces_updated_(false),
       hardware_layers_need_update_(false),
-      display_on_(false),
       active_layer_count_(0),
       gpu_layer_(nullptr),
       terminate_post_thread_event_fd_(-1),
@@ -282,7 +281,6 @@
   PausePostThread();
 
   EnableVsync(false);
-  SetPowerMode(HWC_DISPLAY_PRIMARY, HWC2_POWER_MODE_OFF);
 
   backlight_brightness_fd_.Close();
   primary_display_vsync_event_fd_.Close();
@@ -382,18 +380,6 @@
   return error;
 }
 
-int32_t HardwareComposer::SetPowerMode(hwc2_display_t display,
-                                       hwc2_power_mode_t mode) {
-  if (mode == HWC2_POWER_MODE_OFF) {
-    EnableVsync(false);
-  }
-
-  display_on_ = mode != HWC2_POWER_MODE_OFF;
-
-  return (int32_t)hwc2_hidl_->setPowerMode(
-      display, (Hwc2::IComposerClient::PowerMode)mode);
-}
-
 int32_t HardwareComposer::GetDisplayAttribute(hwc2_display_t display,
                                               hwc2_config_t config,
                                               hwc2_attribute_t attribute,
@@ -556,26 +542,15 @@
   const bool has_display_surfaces = display_surfaces_.size() > 0;
 
   if (has_display_surfaces) {
-    int32_t ret = SetPowerMode(HWC_DISPLAY_PRIMARY, HWC2_POWER_MODE_ON);
-
-    ALOGE_IF(ret, "HardwareComposer: Could not set power mode; ret=%d", ret);
-
     EnableVsync(true);
   }
+
   // TODO(skiazyk): We need to do something about accessing this directly,
   // supposedly there is a backlight service on the way.
   SetBacklightBrightness(255);
 
-  if (!display_on_ && has_display_surfaces) {
-    const int error = ReadVSyncTimestamp(&last_vsync_timestamp_);
-    ALOGE_IF(error < 0,
-             "HardwareComposer::SetDisplaySurfaces: Failed to read vsync "
-             "timestamp: %s",
-             strerror(-error));
-  }
-
   // Trigger target-specific performance mode change.
-  property_set(kDvrPerformanceProperty, display_on_ ? "performance" : "idle");
+  property_set(kDvrPerformanceProperty, has_display_surfaces ? "performance" : "idle");
 }
 
 int HardwareComposer::SetDisplaySurfaces(
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index cfe8c84..4266a40 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -227,7 +227,6 @@
 
  private:
   int32_t EnableVsync(bool enabled);
-  int32_t SetPowerMode(hwc2_display_t display, hwc2_power_mode_t mode);
 
   class ComposerCallback : public Hwc2::IComposerCallback {
    public:
@@ -329,9 +328,6 @@
   bool display_surfaces_updated_;
   bool hardware_layers_need_update_;
 
-  // Cache whether the display was turned on by us
-  bool display_on_; // TODO(hendrikw): The display is always on. Revisit.
-
   // Layer array for handling buffer flow into hardware composer layers.
   // Note that the first array is the actual storage for the layer objects,
   // and the latter is an array of pointers, which can be freely re-arranged
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 01d7bbb..b1ca13d 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -31,6 +31,7 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <utils/Trace.h>
+#include <ui/GraphicsEnv.h>
 
 #include <EGL/egl.h>
 
@@ -147,26 +148,11 @@
 // ----------------------------------------------------------------------------
 
 Loader::Loader()
-    : getProcAddress(NULL),
-      mLibGui(nullptr),
-      mGetDriverNamespace(nullptr)
+    : getProcAddress(NULL)
 {
-    // FIXME: See note in GraphicsEnv.h about android_getDriverNamespace().
-    // libgui should already be loaded in any process that uses libEGL, but
-    // if for some reason it isn't, then we're not going to get a driver
-    // namespace anyway, so don't force it to be loaded.
-    mLibGui = dlopen("libgui.so", RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
-    if (!mLibGui) {
-        ALOGD("failed to load libgui: %s", dlerror());
-        return;
-    }
-    mGetDriverNamespace = reinterpret_cast<decltype(mGetDriverNamespace)>(
-            dlsym(mLibGui, "android_getDriverNamespace"));
 }
 
 Loader::~Loader() {
-    if (mLibGui)
-        dlclose(mLibGui);
 }
 
 static void* load_wrapper(const char* path) {
@@ -483,11 +469,9 @@
     ATRACE_CALL();
 
     void* dso = nullptr;
-    if (mGetDriverNamespace) {
-        android_namespace_t* ns = mGetDriverNamespace();
-        if (ns) {
-            dso = load_updated_driver(kind, ns);
-        }
+    android_namespace_t* ns = android_getDriverNamespace();
+    if (ns) {
+        dso = load_updated_driver(kind, ns);
     }
     if (!dso) {
         dso = load_system_driver(kind);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index d0435e7..b0743a5 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -25,8 +25,6 @@
 #include <utils/Singleton.h>
 #include <utils/String8.h>
 
-#include <gui/GraphicsEnv.h>
-
 #include <EGL/egl.h>
 
 // ----------------------------------------------------------------------------
@@ -56,9 +54,6 @@
     
     getProcAddressType getProcAddress;
 
-    void* mLibGui;
-    decltype(android_getDriverNamespace)* mGetDriverNamespace;
-
 public:
     ~Loader();
     
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 1672397..2782ed7 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
 #include <system/window.h>
 
 #include <EGL/egl.h>
@@ -1833,7 +1833,8 @@
 {
     clearError();
 
-    int usage = 0;
+    uint64_t producerUsage = 0;
+    uint64_t consumerUsage = 0;
     uint32_t width = 0;
     uint32_t height = 0;
     uint32_t format = 0;
@@ -1866,13 +1867,13 @@
                 GET_NONNEGATIVE_VALUE(EGL_LAYER_COUNT_ANDROID, layer_count);
                 case EGL_NATIVE_BUFFER_USAGE_ANDROID:
                     if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) {
-                        usage |= GRALLOC_USAGE_PROTECTED;
+                        producerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
                     }
                     if (value & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) {
-                        usage |= GRALLOC_USAGE_HW_RENDER;
+                        producerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
                     }
                     if (value & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID) {
-                        usage |= GRALLOC_USAGE_HW_TEXTURE;
+                        consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
                     }
                     break;
                 default:
@@ -1940,8 +1941,10 @@
     CHECK_ERROR_CONDITION("Unable to write format");
     err = data.writeUint32(layer_count);
     CHECK_ERROR_CONDITION("Unable to write layer count");
-     err = data.writeUint32(usage);
-    CHECK_ERROR_CONDITION("Unable to write usage");
+    err = data.writeUint64(producerUsage);
+    CHECK_ERROR_CONDITION("Unable to write producer usage");
+    err = data.writeUint64(consumerUsage);
+    CHECK_ERROR_CONDITION("Unable to write consumer usage");
     err = data.writeUtf8AsUtf16(
             std::string("[eglCreateNativeClientBufferANDROID pid ") +
             std::to_string(getpid()) + ']');
@@ -1958,12 +1961,15 @@
     err = gBuffer->initCheck();
     if (err != NO_ERROR) {
         ALOGE("Unable to create native buffer "
-                "{ w=%u, h=%u, f=%u, u=%#x, lc=%u}: %#x", width, height, format,
-                usage, layer_count, err);
+                "{ w=%u, h=%u, f=%u, pu=%" PRIx64 " cu=%" PRIx64 ", lc=%u} %#x",
+                width, height, format, producerUsage, consumerUsage,
+                layer_count, err);
         goto error_condition;
     }
-    ALOGV("Created new native buffer %p { w=%u, h=%u, f=%u, u=%#x, lc=%u}",
-            gBuffer, width, height, format, usage, layer_count);
+    ALOGV("Created new native buffer %p { w=%u, h=%u, f=%u, pu=%" PRIx64
+          " cu=%" PRIx64 ", lc=%u}",
+            gBuffer, width, height, format, producerUsage, consumerUsage,
+            layer_count);
     return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
 
 #undef CHECK_ERROR_CONDITION
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 2b9c38e..1cd40b3 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -20,7 +20,10 @@
 
 #include <EGL/egl.h>
 #include <gui/Surface.h>
-
+#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/BufferQueue.h>
 
 namespace android {
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 61e336f..de7795b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -213,7 +213,7 @@
     ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays");
 
     property_get("ro.sf.disable_triple_buffer", value, "0");
-    mLayerTripleBufferingDisabled = atoi(value);
+    mLayerTripleBufferingDisabled = !atoi(value);
     ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
 }
 
@@ -2275,6 +2275,7 @@
                 switch (layer->getCompositionType(hwcId)) {
                     case HWC2::Composition::Cursor:
                     case HWC2::Composition::Device:
+                    case HWC2::Composition::Sideband:
                     case HWC2::Composition::SolidColor: {
                         const Layer::State& state(layer->getDrawingState());
                         if (layer->getClearClientTarget(hwcId) && !firstLayer &&
diff --git a/services/vr/vr_window_manager/Android.mk_disable b/services/vr/vr_window_manager/Android.mk_disable
index 9a6f752..cc1db7b 100644
--- a/services/vr/vr_window_manager/Android.mk_disable
+++ b/services/vr/vr_window_manager/Android.mk_disable
@@ -14,6 +14,30 @@
 
 LOCAL_PATH := $(call my-dir)
 
+binder_src := \
+  vr_window_manager_binder.cpp \
+  aidl/android/service/vr/IVrWindowManager.aidl
+
+static_libs := \
+  libcutils
+
+shared_libs := \
+  libbase \
+  libbinder \
+  libutils
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(binder_src)
+LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"VrWindowManager\"
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := libvrwm_binder
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_STATIC_LIBRARY)
+
+
 native_src := \
   application.cpp \
   controller_mesh.cpp \
@@ -94,7 +118,7 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(native_src)
 LOCAL_C_INCLUDES := hardware/qcom/display/msm8996/libgralloc
-LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_STATIC_LIBRARIES := $(static_libs) libvrwm_binder
 LOCAL_SHARED_LIBRARIES := $(shared_libs)
 LOCAL_SHARED_LIBRARIES += libgvr
 LOCAL_STATIC_LIBRARIES += libgvr_ext
@@ -126,3 +150,27 @@
 LOCAL_AAPT_FLAGS += --extra-packages com.google.vr.cardboard
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 include $(BUILD_PACKAGE)
+
+
+cmd_src := \
+  vr_wm_ctl.cpp \
+  aidl/android/service/vr/IVrWindowManager.aidl
+
+static_libs := \
+  libcutils
+
+shared_libs := \
+  libbase \
+  libbinder \
+  libutils
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(cmd_src)
+LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"vrwmctl\"
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := vr_wm_ctl
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
diff --git a/services/vr/vr_window_manager/AndroidManifest.xml b/services/vr/vr_window_manager/AndroidManifest.xml
index 5cc4b5c..d5008a3 100644
--- a/services/vr/vr_window_manager/AndroidManifest.xml
+++ b/services/vr/vr_window_manager/AndroidManifest.xml
@@ -27,7 +27,7 @@
     <service android:name=".VrWindowManagerService" />
     <receiver android:name="com.google.vr.windowmanager.BootCompletedReceiver">
       <intent-filter>
-        <action android:name="android.intent.action.BOOT_COMPLETED" />
+        <!-- action android:name="android.intent.action.BOOT_COMPLETED" / -->
       </intent-filter>
     </receiver>
   </application>
diff --git a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
new file mode 100644
index 0000000..b5dbb8b
--- /dev/null
+++ b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2017, 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.
+ */
+
+package android.service.vr;
+
+/** @hide */
+interface IVrWindowManager {
+    const String SERVICE_NAME = "vr_window_manager";
+    void connectController(in FileDescriptor fd) = 0;
+    void disconnectController() = 1;
+    void enterVrMode() = 2;
+    void exitVrMode() = 3;
+    void setDebugMode(int mode) = 4;
+}
+
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index 62db639..895f25f 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -226,10 +226,8 @@
     if (fade_value_ > 1.0f)
       fade_value_ = 1.0f;
 
-    quat controller_quat(controller_orientation_.qw, controller_orientation_.qx,
-        controller_orientation_.qy, controller_orientation_.qz);
-    controller_position_ = elbow_model_.Update(
-        delta, last_pose_.GetRotation(), controller_quat, false);
+    controller_position_ = elbow_model_.Update(delta, last_pose_.GetRotation(),
+                                               controller_orientation_, false);
 
     dvrBeginRenderFrameEds(graphics_context_, pose.orientation,
                            pose.translation);
@@ -257,6 +255,61 @@
 }
 
 void Application::ProcessControllerInput() {
+  if (controller_data_provider_) {
+    shmem_controller_active_ = false;
+    const void* data = controller_data_provider_->LockControllerData();
+    // TODO(kpschoedel): define wire format.
+    if (data) {
+      struct wire_format {
+        uint32_t version;
+        uint32_t timestamph;
+        uint32_t timestampl;
+        uint32_t quat_count;
+        float q[4];
+        uint32_t buttonsh;
+        uint32_t buttonsl;
+      } __attribute__((__aligned__(32)));
+      const wire_format* wire_data = static_cast<const wire_format*>(data);
+      static uint64_t last_timestamp = 0;
+      if (wire_data->version == 1) {
+        shmem_controller_active_ = true;
+        uint64_t timestamp =
+            (((uint64_t)wire_data->timestamph) << 32) | wire_data->timestampl;
+        if (timestamp == last_timestamp) {
+          static uint64_t last_logged_timestamp = 0;
+          if (last_logged_timestamp != last_timestamp) {
+            last_logged_timestamp = last_timestamp;
+            ALOGI("Controller shmem stale T=0x%" PRIX64, last_timestamp);
+          }
+        } else {
+          last_timestamp = timestamp;
+          controller_orientation_ = quat(wire_data->q[3], wire_data->q[0],
+                                         wire_data->q[1], wire_data->q[2]);
+          shmem_controller_buttons_ =
+              (((uint64_t)wire_data->buttonsh) << 32) | wire_data->buttonsl;
+        }
+      } else if (wire_data->version == 0xFEEDFACE) {
+        static bool logged_init = false;
+        if (!logged_init) {
+          logged_init = true;
+          ALOGI("Controller shmem waiting for data");
+        }
+      }
+    }
+    controller_data_provider_->UnlockControllerData();
+    if (shmem_controller_active_) {
+      // TODO(kpschoedel): change to ALOGV or remove.
+      ALOGI("Controller shmem orientation: %f %f %f %f",
+            controller_orientation_.x(), controller_orientation_.y(),
+            controller_orientation_.z(), controller_orientation_.w());
+      if (shmem_controller_buttons_) {
+        ALOGI("Controller shmem buttons: %017" PRIX64,
+            shmem_controller_buttons_);
+      }
+      return;
+    }
+  }
+
   if (!controller_)
     return;
 
@@ -289,8 +342,11 @@
     controller_connection_state_logged_ = false;
   }
 
-  if (new_api_status == gvr::kControllerApiOk)
-    controller_orientation_ = controller_state_->GetOrientation();
+  if (new_api_status == gvr::kControllerApiOk) {
+    gvr_quatf orientation = controller_state_->GetOrientation();
+    controller_orientation_ =
+        quat(orientation.qw, orientation.qx, orientation.qy, orientation.qz);
+  }
 
   controller_api_status_ = new_api_status;
   controller_connection_state_ = new_connection_state;
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index 47a0927..0c6385f 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -11,6 +11,7 @@
 #include <chrono>
 #include <mutex>
 
+#include "controller_data_provider.h"
 #include "elbow_model.h"
 
 struct DvrGraphicsContext;
@@ -32,6 +33,10 @@
 
   void DrawFrame();
 
+  void SetControllerDataProvider(ControllerDataProvider* provider) {
+    controller_data_provider_ = provider;
+  }
+
  protected:
   enum class MainThreadTask {
     EnteringVrMode,
@@ -69,9 +74,11 @@
   std::unique_ptr<gvr::ControllerState> controller_state_;
   gvr::ControllerApiStatus controller_api_status_;
   gvr::ControllerConnectionState controller_connection_state_;
-  gvr_quatf controller_orientation_;
+  quat controller_orientation_;
+  bool shmem_controller_active_ = false;
   bool controller_api_status_logged_;
   bool controller_connection_state_logged_;
+  uint64_t shmem_controller_buttons_;
 
   bool is_visible_ = false;
   std::chrono::time_point<std::chrono::system_clock> visibility_button_press_;
@@ -93,6 +100,9 @@
   jobject app_context_;
   jobject class_loader_;
 
+  // Controller data provider from shared memory buffer.
+  ControllerDataProvider* controller_data_provider_ = nullptr;
+
   Application(const Application&) = delete;
   void operator=(const Application&) = delete;
 };
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index f83fa86..7e406a5 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -178,6 +178,11 @@
     }
   }
 
+  if (frame.empty()) {
+    ALOGE("Requested frame with no layers");
+    return Error::BAD_LAYER;
+  }
+
   // Increment the time the fence is signalled every time we get the
   // presentation frame. This ensures that calling ReleaseFrame() only affects
   // the current frame.
diff --git a/services/vr/vr_window_manager/controller_data_provider.h b/services/vr/vr_window_manager/controller_data_provider.h
new file mode 100644
index 0000000..bc1450c
--- /dev/null
+++ b/services/vr/vr_window_manager/controller_data_provider.h
@@ -0,0 +1,19 @@
+#ifndef VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_
+#define VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_
+
+namespace android {
+namespace dvr {
+
+class ControllerDataProvider {
+ public:
+  virtual ~ControllerDataProvider() {}
+  // Returns data pointer or nullptr. If pointer is valid, call to
+  // UnlockControllerData is required.
+  virtual const void* LockControllerData() = 0;
+  virtual void UnlockControllerData() = 0;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_
\ No newline at end of file
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 11680af..29ade64 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -190,14 +190,6 @@
   return layer_transform;
 }
 
-vec3 FromGvrVec3f(const gvr_vec3f& vec3f) {
-  return vec3(vec3f.x, vec3f.y, vec3f.z);
-}
-
-quat FromGvrQuatf(const gvr_quatf& quaternion) {
-  return quat(quaternion.qw, quaternion.qx, quaternion.qy, quaternion.qz);
-}
-
 // Determine if ths frame should be shown or hidden.
 ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
                                             uint32_t vr_app) {
@@ -302,15 +294,24 @@
 }
 
 void ShellView::EnableDebug(bool debug) {
+  ALOGI("EnableDebug(%d)", (int)debug); // XXX TODO delete
   QueueTask(debug ? MainThreadTask::EnableDebugMode
                   : MainThreadTask::DisableDebugMode);
 }
 
 void ShellView::VrMode(bool mode) {
+  ALOGI("VrMode(%d)", (int)mode); // XXX TODO delete
   QueueTask(mode ? MainThreadTask::EnteringVrMode
                  : MainThreadTask::ExitingVrMode);
 }
 
+void ShellView::dumpInternal(String8& result) {
+  result.append("[shell]\n");
+  result.appendFormat("initialized = %s\n", initialized_ ? "true" : "false");
+  result.appendFormat("is_visible = %s\n", is_visible_ ? "true" : "false");
+  result.appendFormat("debug_mode = %s\n\n", debug_mode_ ? "true" : "false");
+}
+
 void ShellView::AdvanceFrame() {
   if (!pending_frames_.empty()) {
     // Check if we should advance the frame.
@@ -398,7 +399,11 @@
 
   if (visibility == ViewMode::Hidden && debug_mode_)
     visibility = ViewMode::VR;
-  current_vr_app_ = frame->layers().front().appid;
+
+  if (frame->layers().empty())
+    current_vr_app_ = 0;
+  else
+    current_vr_app_ = frame->layers().front().appid;
 
   std::unique_lock<std::mutex> l(pending_frame_mutex_);
 
@@ -418,7 +423,8 @@
 
   // If we are showing ourselves the main thread is not processing anything,
   // so give it a kick.
-  if (visibility != ViewMode::Hidden && current_frame_.visibility == ViewMode::Hidden) {
+  if (visibility != ViewMode::Hidden &&
+      current_frame_.visibility == ViewMode::Hidden) {
     QueueTask(MainThreadTask::EnteringVrMode);
     QueueTask(MainThreadTask::Show);
   }
@@ -598,23 +604,50 @@
   vec3 pointer_location = last_pose_.GetPosition();
   quat view_quaternion = last_pose_.GetRotation();
 
-  if (controller_ && controller_api_status_ == gvr::kControllerApiOk) {
-    view_quaternion = FromGvrQuatf(controller_orientation_);
+  bool gvr_api_active =
+      controller_ && controller_api_status_ == gvr::kControllerApiOk;
+
+  if (gvr_api_active || shmem_controller_active_) {
+    view_quaternion = controller_orientation_;
     vec4 controller_location = controller_translate_ * vec4(0, 0, 0, 1);
     pointer_location = vec3(controller_location.x(), controller_location.y(),
                             controller_location.z());
 
-    if (controller_state_->GetButtonDown(gvr::kControllerButtonClick))
-      OnClick(true);
+    if (shmem_controller_active_) {
+      uint64_t buttons = shmem_controller_buttons_;
+      shmem_controller_buttons_ = 0;
+      while (buttons) {
+        switch (buttons & 0xF) {
+          case 0x1:
+            OnClick(false);
+            break;
+          case 0x3:
+            OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
+            break;
+          case 0x9:
+            OnClick(true);
+            break;
+          case 0xB:
+            OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK);
+            break;
+          default:
+            break;
+        }
+        buttons >>= 4;
+      }
+    } else if (controller_) {
+      if (controller_state_->GetButtonDown(gvr::kControllerButtonClick))
+        OnClick(true);
 
-    if (controller_state_->GetButtonUp(gvr::kControllerButtonClick))
-      OnClick(false);
+      if (controller_state_->GetButtonUp(gvr::kControllerButtonClick))
+        OnClick(false);
 
-    if (controller_state_->GetButtonDown(gvr::kControllerButtonApp))
-      OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK);
+      if (controller_state_->GetButtonDown(gvr::kControllerButtonApp))
+        OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK);
 
-    if (controller_state_->GetButtonUp(gvr::kControllerButtonApp))
-      OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
+      if (controller_state_->GetButtonUp(gvr::kControllerButtonApp))
+        OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
+    }
   }
 
   vec3 view_direction = vec3(view_quaternion * vec3(0, 0, -1));
@@ -643,7 +676,7 @@
 
 void ShellView::DrawController(const mat4& perspective, const mat4& eye_matrix,
                                const mat4& head_matrix) {
-  if (!controller_)
+  if (!controller_ && !shmem_controller_active_)
     return;
 
   controller_program_->Use();
@@ -653,7 +686,7 @@
       controller_program_->GetProgram(), "uViewProjection");
   glUniformMatrix4fv(view_projection_location, 1, 0, mvp.data());
 
-  quat view_quaternion = FromGvrQuatf(controller_orientation_);
+  quat view_quaternion = controller_orientation_;
   view_quaternion.toRotationMatrix();
 
   vec3 world_pos = last_pose_.GetPosition() + controller_position_;
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index ba46e6d..14ad0f3 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -9,6 +9,7 @@
 
 #include "application.h"
 #include "reticle.h"
+#include "shell_view_binder_interface.h"
 #include "surface_flinger_view.h"
 
 namespace android {
@@ -20,7 +21,9 @@
   App,
 };
 
-class ShellView : public Application, public HwcCallback::Client {
+class ShellView : public Application,
+                  public android::dvr::ShellViewBinderInterface,
+                  public HwcCallback::Client {
  public:
   ShellView();
   virtual ~ShellView();
@@ -31,8 +34,10 @@
   int AllocateResources() override;
   void DeallocateResources() override;
 
-  void EnableDebug(bool debug);
-  void VrMode(bool mode);
+  // ShellViewBinderInterface:
+  void EnableDebug(bool debug) override;
+  void VrMode(bool mode) override;
+  void dumpInternal(String8& result) override;
 
  protected:
   void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
diff --git a/services/vr/vr_window_manager/shell_view_binder_interface.h b/services/vr/vr_window_manager/shell_view_binder_interface.h
new file mode 100644
index 0000000..b58e4bd
--- /dev/null
+++ b/services/vr/vr_window_manager/shell_view_binder_interface.h
@@ -0,0 +1,20 @@
+#ifndef VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_
+#define VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_
+
+namespace android {
+namespace dvr {
+
+class ShellViewBinderInterface {
+ public:
+  ShellViewBinderInterface() {};
+  virtual ~ShellViewBinderInterface() {};
+
+  virtual void EnableDebug(bool debug) = 0;
+  virtual void VrMode(bool mode) = 0;
+  virtual void dumpInternal(String8& result) = 0;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_
diff --git a/services/vr/vr_window_manager/vr_window_manager.cpp b/services/vr/vr_window_manager/vr_window_manager.cpp
index 8d9ad79..c51ddee 100644
--- a/services/vr/vr_window_manager/vr_window_manager.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager.cpp
@@ -1,18 +1,33 @@
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 
 #include "shell_view.h"
+#include "vr_window_manager_binder.h"
 
 int main(int /* argc */, char** /* argv */) {
+  android::dvr::ShellView app;
+  const int app_status = app.Initialize(nullptr, nullptr, nullptr);
+  LOG_ALWAYS_FATAL_IF(app_status != 0, "failed to initialize: %d", app_status);
+
+  android::service::vr::VrWindowManagerBinder service(app);
+  const int status = service.Initialize();
+  LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status);
+
   android::ProcessState::self()->startThreadPool();
 
-  android::dvr::ShellView app;
-  if (app.Initialize(nullptr, nullptr, nullptr)) {
-    ALOGE("Failed to initialize");
-    return 1;
-  }
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+  const android::status_t service_status = sm->addService(
+      android::service::vr::VrWindowManagerBinder::SERVICE_NAME(), &service,
+      false /*allowIsolated*/);
+  LOG_ALWAYS_FATAL_IF(service_status != android::OK, "service not added: %d",
+                      static_cast<int>(service_status));
+
+  app.SetControllerDataProvider(&service);
 
   while (true)
     app.DrawFrame();
 
+  android::IPCThreadState::self()->joinThreadPool();
   return 0;
 }
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.cpp b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
new file mode 100644
index 0000000..c2138b7
--- /dev/null
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
@@ -0,0 +1,156 @@
+#include "vr_window_manager_binder.h"
+
+#include <inttypes.h>
+#include <sys/mman.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <binder/Status.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace service {
+namespace vr {
+
+namespace {
+const String16 kDumpPermission("android.permission.DUMP");
+const String16 kSendMeControllerInputPermission("TODO");  // TODO(kpschoedel)
+}  // anonymous namespace
+
+constexpr size_t AshmemControllerDataProvider::kRegionLength;
+
+status_t AshmemControllerDataProvider::Connect(const int in_fd) {
+  if (in_fd < 0) {
+    return BAD_VALUE;
+  }
+  if (fd_.get() >= 0) {
+    // The VrCore is dead. Long live the VrCore.
+    Disconnect();
+  }
+  void* const shared_region =
+      ::mmap(nullptr, kRegionLength, PROT_READ, MAP_SHARED, in_fd, 0);
+  if (shared_region == MAP_FAILED) {
+    shared_region_ = nullptr;
+    return NO_MEMORY;
+  }
+
+  errno = 0;
+  const int fd = ::fcntl(in_fd, F_DUPFD_CLOEXEC, 0);
+  if (fd < 0) {
+    ::munmap(shared_region, kRegionLength);
+    return -errno;
+  }
+  fd_.reset(fd);
+  ALOGI("controller connected %d -> %d @ %p", in_fd, fd, shared_region);
+
+  std::lock_guard<std::mutex> guard(mutex_);
+  shared_region_ = shared_region;
+  return OK;
+}
+
+status_t AshmemControllerDataProvider::Disconnect() {
+  if (shared_region_ == nullptr || fd_.get() < 0) {
+    return INVALID_OPERATION;
+  }
+  std::lock_guard<std::mutex> guard(mutex_);
+  ::munmap(shared_region_, kRegionLength);
+  shared_region_ = nullptr;
+  fd_.reset();
+  ALOGI("controller disconnected");
+  return OK;
+}
+
+const void* AshmemControllerDataProvider::LockControllerData() {
+  mutex_.lock();
+  if (!shared_region_) {
+    mutex_.unlock();
+    return nullptr;
+  }
+  return shared_region_;
+}
+
+void AshmemControllerDataProvider::UnlockControllerData() { mutex_.unlock(); }
+
+void AshmemControllerDataProvider::dumpInternal(String8& result) {
+  result.appendFormat("[controller]\nfd = %d\n", fd_.get());
+  if (shared_region_) {
+    int32_t* p = reinterpret_cast<int32_t*>(shared_region_);
+    result.appendFormat("header = ");
+    for (int i = 0; i < 8; ++i) {
+      result.appendFormat("%c 0x%08" PRIX32, i ? ',' : '[', p[i]);
+    }
+    result.appendFormat(" ]\n\n");
+  }
+}
+
+int VrWindowManagerBinder::Initialize() { return 0; }
+
+binder::Status VrWindowManagerBinder::connectController(
+    const ::android::base::unique_fd& in_fd) {
+  // TODO(kpschoedel): check permission
+#if 0
+  int32_t pid, uid;
+  if (!PermissionCache::checkCallingPermission(kSendMeControllerInputPermission,
+                                               &pid, &uid)) {
+    ALOGE("permission denied to pid=%" PRId32 " uid=%" PRId32, pid, uid);
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+#endif
+  return binder::Status::fromStatusT(Connect(in_fd.get()));
+}
+
+binder::Status VrWindowManagerBinder::disconnectController() {
+  // TODO(kpschoedel): check permission
+#if 0
+  int32_t pid, uid;
+  if (!PermissionCache::checkCallingPermission(kSendMeControllerInputPermission,
+                                               &pid, &uid)) {
+    ALOGE("permission denied to pid=%" PRId32 " uid=%" PRId32, pid, uid);
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+#endif
+  return binder::Status::fromStatusT(Disconnect());
+}
+
+binder::Status VrWindowManagerBinder::enterVrMode() {
+  // TODO(kpschoedel): check permission
+  app_.VrMode(true);
+  return binder::Status::ok();
+}
+
+binder::Status VrWindowManagerBinder::exitVrMode() {
+  // TODO(kpschoedel): check permission
+  app_.VrMode(false);
+  return binder::Status::ok();
+}
+
+binder::Status VrWindowManagerBinder::setDebugMode(int32_t mode) {
+  // TODO(kpschoedel): check permission
+  app_.EnableDebug(static_cast<bool>(mode));
+  return binder::Status::ok();
+}
+
+status_t VrWindowManagerBinder::dump(
+    int fd, const Vector<String16>& args [[gnu::unused]]) {
+  String8 result;
+  const android::IPCThreadState* ipc = android::IPCThreadState::self();
+  const int pid = ipc->getCallingPid();
+  const int uid = ipc->getCallingUid();
+  if ((uid != AID_SHELL) &&
+      !PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
+    result.appendFormat("Permission denial: can't dump " LOG_TAG
+                        " from pid=%d, uid=%d\n",
+                        pid, uid);
+  } else {
+    app_.dumpInternal(result);
+    AshmemControllerDataProvider::dumpInternal(result);
+  }
+  write(fd, result.string(), result.size());
+  return OK;
+}
+
+}  // namespace vr
+}  // namespace service
+}  // namespace android
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.h b/services/vr/vr_window_manager/vr_window_manager_binder.h
new file mode 100644
index 0000000..99ca27a
--- /dev/null
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.h
@@ -0,0 +1,77 @@
+#ifndef VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_
+#define VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_
+
+#include <android/service/vr/BnVrWindowManager.h>
+
+#include <mutex>
+
+#include "controller_data_provider.h"
+#include "shell_view_binder_interface.h"
+
+namespace android {
+namespace service {
+namespace vr {
+
+class AshmemControllerDataProvider : public dvr::ControllerDataProvider {
+ public:
+  AshmemControllerDataProvider() {}
+  virtual ~AshmemControllerDataProvider() {}
+
+  status_t Connect(int fd);
+  status_t Disconnect();
+
+  // ControllerDataProvider:
+  const void* LockControllerData() override;
+  void UnlockControllerData() override;
+
+ protected:
+  void dumpInternal(String8& result);
+
+ private:
+  static constexpr size_t kRegionLength = 8192;  // TODO(kpschoedel)
+  ::android::base::unique_fd fd_;
+
+  // Mutex for guarding shared_region_.
+  std::mutex mutex_;
+  void* shared_region_ = nullptr;
+
+  AshmemControllerDataProvider(const AshmemControllerDataProvider&) = delete;
+  void operator=(const AshmemControllerDataProvider&) = delete;
+};
+
+class VrWindowManagerBinder : public BnVrWindowManager,
+                              public AshmemControllerDataProvider {
+ public:
+  VrWindowManagerBinder(android::dvr::ShellViewBinderInterface& app)
+      : app_(app) {}
+  virtual ~VrWindowManagerBinder() {}
+
+  // Must be called before clients can connect.
+  // Returns 0 if initialization is successful.
+  int Initialize();
+  static char const* getServiceName() { return "vr_window_manager"; }
+
+ protected:
+  // Implements IVrWindowManagerBinder.
+  ::android::binder::Status connectController(
+      const ::android::base::unique_fd& fd) override;
+  ::android::binder::Status disconnectController() override;
+  ::android::binder::Status enterVrMode() override;
+  ::android::binder::Status exitVrMode() override;
+  ::android::binder::Status setDebugMode(int32_t mode) override;
+
+  // Implements BBinder::dump().
+  status_t dump(int fd, const Vector<String16>& args) override;
+
+ private:
+  android::dvr::ShellViewBinderInterface& app_;
+
+  VrWindowManagerBinder(const VrWindowManagerBinder&) = delete;
+  void operator=(const VrWindowManagerBinder&) = delete;
+};
+
+}  // namespace vr
+}  // namespace service
+}  // namespace android
+
+#endif  // VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder_test.cpp b/services/vr/vr_window_manager/vr_window_manager_binder_test.cpp
new file mode 100644
index 0000000..f43e803
--- /dev/null
+++ b/services/vr/vr_window_manager/vr_window_manager_binder_test.cpp
@@ -0,0 +1,29 @@
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/log.h>
+
+#include "vr_window_manager_binder.h"
+
+int main() {
+  ALOGI("Starting");
+  android::service::vr::VrWindowManagerBinder service;
+  const int status = service.Initialize();
+  LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status);
+
+  signal(SIGPIPE, SIG_IGN);
+  android::sp<android::ProcessState> ps(android::ProcessState::self());
+  ps->setThreadPoolMaxThreadCount(4);
+  ps->startThreadPool();
+  ps->giveThreadPoolName();
+
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+  const android::status_t service_status = sm->addService(
+      android::service::vr::VrWindowManagerBinder::SERVICE_NAME(), &service,
+      false /*allowIsolated*/);
+  LOG_ALWAYS_FATAL_IF(service_status != android::OK, "service not added: %d",
+                      static_cast<int>(service_status));
+
+  android::IPCThreadState::self()->joinThreadPool();
+  return 0;
+}
diff --git a/services/vr/vr_window_manager/vr_wm_ctl.cpp b/services/vr/vr_window_manager/vr_wm_ctl.cpp
new file mode 100644
index 0000000..c67b2eb
--- /dev/null
+++ b/services/vr/vr_window_manager/vr_wm_ctl.cpp
@@ -0,0 +1,48 @@
+#include <android/service/vr/BpVrWindowManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <inttypes.h>
+
+void usage() { fprintf(stderr, "usage: vr_wm_ctl [enter|exit|debug N]\n"); }
+
+int report(const android::binder::Status& status) {
+  if (status.isOk()) {
+    fprintf(stderr, "ok\n");
+    return 0;
+  }
+  fprintf(stderr, "failed (%" PRId32 ") %s\n", status.exceptionCode(),
+          status.exceptionMessage().string());
+  return (int)status.exceptionCode();
+}
+
+int main(int argc, char* argv[]) {
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+  if (sm == nullptr) {
+    fprintf(stderr, "service manager not found\n");
+    exit(1);
+  }
+
+  android::sp<android::service::vr::IVrWindowManager> vrwm =
+      android::interface_cast<android::service::vr::IVrWindowManager>(
+          sm->getService(
+              android::service::vr::IVrWindowManager::SERVICE_NAME()));
+  if (vrwm == nullptr) {
+    fprintf(stderr, "service not found\n");
+    exit(1);
+  }
+
+  android::binder::Status status;
+  if ((argc == 2) && (strcmp(argv[1], "enter") == 0)) {
+    exit(report(vrwm->enterVrMode()));
+  } else if ((argc == 2) && (strcmp(argv[1], "exit") == 0)) {
+    exit(report(vrwm->exitVrMode()));
+  } else if ((argc == 3) && (strcmp(argv[1], "debug") == 0)) {
+    exit(report(vrwm->setDebugMode(atoi(argv[2]))));
+  } else {
+    usage();
+    exit(2);
+  }
+
+  return 0;
+}
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 746ab4e..524de75 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -69,12 +69,12 @@
         "vulkan_headers",
     ],
     shared_libs: [
-        "libgui",
         "libziparchive",
         "libhardware",
         "libsync",
         "libbase",
         "liblog",
+        "libui",
         "libutils",
         "libcutils",
         "libz",
diff --git a/vulkan/libvulkan/debug_report.cpp b/vulkan/libvulkan/debug_report.cpp
index 0c2f138..40ba1e5 100644
--- a/vulkan/libvulkan/debug_report.cpp
+++ b/vulkan/libvulkan/debug_report.cpp
@@ -46,7 +46,8 @@
         Node* prev = &head_;
         while (prev && prev->next != node)
             prev = prev->next;
-        prev->next = node->next;
+        if (prev)
+            prev->next = node->next;
     }
 
     allocator.pfnFree(allocator.pUserData, node);
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index b34e9be..991c3ed 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,7 +28,7 @@
 
 #include <android/dlext.h>
 #include <cutils/properties.h>
-#include <gui/GraphicsEnv.h>
+#include <ui/GraphicsEnv.h>
 
 #include "driver.h"
 #include "stubhal.h"