Merge "SF: Add systrace lines for layer transactions"
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index abf7b06..5548699 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -14,9 +14,6 @@
         "libz",
         "libbase",
     ],
-    static_libs: [
-        "libpdx_default_transport",
-    ],
 
     init_rc: ["atrace.rc"],
 
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 1ce88b9..054b00e 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -39,7 +39,6 @@
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 
-#include <pdx/default_transport/service_utility.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
@@ -50,7 +49,6 @@
 #include <android-base/stringprintf.h>
 
 using namespace android;
-using pdx::default_transport::ServiceUtility;
 
 using std::string;
 
@@ -809,7 +807,6 @@
     ok &= setAppCmdlineProperty(&packageList[0]);
     ok &= pokeBinderServices();
     pokeHalServices();
-    ok &= ServiceUtility::PokeServices();
 
     // Disable all the sysfs enables.  This is done as a separate loop from
     // the enables to allow the same enable to exist in multiple categories.
@@ -847,7 +844,6 @@
     setTagsProperty(0);
     clearAppProperties();
     pokeBinderServices();
-    ServiceUtility::PokeServices();
 
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 73d274f..7e05d72 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -123,6 +123,13 @@
 {
     signal(SIGPIPE, SIG_IGN);
     sp<ProcessState> proc = ProcessState::self();
+    // setThreadPoolMaxThreadCount(0) actually tells the kernel it's
+    // not allowed to spawn any additional threads, but we still spawn
+    // a binder thread from userspace when we call startThreadPool().
+    // This is safe because we only have 2 callbacks, neither of which
+    // block.
+    // See b/36066697 for rationale
+    proc->setThreadPoolMaxThreadCount(0);
     proc->startThreadPool();
 
     sp<IServiceManager> sm = defaultServiceManager();
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a0d987d..6e89f3a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1782,6 +1782,16 @@
     return ok();
 }
 
+// Copy the contents of a system profile over the data profile.
+binder::Status InstalldNativeService::copySystemProfile(const std::string& systemProfile,
+        int32_t packageUid, const std::string& packageName, bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+    *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName);
+    return ok();
+}
+
 // TODO: Consider returning error codes.
 binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
         bool* _aidl_return) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 200fc77..a94223c 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -91,6 +91,8 @@
     binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
     binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
             const std::string& codePaths, bool* _aidl_return);
+    binder::Status copySystemProfile(const std::string& systemProfile,
+            int32_t uid, const std::string& packageName, bool* _aidl_return);
     binder::Status clearAppProfiles(const std::string& packageName);
     binder::Status destroyAppProfiles(const std::string& packageName);
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 6b99c1d..efcae4f 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -57,6 +57,8 @@
 
     boolean mergeProfiles(int uid, @utf8InCpp String packageName);
     boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+    boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
+            @utf8InCpp String packageName);
     void clearAppProfiles(@utf8InCpp String packageName);
     void destroyAppProfiles(@utf8InCpp String packageName);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 3bbe3a1..5a78d78 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -847,6 +847,66 @@
     return true;
 }
 
+bool copy_system_profile(const std::string& system_profile,
+        uid_t packageUid, const std::string& data_profile_location) {
+    unique_fd in_fd(open(system_profile.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+    unique_fd out_fd(open_reference_profile(packageUid,
+                     data_profile_location,
+                     /*read_write*/ true,
+                     /*secondary*/ false));
+    if (in_fd.get() < 0) {
+        PLOG(WARNING) << "Could not open profile " << system_profile;
+        return false;
+    }
+    if (out_fd.get() < 0) {
+        PLOG(WARNING) << "Could not open profile " << data_profile_location;
+        return false;
+    }
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        drop_capabilities(packageUid);
+
+        if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
+            if (errno != EWOULDBLOCK) {
+                PLOG(WARNING) << "Error locking profile " << data_profile_location;
+            }
+            // This implies that the app owning this profile is running
+            // (and has acquired the lock).
+            //
+            // The app never acquires the lock for the reference profiles of primary apks.
+            // Only dex2oat from installd will do that. Since installd is single threaded
+            // we should not see this case. Nevertheless be prepared for it.
+            PLOG(WARNING) << "Failed to flock " << data_profile_location;
+            return false;
+        }
+
+        bool truncated = ftruncate(out_fd.get(), 0) == 0;
+        if (!truncated) {
+            PLOG(WARNING) << "Could not truncate " << data_profile_location;
+        }
+
+        // Copy over data.
+        static constexpr size_t kBufferSize = 4 * 1024;
+        char buffer[kBufferSize];
+        while (true) {
+            ssize_t bytes = read(in_fd.get(), buffer, kBufferSize);
+            if (bytes == 0) {
+                break;
+            }
+            write(out_fd.get(), buffer, bytes);
+        }
+        if (flock(out_fd.get(), LOCK_UN) != 0) {
+            PLOG(WARNING) << "Error unlocking profile " << data_profile_location;
+        }
+        exit(0);
+    }
+    /* parent */
+    int return_code = wait_child(pid);
+    return return_code == 0;
+}
+
 static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) {
   // A standard dalvik-cache entry. Replace ".dex" with `new_ext`.
   if (EndsWith(oat_path, ".dex")) {
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index cb8aaeb..d171ee5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -50,6 +50,10 @@
 
 bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
 
+bool copy_system_profile(const std::string& system_profile,
+                         uid_t packageUid,
+                         const std::string& data_profile_location);
+
 bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
 
 bool reconcile_secondary_dex_file(const std::string& dex_path,
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 299ea17..43d0780 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -734,6 +734,10 @@
     }
 
     static const char* ParseNull(const char* arg) {
+        // b/38186355. Revert soon.
+        if (strcmp(arg, "!null") == 0) {
+            return nullptr;
+        }
         return (strcmp(arg, "!") == 0) ? nullptr : arg;
     }
 
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
new file mode 100644
index 0000000..86da4d3
--- /dev/null
+++ b/include/input/DisplayViewport.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
+#define _LIBINPUT_DISPLAY_VIEWPORT_H
+
+#include <ui/DisplayInfo.h>
+#include <input/Input.h>
+
+namespace android {
+
+/*
+ * Describes how coordinates are mapped on a physical display.
+ * See com.android.server.display.DisplayViewport.
+ */
+struct DisplayViewport {
+    int32_t displayId; // -1 if invalid
+    int32_t orientation;
+    int32_t logicalLeft;
+    int32_t logicalTop;
+    int32_t logicalRight;
+    int32_t logicalBottom;
+    int32_t physicalLeft;
+    int32_t physicalTop;
+    int32_t physicalRight;
+    int32_t physicalBottom;
+    int32_t deviceWidth;
+    int32_t deviceHeight;
+    String8 uniqueId;
+
+    DisplayViewport() :
+            displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
+            logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
+            physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
+            deviceWidth(0), deviceHeight(0) {
+    }
+
+    bool operator==(const DisplayViewport& other) const {
+        return displayId == other.displayId
+                && orientation == other.orientation
+                && logicalLeft == other.logicalLeft
+                && logicalTop == other.logicalTop
+                && logicalRight == other.logicalRight
+                && logicalBottom == other.logicalBottom
+                && physicalLeft == other.physicalLeft
+                && physicalTop == other.physicalTop
+                && physicalRight == other.physicalRight
+                && physicalBottom == other.physicalBottom
+                && deviceWidth == other.deviceWidth
+                && deviceHeight == other.deviceHeight
+                && uniqueId == other.uniqueId;
+    }
+
+    bool operator!=(const DisplayViewport& other) const {
+        return !(*this == other);
+    }
+
+    inline bool isValid() const {
+        return displayId >= 0;
+    }
+
+    void setNonDisplayViewport(int32_t width, int32_t height) {
+        displayId = ADISPLAY_ID_NONE;
+        orientation = DISPLAY_ORIENTATION_0;
+        logicalLeft = 0;
+        logicalTop = 0;
+        logicalRight = width;
+        logicalBottom = height;
+        physicalLeft = 0;
+        physicalTop = 0;
+        physicalRight = width;
+        physicalBottom = height;
+        deviceWidth = width;
+        deviceHeight = height;
+        uniqueId.clear();
+    }
+};
+
+/**
+ * Describes the different type of viewports supported by input flinger.
+ * Keep in sync with values in InputManagerService.java.
+ */
+enum class ViewportType : int32_t {
+    VIEWPORT_INTERNAL = 1,
+    VIEWPORT_EXTERNAL = 2,
+    VIEWPORT_VIRTUAL = 3,
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_DISPLAY_VIEWPORT_H
diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h
index 3230189..3c81f0f 100644
--- a/include/powermanager/IPowerManager.h
+++ b/include/powermanager/IPowerManager.h
@@ -44,10 +44,12 @@
         NAP                          = IBinder::FIRST_CALL_TRANSACTION + 10,
         IS_INTERACTIVE               = IBinder::FIRST_CALL_TRANSACTION + 11,
         IS_POWER_SAVE_MODE           = IBinder::FIRST_CALL_TRANSACTION + 12,
-        SET_POWER_SAVE_MODE          = IBinder::FIRST_CALL_TRANSACTION + 13,
-        REBOOT                       = IBinder::FIRST_CALL_TRANSACTION + 14,
-        SHUTDOWN                     = IBinder::FIRST_CALL_TRANSACTION + 15,
-        CRASH                        = IBinder::FIRST_CALL_TRANSACTION + 16,
+        GET_POWER_SAVE_STATE         = IBinder::FIRST_CALL_TRANSACTION + 13,
+        SET_POWER_SAVE_MODE          = IBinder::FIRST_CALL_TRANSACTION + 14,
+        REBOOT                       = IBinder::FIRST_CALL_TRANSACTION + 17,
+        REBOOT_SAFE_MODE             = IBinder::FIRST_CALL_TRANSACTION + 18,
+        SHUTDOWN                     = IBinder::FIRST_CALL_TRANSACTION + 19,
+        CRASH                        = IBinder::FIRST_CALL_TRANSACTION + 20,
     };
 
     DECLARE_META_INTERFACE(PowerManager)
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index aec8f10..6fefb38 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2547,8 +2547,16 @@
             objectsSize = 0;
         } else {
             while (objectsSize > 0) {
-                if (mObjects[objectsSize-1] < desired)
+                if (mObjects[objectsSize-1] < desired) {
+                    // Check for an object being sliced
+                    if (desired < mObjects[objectsSize-1] + sizeof(flat_binder_object)) {
+                        ALOGE("Attempt to shrink Parcel would slice an objects allocated memory");
+                        return UNKNOWN_ERROR + 0xBADF10;
+                    }
                     break;
+                }
+                // STOPSHIP: Above code to be replaced with following commented code:
+                // if (mObjects[objectsSize-1] + sizeof(flat_binder_object) <= desired) break;
                 objectsSize--;
             }
         }
diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
index d5b57ac..a9166e2 100644
--- a/libs/binder/include/binder/Parcelable.h
+++ b/libs/binder/include/binder/Parcelable.h
@@ -36,6 +36,9 @@
 public:
     virtual ~Parcelable() = default;
 
+    Parcelable() = default;
+    Parcelable(const Parcelable&) = default;
+
     // Write |this| parcelable to the given |parcel|.  Keep in mind that
     // implementations of writeToParcel must be manually kept in sync
     // with readFromParcel and the Java equivalent versions of these methods.
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
new file mode 100644
index 0000000..f2686d5
--- /dev/null
+++ b/libs/graphicsenv/Android.bp
@@ -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.
+
+cc_library_shared {
+    name: "libgraphicsenv",
+
+    srcs: [
+        "GraphicsEnv.cpp",
+    ],
+
+    shared_libs: [
+        "libnativeloader",
+        "liblog",
+    ],
+
+    export_include_dirs: ["include"],
+}
diff --git a/libs/ui/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
similarity index 98%
rename from libs/ui/GraphicsEnv.cpp
rename to libs/graphicsenv/GraphicsEnv.cpp
index 1d20424..0276008 100644
--- a/libs/ui/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -16,7 +16,7 @@
 
 //#define LOG_NDEBUG 1
 #define LOG_TAG "GraphicsEnv"
-#include <ui/GraphicsEnv.h>
+#include <graphicsenv/GraphicsEnv.h>
 
 #include <mutex>
 
diff --git a/include/ui/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
similarity index 100%
rename from include/ui/GraphicsEnv.h
rename to libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index b891c2a..bb703da 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -112,54 +112,60 @@
 void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
     Mutex::Autolock lock(mMutex);
 
-    String8 fifo;
+    outResult->appendFormat("%s- BufferQueue ", prefix.string());
+    outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
+                            mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
+    outResult->appendFormat("%s  mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
+                            mDequeueBufferCannotBlock, mAsyncMode);
+    outResult->appendFormat("%s  default-size=[%dx%d] default-format=%d ", prefix.string(),
+                            mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
+    outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
+                            mFrameCounter);
+
+    outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size());
     Fifo::const_iterator current(mQueue.begin());
     while (current != mQueue.end()) {
-        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
-                "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n",
-                current->mSlot, current->mGraphicBuffer.get(),
-                current->mCrop.left, current->mCrop.top, current->mCrop.right,
-                current->mCrop.bottom, current->mTransform, current->mTimestamp,
-                BufferItem::scalingModeName(current->mScalingMode));
+        double timestamp = current->mTimestamp / 1e9;
+        outResult->appendFormat("%s  %02d:%p ", prefix.string(), current->mSlot,
+                                current->mGraphicBuffer.get());
+        outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top,
+                                current->mCrop.right, current->mCrop.bottom);
+        outResult->appendFormat("xform=0x%02x time=%.4f scale=%s\n", current->mTransform, timestamp,
+                                BufferItem::scalingModeName(current->mScalingMode));
         ++current;
     }
 
-    outResult->appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
-            "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d "
-            "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, "
-            "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix.string(),
-            mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
-            mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth,
-            mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
-            fifo.string());
-
+    outResult->appendFormat("%sSlots:\n", prefix.string());
     for (int s : mActiveBuffers) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
         // A dequeued buffer might be null if it's still being allocated
         if (buffer.get()) {
-            outResult->appendFormat("%s%s[%02d:%p] state=%-8s, %p "
-                    "[%4ux%4u:%4u,%3X]\n", prefix.string(),
-                    (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
-                    buffer.get(), mSlots[s].mBufferState.string(),
-                    buffer->handle, buffer->width, buffer->height,
-                    buffer->stride, buffer->format);
+            outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(),
+                                    (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
+                                    buffer.get());
+            outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
+                                    buffer->handle, mSlots[s].mFrameNumber);
+            outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
+                                    buffer->stride, buffer->format);
         } else {
-            outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
-                    buffer.get(), mSlots[s].mBufferState.string());
+            outResult->appendFormat("%s  [%02d:%p] ", prefix.string(), s, buffer.get());
+            outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n",
+                                    mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber);
         }
     }
     for (int s : mFreeBuffers) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
-        outResult->appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
-                prefix.string(), s, buffer.get(), mSlots[s].mBufferState.string(),
-                buffer->handle, buffer->width, buffer->height, buffer->stride,
-                buffer->format);
+        outResult->appendFormat("%s  [%02d:%p] ", prefix.string(), s, buffer.get());
+        outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
+                                buffer->handle, mSlots[s].mFrameNumber);
+        outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
+                                buffer->stride, buffer->format);
     }
 
     for (int s : mFreeSlots) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
-        outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
-                buffer.get(), mSlots[s].mBufferState.string());
+        outResult->appendFormat("%s  [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(),
+                                mSlots[s].mBufferState.string());
     }
 }
 
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index a12bdd7..5290dd5 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -21,6 +21,7 @@
 
 /**
  * @file native_window.h
+ * @brief API for accessing a native window.
  */
 
 #ifndef ANDROID_NATIVE_WINDOW_H
@@ -71,16 +72,16 @@
 
 struct ANativeWindow;
 /**
- * {@link ANativeWindow} is opaque type that provides access to a native window.
+ * Opaque type that provides access to a native window.
  *
- * A pointer can be obtained using ANativeWindow_fromSurface().
+ * A pointer can be obtained using {@link ANativeWindow_fromSurface()}.
  */
 typedef struct ANativeWindow ANativeWindow;
 
 /**
- * {@link ANativeWindow} is a struct that represents a windows buffer.
+ * Struct that represents a windows buffer.
  *
- * A pointer can be obtained using ANativeWindow_lock().
+ * A pointer can be obtained using {@link ANativeWindow_lock()}.
  */
 typedef struct ANativeWindow_Buffer {
     // The number of pixels that are show horizontally.
@@ -90,10 +91,10 @@
     int32_t height;
 
     // The number of *pixels* that a line in the buffer takes in
-    // memory.  This may be >= width.
+    // memory. This may be >= width.
     int32_t stride;
 
-    // The format of the buffer.  One of AHARDWAREBUFFER_FORMAT_*
+    // The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
     int32_t format;
 
     // The actual bits.
@@ -104,49 +105,53 @@
 } ANativeWindow_Buffer;
 
 /**
- * Acquire a reference on the given ANativeWindow object.  This prevents the object
+ * Acquire a reference on the given {@link ANativeWindow} object. This prevents the object
  * from being deleted until the reference is removed.
  */
 void ANativeWindow_acquire(ANativeWindow* window);
 
 /**
- * Remove a reference that was previously acquired with ANativeWindow_acquire().
+ * Remove a reference that was previously acquired with {@link ANativeWindow_acquire()}.
  */
 void ANativeWindow_release(ANativeWindow* window);
 
 /**
- * Return the current width in pixels of the window surface.  Returns a
- * negative value on error.
+ * Return the current width in pixels of the window surface.
+ *
+ * \return negative value on error.
  */
 int32_t ANativeWindow_getWidth(ANativeWindow* window);
 
 /**
- * Return the current height in pixels of the window surface.  Returns a
- * negative value on error.
+ * Return the current height in pixels of the window surface.
+ *
+ * \return a negative value on error.
  */
 int32_t ANativeWindow_getHeight(ANativeWindow* window);
 
 /**
- * Return the current pixel format (AHARDWAREBUFFER_FORMAT_*) of the window surface.  Returns a
- * negative value on error.
+ * Return the current pixel format (AHARDWAREBUFFER_FORMAT_*) of the window surface.
+ *
+ * \return a negative value on error.
  */
 int32_t ANativeWindow_getFormat(ANativeWindow* window);
 
 /**
  * Change the format and size of the window buffers.
  *
- * format: one of AHARDWAREBUFFER_FORMAT_ constants
- *
  * The width and height control the number of pixels in the buffers, not the
- * dimensions of the window on screen.  If these are different than the
- * window's physical size, then it buffer will be scaled to match that size
- * when compositing it to the screen.
+ * dimensions of the window on screen. If these are different than the
+ * window's physical size, then its buffer will be scaled to match that size
+ * when compositing it to the screen. The width and height must be either both zero
+ * or both non-zero.
  *
  * For all of these parameters, if 0 is supplied then the window's base
  * value will come back in force.
  *
- * width and height must be either both zero or both non-zero.
- *
+ * \param width width of the buffers in pixels.
+ * \param height height of the buffers in pixels.
+ * \param format one of AHARDWAREBUFFER_FORMAT_* constants.
+ * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
         int32_t width, int32_t height, int32_t format);
@@ -157,7 +162,9 @@
  * function, it contains the dirty region, that is, the region the caller
  * intends to redraw. When the function returns, inOutDirtyBounds is updated
  * with the actual area the caller needs to redraw -- this region is often
- * extended by ANativeWindow_lock.
+ * extended by {@link ANativeWindow_lock}.
+ *
+ * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
         ARect* inOutDirtyBounds);
@@ -165,6 +172,8 @@
 /**
  * Unlock the window's drawing surface after previously locking it,
  * posting the new buffer to the display.
+ *
+ * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
 
@@ -173,9 +182,8 @@
 /**
  * Set a transform that will be applied to future buffers posted to the window.
  *
- * @param transform combination of {@link ANativeWindowTransform} flags
- * @return 0 if successful
- * @return -EINVAL if @param transform is invalid
+ * \param transform combination of {@link ANativeWindowTransform} flags
+ * \return 0 for success, or -EINVAL if \p transform is invalid
  */
 int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform);
 
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 42ef075..6429c52 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -530,7 +530,6 @@
  /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
   * android_native_window_t is deprecated.
   */
-typedef struct ANativeWindow ANativeWindow;
 typedef struct ANativeWindow android_native_window_t __deprecated;
 
 /*
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index cb661e1..c2e93d8 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -53,7 +53,6 @@
         "GraphicBuffer.cpp",
         "GraphicBufferAllocator.cpp",
         "GraphicBufferMapper.cpp",
-        "GraphicsEnv.cpp",
         "HdrCapabilities.cpp",
         "PixelFormat.cpp",
         "Rect.cpp",
@@ -67,7 +66,6 @@
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
         "libbase",
-        "libnativeloader",
         "libcutils",
         "libhardware",
         "libhidlbase",
@@ -75,6 +73,7 @@
         "libsync",
         "libutils",
         "liblog",
+        "libgraphicsenv",
     ],
 
     static_libs: [
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 3876745..fa78b1c 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -19,47 +19,69 @@
     export_include_dirs: ["include"],
 }
 
-cc_library_static {
+cflags = [
+    "-DLOG_TAG=\"libdvr\"",
+]
+
+srcs = [
+    "dvr_api.cpp",
+    "dvr_buffer.cpp",
+    "dvr_buffer_queue.cpp",
+    "dvr_display_manager.cpp",
+    "dvr_hardware_composer_client.cpp",
+    "dvr_surface.cpp",
+    "dvr_vsync.cpp",
+]
+
+static_libs = [
+    "libbufferhub",
+    "libbufferhubqueue",
+    "libdisplay",
+    "libvrsensor",
+    "libvirtualtouchpadclient",
+    "libvr_hwc-impl",
+    "libvr_hwc-binder",
+    "libgrallocusage",
+    "libpdx_default_transport",
+]
+
+shared_libs = [
+    "android.hardware.graphics.bufferqueue@1.0",
+    "android.hidl.token@1.0-utils",
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libcutils",
+    "libutils",
+    "libnativewindow",
+    "libgui",
+    "libui",
+]
+
+cc_library_shared {
     name: "libdvr",
     owner: "google",
-
-    cflags: [
-        "-fvisibility=hidden",
-        "-DLOG_TAG=\"libdvr\"",
-        "-DDVR_EXPORT=__attribute__((visibility(\"default\")))",
-    ],
-
+    cflags: cflags,
     header_libs: ["libdvr_headers"],
     export_header_lib_headers: ["libdvr_headers"],
+    srcs: srcs,
+    static_libs: static_libs,
+    shared_libs: shared_libs,
+    version_script: "exported_apis.lds",
+}
 
-    srcs: [
-        "dvr_api.cpp",
-        "dvr_buffer.cpp",
-        "dvr_buffer_queue.cpp",
-        "dvr_display_manager.cpp",
-        "dvr_hardware_composer_client.cpp",
-        "dvr_surface.cpp",
-        "dvr_vsync.cpp",
-    ],
-
-    static_libs: [
-        "libbufferhub",
-        "libbufferhubqueue",
-        "libdisplay",
-        "libvrsensor",
-        "libvirtualtouchpadclient",
-        "libvr_hwc-impl",
-        "libvr_hwc-binder",
-        "libgrallocusage",
-    ],
-
-    shared_libs: [
-        "android.hardware.graphics.bufferqueue@1.0",
-        "android.hidl.token@1.0-utils",
-        "libbase",
-        "libnativewindow",
-    ],
-
+// Also build a static libdvr for linking into tests. The linker script
+// restricting function access in the shared lib makes it inconvenient to use in
+// test code.
+cc_library_static {
+    name: "libdvr_static",
+    owner: "google",
+    cflags: cflags,
+    header_libs: ["libdvr_headers"],
+    export_header_lib_headers: ["libdvr_headers"],
+    srcs: srcs,
+    static_libs: static_libs,
+    shared_libs: shared_libs,
 }
 
 subdirs = [
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 4d7e1a6..2c95583 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -18,7 +18,7 @@
 
 extern "C" {
 
-DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) {
+int dvrGetApi(void* api, size_t struct_size, int version) {
   ALOGI("dvrGetApi: api=%p struct_size=%zu version=%d", api, struct_size,
         version);
   if (version == 1) {
diff --git a/libs/vr/libdvr/exported_apis.lds b/libs/vr/libdvr/exported_apis.lds
new file mode 100644
index 0000000..5ecb498
--- /dev/null
+++ b/libs/vr/libdvr/exported_apis.lds
@@ -0,0 +1,9 @@
+{
+  global:
+    # Whitelist the function to load the dvr api.
+    dvrGetApi;
+
+  local:
+    # Hide everything else.
+    *;
+};
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index af202b4..ef746e2 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -25,7 +25,7 @@
 ]
 
 static_libraries = [
-    "libdvr",
+    "libdvr_static",
     "libbufferhubqueue",
     "libbufferhub",
     "libchrome",
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index cfc2022..82a5ea7 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -24,6 +24,9 @@
         "libbase",
         "libpdx",
     ],
+    whole_static_libs: [
+        "libselinux",
+    ],
 }
 
 cc_test {
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index d96eeff..27a56f9 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -11,6 +11,7 @@
 #include <android-base/strings.h>
 #include <cutils/sockets.h>
 #include <pdx/service.h>
+#include <selinux/selinux.h>
 #include <uds/channel_manager.h>
 #include <uds/client_channel_factory.h>
 #include <uds/ipc_helper.h>
@@ -364,6 +365,36 @@
 Status<void> Endpoint::CreateChannelSocketPair(LocalHandle* local_socket,
                                                LocalHandle* remote_socket) {
   Status<void> status;
+  char* endpoint_context = nullptr;
+  // Make sure the channel socket has the correct SELinux label applied.
+  // Here we get the label from the endpoint file descriptor, which should be
+  // something like "u:object_r:pdx_service_endpoint_socket:s0" and replace
+  // "endpoint" with "channel" to produce the channel label such as this:
+  // "u:object_r:pdx_service_channel_socket:s0".
+  if (fgetfilecon_raw(socket_fd_.Get(), &endpoint_context) > 0) {
+    std::string channel_context = endpoint_context;
+    freecon(endpoint_context);
+    const std::string suffix = "_endpoint_socket";
+    auto pos = channel_context.find(suffix);
+    if (pos != std::string::npos) {
+      channel_context.replace(pos, suffix.size(), "_channel_socket");
+    } else {
+      ALOGW(
+          "Endpoint::CreateChannelSocketPair: Endpoint security context '%s' "
+          "does not contain expected substring '%s'",
+          channel_context.c_str(), suffix.c_str());
+    }
+    ALOGE_IF(setsockcreatecon_raw(channel_context.c_str()) == -1,
+             "Endpoint::CreateChannelSocketPair: Failed to set channel socket "
+             "security context: %s",
+             strerror(errno));
+  } else {
+    ALOGE(
+        "Endpoint::CreateChannelSocketPair: Failed to obtain the endpoint "
+        "socket's security context: %s",
+        strerror(errno));
+  }
+
   int channel_pair[2] = {};
   if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, channel_pair) == -1) {
     ALOGE("Endpoint::CreateChannelSocketPair: Failed to create socket pair: %s",
@@ -372,6 +403,8 @@
     return status;
   }
 
+  setsockcreatecon_raw(nullptr);
+
   local_socket->Reset(channel_pair[0]);
   remote_socket->Reset(channel_pair[1]);
 
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index a895e63..bff80cd 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -81,7 +81,7 @@
     shared_libs: [
         // ***** DO NOT ADD NEW DEPENDENCIES HERE *****
         // In particular, DO NOT add libutils nor anything "above" libui
-        "libui",
+        "libgraphicsenv",
         "libnativewindow",
         "libbacktrace",
     ],
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 7d20ba1..1116400 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -28,7 +28,7 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 
-#include <ui/GraphicsEnv.h>
+#include <graphicsenv/GraphicsEnv.h>
 
 #include "egl_trace.h"
 #include "egldefs.h"
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8af9038..97565aa 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -227,18 +227,65 @@
 
 // --- InputReaderConfiguration ---
 
-bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const {
-    const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay;
-    if (viewport.displayId >= 0) {
-        *outViewport = viewport;
+bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
+        const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
+    const DisplayViewport* viewport = NULL;
+    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != NULL) {
+        for (DisplayViewport currentViewport : mVirtualDisplays) {
+            if (currentViewport.uniqueId == *uniqueDisplayId) {
+                viewport = &currentViewport;
+                break;
+            }
+        }
+    } else if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
+        viewport = &mExternalDisplay;
+    } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
+        viewport = &mInternalDisplay;
+    }
+
+    if (viewport != NULL && viewport->displayId >= 0) {
+        *outViewport = *viewport;
         return true;
     }
     return false;
 }
 
-void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) {
-    DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay;
-    v = viewport;
+void InputReaderConfiguration::setPhysicalDisplayViewport(ViewportType viewportType,
+        const DisplayViewport& viewport) {
+    if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
+        mExternalDisplay = viewport;
+    } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
+        mInternalDisplay = viewport;
+    }
+}
+
+void InputReaderConfiguration::setVirtualDisplayViewports(
+        const Vector<DisplayViewport>& viewports) {
+    mVirtualDisplays = viewports;
+}
+
+void InputReaderConfiguration::dump(String8& dump) const {
+    dump.append(INDENT4 "ViewportInternal:\n");
+    dumpViewport(dump, mInternalDisplay);
+    dump.append(INDENT4 "ViewportExternal:\n");
+    dumpViewport(dump, mExternalDisplay);
+    dump.append(INDENT4 "ViewportVirtual:\n");
+    for (const DisplayViewport& viewport : mVirtualDisplays) {
+        dumpViewport(dump, viewport);
+    }
+}
+
+void InputReaderConfiguration::dumpViewport(String8& dump, const DisplayViewport& viewport) const {
+    dump.appendFormat(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
+            "logicalFrame=[%d, %d, %d, %d], "
+            "physicalFrame=[%d, %d, %d, %d], "
+            "deviceSize=[%d, %d]\n",
+            viewport.displayId, viewport.orientation, viewport.uniqueId.c_str(),
+            viewport.logicalLeft, viewport.logicalTop,
+            viewport.logicalRight, viewport.logicalBottom,
+            viewport.physicalLeft, viewport.physicalTop,
+            viewport.physicalRight, viewport.physicalBottom,
+            viewport.deviceWidth, viewport.deviceHeight);
 }
 
 
@@ -863,6 +910,9 @@
             mConfig.pointerGestureMovementSpeedRatio);
     dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n",
             mConfig.pointerGestureZoomSpeedRatio);
+
+    dump.append(INDENT3 "Viewports:\n");
+    mConfig.dump(dump);
 }
 
 void InputReader::monitor() {
@@ -2199,7 +2249,7 @@
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
             DisplayViewport v;
-            if (config->getDisplayInfo(false /*external*/, &v)) {
+            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
                 mOrientation = v.orientation;
             } else {
                 mOrientation = DISPLAY_ORIENTATION_0;
@@ -2572,7 +2622,7 @@
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
             DisplayViewport v;
-            if (config->getDisplayInfo(false /*external*/, &v)) {
+            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
                 mOrientation = v.orientation;
             } else {
                 mOrientation = DISPLAY_ORIENTATION_0;
@@ -3017,7 +3067,7 @@
 }
 
 void TouchInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Touch Input Mapper:\n");
+    dump.appendFormat(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode));
     dumpParameters(dump);
     dumpVirtualKeys(dump);
     dumpRawPointerAxes(dump);
@@ -3109,6 +3159,22 @@
     }
 }
 
+const char* TouchInputMapper::modeToString(DeviceMode deviceMode) {
+    switch (deviceMode) {
+    case DEVICE_MODE_DISABLED:
+        return "disabled";
+    case DEVICE_MODE_DIRECT:
+        return "direct";
+    case DEVICE_MODE_UNSCALED:
+        return "unscaled";
+    case DEVICE_MODE_NAVIGATION:
+        return "navigation";
+    case DEVICE_MODE_POINTER:
+        return "pointer";
+    }
+    return "unknown";
+}
+
 void TouchInputMapper::configure(nsecs_t when,
         const InputReaderConfiguration* config, uint32_t changes) {
     InputMapper::configure(when, config, changes);
@@ -3234,9 +3300,11 @@
             || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
             || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
         mParameters.hasAssociatedDisplay = true;
-        mParameters.associatedDisplayIsExternal =
-                mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
-                        && getDevice()->isExternal();
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+            mParameters.associatedDisplayIsExternal = getDevice()->isExternal();
+            getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"),
+                    mParameters.uniqueDisplayId);
+        }
     }
 
     // Initial downs on external touch devices should wake the device.
@@ -3278,9 +3346,11 @@
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n",
+    dump.appendFormat(
+            INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, displayId='%s'\n",
             toString(mParameters.hasAssociatedDisplay),
-            toString(mParameters.associatedDisplayIsExternal));
+            toString(mParameters.associatedDisplayIsExternal),
+            mParameters.uniqueDisplayId.c_str());
     dump.appendFormat(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
@@ -3356,7 +3426,21 @@
     // Get associated display dimensions.
     DisplayViewport newViewport;
     if (mParameters.hasAssociatedDisplay) {
-        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) {
+        const String8* uniqueDisplayId = NULL;
+        ViewportType viewportTypeToUse;
+
+        if (mParameters.associatedDisplayIsExternal) {
+            viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
+        } else if (!mParameters.uniqueDisplayId.isEmpty()) {
+            // If the IDC file specified a unique display Id, then it expects to be linked to a
+            // virtual display with the same unique ID.
+            uniqueDisplayId = &mParameters.uniqueDisplayId;
+            viewportTypeToUse = ViewportType::VIEWPORT_VIRTUAL;
+        } else {
+            viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
+        }
+
+        if (!mConfig.getDisplayViewport(viewportTypeToUse, uniqueDisplayId, &newViewport)) {
             ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
                     "display.  The device will be inoperable until the display size "
                     "becomes available.",
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 647f271..157fa4f 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -21,6 +21,7 @@
 #include "PointerControllerInterface.h"
 #include "InputListener.h"
 
+#include <input/DisplayViewport.h>
 #include <input/Input.h>
 #include <input/VelocityControl.h>
 #include <input/VelocityTracker.h>
@@ -52,70 +53,6 @@
 class InputMapper;
 
 /*
- * Describes how coordinates are mapped on a physical display.
- * See com.android.server.display.DisplayViewport.
- */
-struct DisplayViewport {
-    int32_t displayId; // -1 if invalid
-    int32_t orientation;
-    int32_t logicalLeft;
-    int32_t logicalTop;
-    int32_t logicalRight;
-    int32_t logicalBottom;
-    int32_t physicalLeft;
-    int32_t physicalTop;
-    int32_t physicalRight;
-    int32_t physicalBottom;
-    int32_t deviceWidth;
-    int32_t deviceHeight;
-
-    DisplayViewport() :
-            displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
-            logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
-            physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
-            deviceWidth(0), deviceHeight(0) {
-    }
-
-    bool operator==(const DisplayViewport& other) const {
-        return displayId == other.displayId
-                && orientation == other.orientation
-                && logicalLeft == other.logicalLeft
-                && logicalTop == other.logicalTop
-                && logicalRight == other.logicalRight
-                && logicalBottom == other.logicalBottom
-                && physicalLeft == other.physicalLeft
-                && physicalTop == other.physicalTop
-                && physicalRight == other.physicalRight
-                && physicalBottom == other.physicalBottom
-                && deviceWidth == other.deviceWidth
-                && deviceHeight == other.deviceHeight;
-    }
-
-    bool operator!=(const DisplayViewport& other) const {
-        return !(*this == other);
-    }
-
-    inline bool isValid() const {
-        return displayId >= 0;
-    }
-
-    void setNonDisplayViewport(int32_t width, int32_t height) {
-        displayId = ADISPLAY_ID_NONE;
-        orientation = DISPLAY_ORIENTATION_0;
-        logicalLeft = 0;
-        logicalTop = 0;
-        logicalRight = width;
-        logicalBottom = height;
-        physicalLeft = 0;
-        physicalTop = 0;
-        physicalRight = width;
-        physicalBottom = height;
-        deviceWidth = width;
-        deviceHeight = height;
-    }
-};
-
-/*
  * Input reader configuration.
  *
  * Specifies various options that modify the behavior of the input reader.
@@ -264,12 +201,19 @@
             pointerGestureZoomSpeedRatio(0.3f),
             showTouches(false) { }
 
-    bool getDisplayInfo(bool external, DisplayViewport* outViewport) const;
-    void setDisplayInfo(bool external, const DisplayViewport& viewport);
+    bool getDisplayViewport(ViewportType viewportType, const String8* displayId,
+            DisplayViewport* outViewport) const;
+    void setPhysicalDisplayViewport(ViewportType viewportType, const DisplayViewport& viewport);
+    void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
+
+
+    void dump(String8& dump) const;
+    void dumpViewport(String8& dump, const DisplayViewport& viewport) const;
 
 private:
     DisplayViewport mInternalDisplay;
     DisplayViewport mExternalDisplay;
+    Vector<DisplayViewport> mVirtualDisplays;
 };
 
 
@@ -1358,6 +1302,7 @@
         bool associatedDisplayIsExternal;
         bool orientationAware;
         bool hasButtonUnderPad;
+        String8 uniqueDisplayId;
 
         enum GestureMode {
             GESTURE_MODE_SINGLE_TOUCH,
@@ -1906,6 +1851,8 @@
     const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
 
     static void assignPointerIds(const RawState* last, RawState* current);
+
+    const char* modeToString(DeviceMode deviceMode);
 };
 
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 7082fe1..76291a5 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -30,6 +30,10 @@
 static const int32_t DISPLAY_ID = 0;
 static const int32_t DISPLAY_WIDTH = 480;
 static const int32_t DISPLAY_HEIGHT = 800;
+static const int32_t VIRTUAL_DISPLAY_ID = 1;
+static const int32_t VIRTUAL_DISPLAY_WIDTH = 400;
+static const int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
+static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "Vr-display-unique-ID";
 
 // Error tolerance for floating point assertions.
 static const float EPSILON = 0.001f;
@@ -137,25 +141,19 @@
     FakeInputReaderPolicy() {
     }
 
-    void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) {
+    void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
+            const String8& uniqueId) {
+        DisplayViewport v = createDisplayViewport(displayId, width, height, orientation, uniqueId);
         // Set the size of both the internal and external display at the same time.
-        bool isRotated = (orientation == DISPLAY_ORIENTATION_90
-                || orientation == DISPLAY_ORIENTATION_270);
-        DisplayViewport v;
-        v.displayId = displayId;
-        v.orientation = orientation;
-        v.logicalLeft = 0;
-        v.logicalTop = 0;
-        v.logicalRight = isRotated ? height : width;
-        v.logicalBottom = isRotated ? width : height;
-        v.physicalLeft = 0;
-        v.physicalTop = 0;
-        v.physicalRight = isRotated ? height : width;
-        v.physicalBottom = isRotated ? width : height;
-        v.deviceWidth = isRotated ? height : width;
-        v.deviceHeight = isRotated ? width : height;
-        mConfig.setDisplayInfo(false /*external*/, v);
-        mConfig.setDisplayInfo(true /*external*/, v);
+        mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL, v);
+        mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_EXTERNAL, v);
+    }
+
+    void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
+            const String8& uniqueId) {
+        Vector<DisplayViewport> viewports;
+        viewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId));
+        mConfig.setVirtualDisplayViewports(viewports);
     }
 
     void addExcludedDeviceName(const String8& deviceName) {
@@ -204,6 +202,27 @@
     }
 
 private:
+    DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
+            int32_t orientation, const String8& uniqueId) {
+        bool isRotated = (orientation == DISPLAY_ORIENTATION_90
+                || orientation == DISPLAY_ORIENTATION_270);
+        DisplayViewport v;
+        v.displayId = displayId;
+        v.orientation = orientation;
+        v.logicalLeft = 0;
+        v.logicalTop = 0;
+        v.logicalRight = isRotated ? height : width;
+        v.logicalBottom = isRotated ? width : height;
+        v.physicalLeft = 0;
+        v.physicalTop = 0;
+        v.physicalRight = isRotated ? height : width;
+        v.physicalBottom = isRotated ? width : height;
+        v.deviceWidth = isRotated ? height : width;
+        v.deviceHeight = isRotated ? width : height;
+        v.uniqueId = uniqueId;
+        return v;
+    }
+
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) {
         *outConfig = mConfig;
     }
@@ -1578,7 +1597,13 @@
 
     void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
             int32_t orientation) {
-        mFakePolicy->setDisplayInfo(displayId, width, height, orientation);
+        mFakePolicy->setDisplayViewport(displayId, width, height, orientation, String8::empty());
+        configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    }
+
+    void setVirtualDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
+            int32_t orientation, const String8& uniqueId) {
+        mFakePolicy->setVirtualDisplayViewport(displayId, width, height, orientation, uniqueId);
         configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
 
@@ -2884,6 +2909,8 @@
     static const int32_t RAW_SLOT_MAX;
     static const float X_PRECISION;
     static const float Y_PRECISION;
+    static const float X_PRECISION_VIRTUAL;
+    static const float Y_PRECISION_VIRTUAL;
 
     static const float GEOMETRIC_SCALE;
     static const TouchAffineTransformation AFFINE_TRANSFORM;
@@ -2905,6 +2932,7 @@
     };
 
     void prepareDisplay(int32_t orientation);
+    void prepareVirtualDisplay(int32_t orientation);
     void prepareVirtualKeys();
     void prepareLocationCalibration();
     int32_t toRawX(float displayX);
@@ -2912,7 +2940,10 @@
     float toCookedX(float rawX, float rawY);
     float toCookedY(float rawX, float rawY);
     float toDisplayX(int32_t rawX);
+    float toDisplayX(int32_t rawX, int32_t displayWidth);
     float toDisplayY(int32_t rawY);
+    float toDisplayY(int32_t rawY, int32_t displayHeight);
+
 };
 
 const int32_t TouchInputMapperTest::RAW_X_MIN = 25;
@@ -2937,6 +2968,10 @@
 const int32_t TouchInputMapperTest::RAW_SLOT_MAX = 9;
 const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH;
 const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT;
+const float TouchInputMapperTest::X_PRECISION_VIRTUAL =
+        float(RAW_X_MAX - RAW_X_MIN + 1) / VIRTUAL_DISPLAY_WIDTH;
+const float TouchInputMapperTest::Y_PRECISION_VIRTUAL =
+        float(RAW_Y_MAX - RAW_Y_MIN + 1) / VIRTUAL_DISPLAY_HEIGHT;
 const TouchAffineTransformation TouchInputMapperTest::AFFINE_TRANSFORM =
         TouchAffineTransformation(1, -2, 3, -4, 5, -6);
 
@@ -2953,6 +2988,11 @@
     setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation);
 }
 
+void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) {
+    setVirtualDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
+        VIRTUAL_DISPLAY_HEIGHT, orientation, String8(VIRTUAL_DISPLAY_UNIQUE_ID));
+}
+
 void TouchInputMapperTest::prepareVirtualKeys() {
     mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]);
     mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]);
@@ -2983,11 +3023,19 @@
 }
 
 float TouchInputMapperTest::toDisplayX(int32_t rawX) {
-    return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1);
+    return toDisplayX(rawX, DISPLAY_WIDTH);
+}
+
+float TouchInputMapperTest::toDisplayX(int32_t rawX, int32_t displayWidth) {
+    return float(rawX - RAW_X_MIN) * displayWidth / (RAW_X_MAX - RAW_X_MIN + 1);
 }
 
 float TouchInputMapperTest::toDisplayY(int32_t rawY) {
-    return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1);
+    return toDisplayY(rawY, DISPLAY_HEIGHT);
+}
+
+float TouchInputMapperTest::toDisplayY(int32_t rawY, int32_t displayHeight) {
+    return float(rawY - RAW_Y_MIN) * displayHeight / (RAW_Y_MAX - RAW_Y_MIN + 1);
 }
 
 
@@ -3447,6 +3495,105 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 }
 
+TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDisplay) {
+    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    addConfigurationProperty("touch.displayId", VIRTUAL_DISPLAY_UNIQUE_ID);
+
+    prepareVirtualDisplay(DISPLAY_ORIENTATION_0);
+    prepareButtons();
+    prepareAxes(POSITION);
+    prepareVirtualKeys();
+    addMapperAndConfigure(mapper);
+
+    mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
+
+    NotifyMotionArgs motionArgs;
+
+    // Down.
+    int32_t x = 100;
+    int32_t y = 125;
+    processDown(mapper, x, y);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
+    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
+    ASSERT_EQ(VIRTUAL_DISPLAY_ID, motionArgs.displayId);
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
+    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(0, motionArgs.flags);
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
+    ASSERT_EQ(0, motionArgs.buttonState);
+    ASSERT_EQ(0, motionArgs.edgeFlags);
+    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
+    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
+            toDisplayX(x, VIRTUAL_DISPLAY_WIDTH), toDisplayY(y, VIRTUAL_DISPLAY_HEIGHT),
+            1, 0, 0, 0, 0, 0, 0, 0));
+    ASSERT_NEAR(X_PRECISION_VIRTUAL, motionArgs.xPrecision, EPSILON);
+    ASSERT_NEAR(Y_PRECISION_VIRTUAL, motionArgs.yPrecision, EPSILON);
+    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
+
+    // Move.
+    x += 50;
+    y += 75;
+    processMove(mapper, x, y);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
+    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
+    ASSERT_EQ(VIRTUAL_DISPLAY_ID, motionArgs.displayId);
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
+    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(0, motionArgs.flags);
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
+    ASSERT_EQ(0, motionArgs.buttonState);
+    ASSERT_EQ(0, motionArgs.edgeFlags);
+    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
+    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
+            toDisplayX(x, VIRTUAL_DISPLAY_WIDTH), toDisplayY(y, VIRTUAL_DISPLAY_HEIGHT),
+            1, 0, 0, 0, 0, 0, 0, 0));
+    ASSERT_NEAR(X_PRECISION_VIRTUAL, motionArgs.xPrecision, EPSILON);
+    ASSERT_NEAR(Y_PRECISION_VIRTUAL, motionArgs.yPrecision, EPSILON);
+    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
+
+    // Up.
+    processUp(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime);
+    ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
+    ASSERT_EQ(VIRTUAL_DISPLAY_ID, motionArgs.displayId);
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
+    ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_EQ(0, motionArgs.flags);
+    ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
+    ASSERT_EQ(0, motionArgs.buttonState);
+    ASSERT_EQ(0, motionArgs.edgeFlags);
+    ASSERT_EQ(size_t(1), motionArgs.pointerCount);
+    ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0],
+            toDisplayX(x, VIRTUAL_DISPLAY_WIDTH), toDisplayY(y, VIRTUAL_DISPLAY_HEIGHT),
+            1, 0, 0, 0, 0, 0, 0, 0));
+    ASSERT_NEAR(X_PRECISION_VIRTUAL, motionArgs.xPrecision, EPSILON);
+    ASSERT_NEAR(Y_PRECISION_VIRTUAL, motionArgs.yPrecision, EPSILON);
+    ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime);
+
+    // Should not have sent any more keys or motions.
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled());
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
 TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
     SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
     addConfigurationProperty("touch.deviceType", "touchScreen");
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3cbc2f4..0f93cd7 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -699,7 +699,16 @@
             mName.string(), z, to_string(error).c_str(),
             static_cast<int32_t>(error));
 
-    error = hwcLayer->setInfo(s.type, s.appId);
+    int type = s.type;
+    int appId = s.appId;
+    sp<Layer> parent = mParent.promote();
+    if (parent.get()) {
+        auto& parentState = parent->getDrawingState();
+        type = parentState.type;
+        appId = parentState.appId;
+    }
+
+    error = hwcLayer->setInfo(type, appId);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)",
              mName.string(), static_cast<int32_t>(error));
 #else
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 505e81c..32fdc35 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1116,9 +1116,14 @@
 
 void SurfaceFlinger::resyncWithRateLimit() {
     static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
-    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
+
+    // No explicit locking is needed here since EventThread holds a lock while calling this method
+    static nsecs_t sLastResyncAttempted = 0;
+    const nsecs_t now = systemTime();
+    if (now - sLastResyncAttempted > kIgnoreDelay) {
         resyncToHardwareVsync(false);
     }
+    sLastResyncAttempted = now;
 }
 
 void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type,
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index ff6be81..aea602b 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -4,6 +4,6 @@
     group graphics drmrpc readproc
     onrestart restart zygote
     writepid /dev/stune/foreground/tasks
-    socket pdx/system/vr/display/client stream 0666 system graphics
-    socket pdx/system/vr/display/manager stream 0666 system graphics
-    socket pdx/system/vr/display/vsync stream 0666 system graphics
+    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
+    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
+    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
diff --git a/services/vr/bufferhubd/bufferhubd.rc b/services/vr/bufferhubd/bufferhubd.rc
index 8d57723..46fe5f9 100644
--- a/services/vr/bufferhubd/bufferhubd.rc
+++ b/services/vr/bufferhubd/bufferhubd.rc
@@ -3,4 +3,4 @@
   user system
   group system
   writepid /dev/cpuset/tasks
-  socket pdx/system/buffer_hub/client stream 0660 system system
+  socket pdx/system/buffer_hub/client stream 0660 system system u:object_r:pdx_bufferhub_client_endpoint_socket:s0
diff --git a/services/vr/performanced/performanced.rc b/services/vr/performanced/performanced.rc
index 6283f37..2605a47 100644
--- a/services/vr/performanced/performanced.rc
+++ b/services/vr/performanced/performanced.rc
@@ -3,4 +3,4 @@
   user root
   group system readproc
   writepid /dev/cpuset/tasks
-  socket pdx/system/performance/client stream 0666 system system
+  socket pdx/system/performance/client stream 0666 system system u:object_r:pdx_performance_client_endpoint_socket:s0
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index ee09d48..f0bdcd9 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -18,7 +18,7 @@
 // use it to look up device configuration, so it must be unique. Vendor and
 // product values must be 0 to indicate an internal device and prevent a
 // similar lookup that could conflict with a physical device.
-static const char* const kDeviceNameFormat = "vr virtual touchpad %d";
+static const char* const kDeviceNameFormat = "vr-virtual-touchpad-%d";
 static constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
 static constexpr int16_t kDeviceVendor = 0;
 static constexpr int16_t kDeviceProduct = 0;
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 24cfdf8..564bcd7 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -139,7 +139,7 @@
     SCOPED_TRACE(t);
     uidev = touchpad->injector[t].GetUiDev();
     String8 name;
-    name.appendFormat("vr virtual touchpad %d", t);
+    name.appendFormat("vr-virtual-touchpad-%d", t);
     EXPECT_EQ(name, uidev->name);
     for (int i = 0; i < ABS_CNT; ++i) {
       EXPECT_EQ(0, uidev->absmin[i]);
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 6149894..5f9b357 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -75,6 +75,7 @@
         "libbase",
         "liblog",
         "libui",
+        "libgraphicsenv",
         "libutils",
         "libcutils",
         "libz",
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 0005a90..a869317 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,7 +28,7 @@
 
 #include <android/dlext.h>
 #include <cutils/properties.h>
-#include <ui/GraphicsEnv.h>
+#include <graphicsenv/GraphicsEnv.h>
 #include <utils/Vector.h>
 
 #include "driver.h"