Merge "vndservicemanager: load vendor service_contexts." into oc-dev
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..03af56d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index cba8f36..5421a75 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -820,28 +820,33 @@
     if (timeout < 20000) {
         timeout = 20000;
     }
-    RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+    RunCommand("SYSTEM LOG",
+               {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
                CommandOptions::WithTimeout(timeout / 1000).Build());
     timeout = logcat_timeout("events");
     if (timeout < 20000) {
         timeout = 20000;
     }
     RunCommand("EVENT LOG",
-               {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+               {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
                CommandOptions::WithTimeout(timeout / 1000).Build());
     timeout = logcat_timeout("radio");
     if (timeout < 20000) {
         timeout = 20000;
     }
     RunCommand("RADIO LOG",
-               {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+               {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
                CommandOptions::WithTimeout(timeout / 1000).Build());
 
     RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
 
     /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
     RunCommand("LAST LOGCAT",
-               {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
+                {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"});
 }
 
 static void DumpIpTables() {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 381e90c..c604ca0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -289,6 +289,46 @@
     return 0;
 }
 
+/**
+ * Ensure that we have a hard-limit quota to protect against abusive apps;
+ * they should never use more than 90% of blocks or 50% of inodes.
+ */
+static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
+        uid_t uid) {
+    if (device.empty()) return 0;
+
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        PLOG(WARNING) << "Failed to find quota for " << uid;
+        return -1;
+    }
+
+    if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
+        auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+        struct statvfs stat;
+        if (statvfs(path.c_str(), &stat) != 0) {
+            PLOG(WARNING) << "Failed to statvfs " << path;
+            return -1;
+        }
+
+        dq.dqb_valid = QIF_LIMITS;
+        dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
+        dq.dqb_ihardlimit = (stat.f_files / 2);
+        if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            PLOG(WARNING) << "Failed to set hard quota for " << uid;
+            return -1;
+        } else {
+            LOG(DEBUG) << "Applied hard quotas for " << uid;
+            return 0;
+        }
+    } else {
+        // Hard quota already set; assume it's reasonable
+        return 0;
+    }
+}
+
 binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
@@ -358,6 +398,10 @@
             return error("Failed to restorecon " + path);
         }
 
+        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
+            return error("Failed to set hard quota " + path);
+        }
+
         if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
             const std::string profile_dir =
                     create_primary_current_profile_package_dir_path(userId, pkgname);
@@ -709,6 +753,14 @@
             }
         }
     }
+
+    // Data under /data/media doesn't have an app, but we still want
+    // to limit it to prevent abuse.
+    if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
+            multiuser_get_uid(userId, AID_MEDIA_RW))) {
+        return error("Failed to set hard quota for media_rw");
+    }
+
     return ok();
 }
 
@@ -2006,6 +2058,17 @@
                     reinterpret_cast<char*>(&dq)) == 0) {
                 LOG(DEBUG) << "Found " << source << " with quota";
                 mQuotaDevices[target] = source;
+
+                // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
+                // need to kick it again to enable DQUOT_LIMITS_ENABLED.
+                if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+                        && errno != EBUSY) {
+                    PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
+                }
+                if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+                        && errno != EBUSY) {
+                    PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+                }
             }
         }
     }
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 360f71a..174ce77 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
 static int64_t free() {
     struct statvfs buf;
     if (!statvfs("/data/local/tmp", &buf)) {
-        return buf.f_bavail * buf.f_bsize;
+        return buf.f_bavail * buf.f_frsize;
     } else {
         PLOG(ERROR) << "Failed to statvfs";
         return -1;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index fbe6edf..24c0b45 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -629,11 +629,10 @@
     return res;
 }
 
-int64_t data_disk_free(const std::string& data_path)
-{
+int64_t data_disk_free(const std::string& data_path) {
     struct statvfs sfs;
     if (statvfs(data_path.c_str(), &sfs) == 0) {
-        return sfs.f_bavail * sfs.f_bsize;
+        return sfs.f_bavail * sfs.f_frsize;
     } else {
         PLOG(ERROR) << "Couldn't statvfs " << data_path;
         return -1;
@@ -1030,6 +1029,10 @@
     } else if (st.st_gid == gid && actual_mode == target_mode) {
         // Everything looks good!
         return 0;
+    } else {
+        // Mismatched GID/mode is recoverable; fall through to update
+        LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
+                << " but expected " << gid;
     }
 
     // Directory is owned correctly, but GID or mode mismatch means it's
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aee7bd8..aec211a 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -1,5 +1,5 @@
 service servicemanager /system/bin/servicemanager
-    class core
+    class core animation
     user system
     group system readproc
     critical
@@ -12,4 +12,3 @@
     onrestart restart drm
     onrestart restart cameraserver
     writepid /dev/cpuset/system-background/tasks
-
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 62f6cad..88ef010 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -257,10 +257,25 @@
     virtual int query(int what, int* value) const;
 
     virtual int connect(int api, const sp<IProducerListener>& listener);
+
+    // When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch
+    // GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or
+    // attachBuffer call. This allows clients with their own buffer caches to free up buffers no
+    // longer in use by this surface.
+    virtual int connect(
+            int api, const sp<IProducerListener>& listener,
+            bool reportBufferRemoval);
     virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
     virtual int attachBuffer(ANativeWindowBuffer*);
 
+    // When client connects to Surface with reportBufferRemoval set to true, any buffers removed
+    // from this Surface will be collected and returned here. Once this method returns, these
+    // buffers will no longer be referenced by this Surface unless they are attached to this
+    // Surface later. The list of removed buffers will only be stored until the next dequeueBuffer,
+    // detachNextBuffer, or attachBuffer call.
+    status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
+
 protected:
     enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
@@ -414,6 +429,9 @@
     // A cached copy of the FrameEventHistory maintained by the consumer.
     bool mEnableFrameTimestamps = false;
     std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
+
+    bool mReportRemovedBuffers = false;
+    std::vector<sp<GraphicBuffer>> mRemovedBuffers;
 };
 
 } // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 8acdfed..d4e4dc3 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -287,6 +287,9 @@
     }
 
     if (item->mGraphicBuffer != NULL) {
+        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+            freeBufferLocked(item->mSlot);
+        }
         mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
     }
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 06fc31d..1149b89 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -505,7 +505,11 @@
          mFrameEventHistory->applyDelta(frameTimestamps);
     }
 
-    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
+        if (mReportRemovedBuffers && (gbuf != nullptr)) {
+            mRemovedBuffers.clear();
+            mRemovedBuffers.push_back(gbuf);
+        }
         result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
         if (result != NO_ERROR) {
             ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
@@ -1075,10 +1079,16 @@
 }
 
 int Surface::connect(int api, const sp<IProducerListener>& listener) {
+    return connect(api, listener, false);
+}
+
+int Surface::connect(
+        int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
     ATRACE_CALL();
     ALOGV("Surface::connect");
     Mutex::Autolock lock(mMutex);
     IGraphicBufferProducer::QueueBufferOutput output;
+    mReportRemovedBuffers = reportBufferRemoval;
     int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
     if (err == NO_ERROR) {
         mDefaultWidth = output.width;
@@ -1109,6 +1119,7 @@
     ATRACE_CALL();
     ALOGV("Surface::disconnect");
     Mutex::Autolock lock(mMutex);
+    mRemovedBuffers.clear();
     mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
     mSharedBufferHasBeenQueued = false;
     freeAllBuffers();
@@ -1156,9 +1167,16 @@
         *outFence = Fence::NO_FENCE;
     }
 
+    if (mReportRemovedBuffers) {
+        mRemovedBuffers.clear();
+    }
+
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         if (mSlots[i].buffer != NULL &&
                 mSlots[i].buffer->handle == buffer->handle) {
+            if (mReportRemovedBuffers) {
+                mRemovedBuffers.push_back(mSlots[i].buffer);
+            }
             mSlots[i].buffer = NULL;
         }
     }
@@ -1184,6 +1202,10 @@
         graphicBuffer->mGenerationNumber = priorGeneration;
         return result;
     }
+    if (mReportRemovedBuffers && (mSlots[attachedSlot].buffer != nullptr)) {
+        mRemovedBuffers.clear();
+        mRemovedBuffers.push_back(mSlots[attachedSlot].buffer);
+    }
     mSlots[attachedSlot].buffer = graphicBuffer;
 
     return NO_ERROR;
@@ -1617,4 +1639,16 @@
     return mGraphicBufferProducer->getUniqueId(outId);
 }
 
+status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out must not be null!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    *out = mRemovedBuffers;
+    mRemovedBuffers.clear();
+    return OK;
+}
+
 }; // namespace android
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 03297ca..e35bfc9 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -538,6 +538,12 @@
     for (auto& change : mChanges->getTypeChanges()) {
         auto layerId = change.first;
         auto type = change.second;
+        if (mDevice.mLayers.count(layerId) == 0) {
+            // This should never happen but somehow does.
+            ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+                  layerId);
+            continue;
+        }
         auto layer = mDevice.mLayers[layerId];
         layer->setCompositionType(type);
     }
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 1ed150b..a38b4dc 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -28,6 +28,7 @@
 #include <ui/GraphicBuffer.h>
 #include <system/graphics.h>
 #include <hardware/gralloc1.h>
+#include <grallocusage/GrallocUsageConversion.h>
 
 #include <private/android/AHardwareBufferHelpers.h>
 
@@ -100,8 +101,12 @@
     outDesc->width = gbuffer->getWidth();
     outDesc->height = gbuffer->getHeight();
     outDesc->layers = gbuffer->getLayerCount();
+
+    uint64_t producerUsage = 0;
+    uint64_t consumerUsage = 0;
+    android_convertGralloc0To1Usage(gbuffer->getUsage(), &producerUsage, &consumerUsage);
     AHardwareBuffer_convertFromGrallocUsageBits(&outDesc->usage0, &outDesc->usage1,
-            gbuffer->getUsage(), gbuffer->getUsage());
+            producerUsage, consumerUsage);
     outDesc->format = AHardwareBuffer_convertFromPixelFormat(
             static_cast<uint32_t>(gbuffer->getPixelFormat()));
 }
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c0c4ac0..6c67cf8 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -25,6 +25,8 @@
 
 #include <private/android/AHardwareBufferHelpers.h>
 
+#include <ui/GraphicBuffer.h>
+
 using namespace android;
 
 static int32_t query(ANativeWindow* window, int what) {
@@ -105,6 +107,10 @@
  * vndk-stable
  **************************************************************************************************/
 
+AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb) {
+    return AHardwareBuffer_from_GraphicBuffer(static_cast<GraphicBuffer*>(anwb));
+}
+
 int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value) {
     if (slot < 4) {
         window->oem[slot] = value;
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index 310e1e5..067046b 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -99,8 +99,12 @@
 
 typedef struct ANativeWindowBuffer ANativeWindowBuffer;
 
-/*****************************************************************************/
+/*
+ * Convert this ANativeWindowBuffer into a AHardwareBuffer
+ */
+AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb);
 
+/*****************************************************************************/
 
 /*
  * Stores a value into one of the 4 available slots
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 2d96638..0fa1f01 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -42,7 +42,7 @@
 
 cc_library {
     name: "libbufferhubqueue",
-    cflags = [
+    cflags: [
         "-DLOG_TAG=\"libbufferhubqueue\"",
         "-DTRACE=0",
     ],
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index bd6511d..031401a 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -146,7 +146,7 @@
     ALOGW(
         "Receives EPOLLHUP at slot: %zu, buffer event fd: %d, EPOLLHUP "
         "pending: %d",
-        slot, buffer->event_fd(), epollhup_pending_[slot]);
+        slot, buffer->event_fd(), int{epollhup_pending_[slot]});
     if (epollhup_pending_[slot]) {
       epollhup_pending_[slot] = false;
     } else {
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 1879127..f059453 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -6,10 +6,16 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include <chrono>
+#include <thread>
+
 #include <uds/channel_manager.h>
 #include <uds/client_channel.h>
 #include <uds/ipc_helper.h>
 
+using std::chrono::duration_cast;
+using std::chrono::steady_clock;
+
 namespace android {
 namespace pdx {
 namespace uds {
@@ -41,13 +47,11 @@
 
 Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
     int64_t timeout_ms) const {
-  auto status = WaitForEndpoint(endpoint_path_, timeout_ms);
-  if (!status)
-    return ErrorStatus(status.error());
+  Status<void> status;
 
   LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)};
   if (!socket_fd) {
-    ALOGE("ClientChannelFactory::Connect: socket error %s", strerror(errno));
+    ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
     return ErrorStatus(errno);
   }
 
@@ -56,16 +60,55 @@
   strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
   remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
 
-  int ret = RETRY_EINTR(connect(
-      socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
-  if (ret == -1) {
-    ALOGE(
-        "ClientChannelFactory::Connect: Failed to initialize connection when "
-        "connecting %s",
-        strerror(errno));
-    return ErrorStatus(errno);
-  }
+  bool use_timeout = (timeout_ms >= 0);
+  auto now = steady_clock::now();
+  auto time_end = now + std::chrono::milliseconds{timeout_ms};
 
+  bool connected = false;
+  while (!connected) {
+    int64_t timeout = -1;
+    if (use_timeout) {
+      auto remaining = time_end - now;
+      timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
+      if (timeout < 0)
+        return ErrorStatus(ETIMEDOUT);
+    }
+    ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
+    status = WaitForEndpoint(endpoint_path_, timeout);
+    if (!status)
+      return ErrorStatus(status.error());
+
+    ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
+    int ret = RETRY_EINTR(connect(
+        socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
+    if (ret == -1) {
+      ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
+            strerror(errno));
+      if (errno == ECONNREFUSED) {
+        // Connection refused can be the result of connecting too early (the
+        // service socket is created but not being listened to yet).
+        ALOGD("ClientChannelFactory: Connection refused, waiting...");
+        using namespace std::literals::chrono_literals;
+        std::this_thread::sleep_for(100ms);
+      } else if (errno != ENOENT && errno != ENOTDIR) {
+        // ENOENT/ENOTDIR might mean that the socket file/directory containing
+        // it has been just deleted. Try to wait for its creation and do not
+        // return an error immediately.
+        ALOGE(
+            "ClientChannelFactory::Connect: Failed to initialize connection "
+            "when connecting: %s",
+            strerror(errno));
+        return ErrorStatus(errno);
+      }
+    } else {
+      connected = true;
+    }
+    if (use_timeout)
+      now = steady_clock::now();
+  }  // while (!connected)
+
+  ALOGD("ClientChannelFactory: Connected successfully to %s...",
+        remote.sun_path);
   RequestHeader<BorrowedHandle> request;
   InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
   status = SendData(socket_fd.Get(), request);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f82b363..834c1c4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1903,7 +1903,8 @@
                         // etc.) but no internal state (i.e. a DisplayDevice).
                         if (state.surface != NULL) {
 
-                            if (mUseHwcVirtualDisplays) {
+                            // Allow VR composer to use virtual displays.
+                            if (mUseHwcVirtualDisplays || mHwc == mVrHwc) {
                                 int width = 0;
                                 int status = state.surface->query(
                                         NATIVE_WINDOW_WIDTH, &width);
@@ -2839,15 +2840,17 @@
 
     sp<Layer> layer;
 
+    String8 uniqueName = getUniqueLayerName(name);
+
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceNormal:
             result = createNormalLayer(client,
-                    name, w, h, flags, format,
+                    uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceDim:
             result = createDimLayer(client,
-                    name, w, h, flags,
+                    uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
         default:
@@ -2871,6 +2874,30 @@
     return result;
 }
 
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+    bool matchFound = true;
+    uint32_t dupeCounter = 0;
+
+    // Tack on our counter whether there is a hit or not, so everyone gets a tag
+    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+    // Loop over layers until we're sure there is no matching name
+    while (matchFound) {
+        matchFound = false;
+        mDrawingState.traverseInZOrder([&](Layer* layer) {
+            if (layer->getName() == uniqueName) {
+                matchFound = true;
+                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+            }
+        });
+    }
+
+    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+    return uniqueName;
+}
+
 status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 581bbfd..4ecbddd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -364,6 +364,8 @@
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
             sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
 
+    String8 getUniqueLayerName(const String8& name);
+
     // called in response to the window-manager calling
     // ISurfaceComposerClient::destroySurface()
     status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index c26847f..a6c0b9c 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2637,15 +2637,17 @@
 
     sp<Layer> layer;
 
+    String8 uniqueName = getUniqueLayerName(name);
+
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceNormal:
             result = createNormalLayer(client,
-                    name, w, h, flags, format,
+                    uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceDim:
             result = createDimLayer(client,
-                    name, w, h, flags,
+                    uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
         default:
@@ -2669,6 +2671,30 @@
     return result;
 }
 
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+    bool matchFound = true;
+    uint32_t dupeCounter = 0;
+
+    // Tack on our counter whether there is a hit or not, so everyone gets a tag
+    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+    // Loop over layers until we're sure there is no matching name
+    while (matchFound) {
+        matchFound = false;
+        mDrawingState.traverseInZOrder([&](Layer* layer) {
+            if (layer->getName() == uniqueName) {
+                matchFound = true;
+                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+            }
+        });
+    }
+
+    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+    return uniqueName;
+}
+
 status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 435aa0c..0b482f7 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -1,5 +1,5 @@
 service surfaceflinger /system/bin/surfaceflinger
-    class core
+    class core animation
     user system
     group graphics drmrpc readproc
     onrestart restart zygote
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index c1a0b6f..b3d777e 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -30,7 +30,6 @@
 sharedLibraries := \
 	libbase \
 	libcutils \
-	libhardware \
 	liblog \
 	libsync \
 	libutils \
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 98a419f..43010b0 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -238,7 +238,7 @@
 
   ClearAvailable();
   producer_owns_ = true;
-  post_fence_.get_fd();
+  post_fence_.close();
   return std::move(returned_fence_);
 }
 
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
index 5d3c4f7..52d4da8 100644
--- a/services/vr/hardware_composer/vr_hwc.rc
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -3,4 +3,3 @@
   user system
   group system graphics
   onrestart restart surfaceflinger
-  disabled
diff --git a/services/vr/vr_window_manager/Android.bp b/services/vr/vr_window_manager/Android.bp
index a7a341c..0406331 100644
--- a/services/vr/vr_window_manager/Android.bp
+++ b/services/vr/vr_window_manager/Android.bp
@@ -41,6 +41,7 @@
     "libperformance",
     "libpdx_default_transport",
     "libcutils",
+    "libvr_hwc-binder",
     "libvr_manager",
     "libvirtualtouchpadclient",
 ]
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 19b220b..43f5042 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,26 +38,29 @@
 HwcCallback::~HwcCallback() {
 }
 
-base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& display_frame) {
-  auto& frame = display_frame.layers;
-  std::vector<HwcLayer> hwc_frame(frame.size());
-
-  for (size_t i = 0; i < frame.size(); ++i) {
+binder::Status HwcCallback::onNewFrame(
+    const ParcelableComposerFrame& parcelable_frame,
+    ParcelableUniqueFd* fence) {
+  ComposerView::Frame frame = parcelable_frame.frame();
+  std::vector<HwcLayer> hwc_frame(frame.layers.size());
+  for (size_t i = 0; i < frame.layers.size(); ++i) {
+    const ComposerView::ComposerLayer& layer = frame.layers[i];
     hwc_frame[i] = HwcLayer{
-      .fence = frame[i].fence,
-      .buffer = frame[i].buffer,
-      .crop = frame[i].crop,
-      .display_frame = frame[i].display_frame,
-      .blending = static_cast<int32_t>(frame[i].blend_mode),
-      .appid = frame[i].app_id,
-      .type = static_cast<HwcLayer::LayerType>(frame[i].type),
-      .alpha = frame[i].alpha,
+      .fence = layer.fence,
+      .buffer = layer.buffer,
+      .crop = layer.crop,
+      .display_frame = layer.display_frame,
+      .blending = static_cast<int32_t>(layer.blend_mode),
+      .appid = layer.app_id,
+      .type = static_cast<HwcLayer::LayerType>(layer.type),
+      .alpha = layer.alpha,
     };
   }
 
-  return client_->OnFrame(std::make_unique<Frame>(
-      std::move(hwc_frame), display_frame.display_id, display_frame.removed,
-      display_frame.display_width, display_frame.display_height));
+  fence->set_fence(client_->OnFrame(std::make_unique<Frame>(
+      std::move(hwc_frame), frame.display_id, frame.removed,
+      frame.display_width, frame.display_height)));
+  return binder::Status::ok();
 }
 
 HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id,
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index c0d965a..f1f91a1 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -1,14 +1,16 @@
 #ifndef VR_WINDOW_MANAGER_HWC_CALLBACK_H_
 #define VR_WINDOW_MANAGER_HWC_CALLBACK_H_
 
+#include <android/dvr/BnVrComposerCallback.h>
+#include <android-base/unique_fd.h>
+
 #include <deque>
 #include <functional>
 #include <mutex>
 #include <vector>
 
-#include <android-base/unique_fd.h>
-#include <impl/vr_composer_view.h>
-#include <impl/vr_hwc.h>
+#include "impl/vr_composer_view.h"
+#include "impl/vr_hwc.h"
 
 namespace android {
 
@@ -20,7 +22,7 @@
 using Recti = ComposerView::ComposerLayer::Recti;
 using Rectf = ComposerView::ComposerLayer::Rectf;
 
-class HwcCallback : public VrComposerView::Callback {
+class HwcCallback : public BnVrComposerCallback {
  public:
   struct HwcLayer {
     enum LayerType : uint32_t {
@@ -110,7 +112,8 @@
   ~HwcCallback() override;
 
  private:
-  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+  binder::Status onNewFrame(const ParcelableComposerFrame& frame,
+                            ParcelableUniqueFd* fence) override;
 
   Client *client_;
 
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index c0ee1fc..aef23a1 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,5 +1,7 @@
 #include "surface_flinger_view.h"
 
+#include <android/dvr/IVrComposer.h>
+#include <binder/IServiceManager.h>
 #include <impl/vr_composer_view.h>
 #include <private/dvr/native_buffer.h>
 
@@ -14,22 +16,20 @@
 SurfaceFlingerView::~SurfaceFlingerView() {}
 
 bool SurfaceFlingerView::Initialize(HwcCallback::Client *client) {
-  const char vr_hwcomposer_name[] = "vr";
-  vr_hwcomposer_ = HIDL_FETCH_IComposer(vr_hwcomposer_name);
-  if (!vr_hwcomposer_.get()) {
-    ALOGE("Failed to get vr_hwcomposer");
+  sp<IServiceManager> sm(defaultServiceManager());
+  vr_composer_ = interface_cast<IVrComposer>(
+      sm->getService(IVrComposer::SERVICE_NAME()));
+
+  String8 service_name(IVrComposer::SERVICE_NAME().string());
+  if (!vr_composer_.get()) {
+    ALOGE("Faild to connect to %s", service_name.c_str());
     return false;
   }
 
-  if (vr_hwcomposer_->isRemote()) {
-    ALOGE("vr_hwcomposer service is remote");
-    return false;
-  }
-
-  const android::status_t vr_hwcomposer_status =
-      vr_hwcomposer_->registerAsService(vr_hwcomposer_name);
-  if (vr_hwcomposer_status != OK) {
-    ALOGE("Failed to register vr_hwcomposer service");
+  composer_callback_ = new HwcCallback(client);
+  binder::Status status = vr_composer_->registerObserver(composer_callback_);
+  if (!status.isOk()) {
+    ALOGE("Failed to register observer with %s", service_name.c_str());
     return false;
   }
 
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 3ea2b21..1bea38d 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -3,14 +3,13 @@
 
 #include <memory>
 
-#include <impl/vr_composer_view.h>
-
 #include "hwc_callback.h"
 
 namespace android {
 namespace dvr {
 
 class IDisplay;
+class IVrComposer;
 class Texture;
 
 struct TextureLayer {
@@ -34,8 +33,8 @@
                    bool skip_first_layer) const;
 
  private:
-  sp<IComposer> vr_hwcomposer_;
-  std::unique_ptr<VrComposerView> vr_composer_view_;
+  sp<IVrComposer> vr_composer_;
+  sp<HwcCallback> composer_callback_;
 
   SurfaceFlingerView(const SurfaceFlingerView&) = delete;
   void operator=(const SurfaceFlingerView&) = delete;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 5574da2..2fee8a5 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -183,7 +183,9 @@
         : surface(surface_),
           num_images(num_images_),
           mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR),
-          frame_timestamps_enabled(false) {
+          frame_timestamps_enabled(false),
+          shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
+                 present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
         ANativeWindow* window = surface.window.get();
         int64_t rdur;
         native_window_get_refresh_cycle_duration(
@@ -197,6 +199,7 @@
     bool mailbox_mode;
     bool frame_timestamps_enabled;
     uint64_t refresh_duration;
+    bool shared;
 
     struct Image {
         Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
@@ -927,6 +930,25 @@
         return VK_ERROR_SURFACE_LOST_KHR;
     }
 
+    VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
+    if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
+        create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
+        swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID;
+        err = native_window_set_shared_buffer_mode(surface.window.get(), true);
+        if (err != 0) {
+            ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+    }
+
+    if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
+        err = native_window_set_auto_refresh(surface.window.get(), true);
+        if (err != 0) {
+            ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+    }
+
     int query_value;
     err = surface.window->query(surface.window.get(),
                                 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -941,7 +963,13 @@
     uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
     uint32_t num_images =
         (create_info->minImageCount - 1) + min_undequeued_buffers;
-    err = native_window_set_buffer_count(surface.window.get(), num_images);
+
+    // Lower layer insists that we have at least two buffers. This is wasteful
+    // and we'd like to relax it in the shared case, but not all the pieces are
+    // in place for that to work yet. Note we only lie to the lower layer-- we
+    // don't want to give the app back a swapchain with extra images (which they
+    // can't actually use!).
+    err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images));
     if (err != 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
@@ -950,26 +978,6 @@
         return VK_ERROR_SURFACE_LOST_KHR;
     }
 
-    VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
-    if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
-        create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
-        swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID;
-
-        err = native_window_set_shared_buffer_mode(surface.window.get(), true);
-        if (err != 0) {
-            ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
-            return VK_ERROR_SURFACE_LOST_KHR;
-        }
-    }
-
-    if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
-        err = native_window_set_auto_refresh(surface.window.get(), true);
-        if (err != 0) {
-            ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
-            return VK_ERROR_SURFACE_LOST_KHR;
-        }
-    }
-
     int gralloc_usage = 0;
     if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
         uint64_t consumer_usage, producer_usage;
@@ -1106,17 +1114,19 @@
     //
     // TODO(jessehall): The error path here is the same as DestroySwapchain,
     // but not the non-error path. Should refactor/unify.
-    for (uint32_t i = 0; i < num_images; i++) {
-        Swapchain::Image& img = swapchain->images[i];
-        if (img.dequeued) {
-            surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
-                                         img.dequeue_fence);
-            img.dequeue_fence = -1;
-            img.dequeued = false;
-        }
-        if (result != VK_SUCCESS) {
-            if (img.image)
-                dispatch.DestroyImage(device, img.image, nullptr);
+    if (!swapchain->shared) {
+        for (uint32_t i = 0; i < num_images; i++) {
+            Swapchain::Image& img = swapchain->images[i];
+            if (img.dequeued) {
+                surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
+                                             img.dequeue_fence);
+                img.dequeue_fence = -1;
+                img.dequeued = false;
+            }
+            if (result != VK_SUCCESS) {
+                if (img.image)
+                    dispatch.DestroyImage(device, img.image, nullptr);
+            }
         }
     }
 
@@ -1200,6 +1210,16 @@
         timeout != UINT64_MAX,
         "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
 
+    if (swapchain.shared) {
+        // In shared mode, we keep the buffer dequeued all the time, so we don't
+        // want to dequeue a buffer here. Instead, just ask the driver to ensure
+        // the semaphore and fence passed to us will be signalled.
+        *image_index = 0;
+        result = GetData(device).driver.AcquireImageANDROID(
+                device, swapchain.images[*image_index].image, -1, semaphore, vk_fence);
+        return result;
+    }
+
     ANativeWindowBuffer* buffer;
     int fence_fd;
     err = window->dequeueBuffer(window, &buffer, &fence_fd);
@@ -1420,6 +1440,7 @@
                             static_cast<int64_t>(time->desiredPresentTime));
                     }
                 }
+
                 err = window->queueBuffer(window, img.buffer.get(), fence);
                 // queueBuffer always closes fence, even on error
                 if (err != 0) {
@@ -1434,6 +1455,30 @@
                     img.dequeue_fence = -1;
                 }
                 img.dequeued = false;
+
+                // If the swapchain is in shared mode, immediately dequeue the
+                // buffer so it can be presented again without an intervening
+                // call to AcquireNextImageKHR. We expect to get the same buffer
+                // back from every call to dequeueBuffer in this mode.
+                if (swapchain.shared && swapchain_result == VK_SUCCESS) {
+                    ANativeWindowBuffer* buffer;
+                    int fence_fd;
+                    err = window->dequeueBuffer(window, &buffer, &fence_fd);
+                    if (err != 0) {
+                        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
+                        swapchain_result = WorstPresentResult(swapchain_result,
+                            VK_ERROR_SURFACE_LOST_KHR);
+                    }
+                    else if (img.buffer != buffer) {
+                        ALOGE("got wrong image back for shared swapchain");
+                        swapchain_result = WorstPresentResult(swapchain_result,
+                            VK_ERROR_SURFACE_LOST_KHR);
+                    }
+                    else {
+                        img.dequeue_fence = fence_fd;
+                        img.dequeued = true;
+                    }
+                }
             }
             if (swapchain_result != VK_SUCCESS) {
                 ReleaseSwapchainImage(device, window, fence, img);