diff --git a/MultiDisplayProvider/Android.mk b/MultiDisplayProvider/Android.mk
new file mode 100644
index 0000000000000000000000000000000000000000..21918a8e831988e2964ecc8030077d83264bed8c
--- /dev/null
+++ b/MultiDisplayProvider/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2019 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the application.
+LOCAL_MODULE_TAGS := optional
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := MultiDisplayProvider
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_CERTIFICATE := platform
+LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
+LOCAL_JNI_SHARED_LIBRARIES := libemulator_multidisplay_jni
+include $(BUILD_PACKAGE)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/MultiDisplayProvider/AndroidManifest.xml b/MultiDisplayProvider/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..591b189a7bb6ffaefe4536d473e914b4e8e76094
--- /dev/null
+++ b/MultiDisplayProvider/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<!-- sharedUserId with system is required to allow putting activities
+     on virtual/secondary displays -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.emulator.multidisplay"
+          android:sharedUserId="android.uid.system" >
+
+    <uses-sdk android:minSdkVersion="19" />
+    <application android:label="@string/app_name"
+                 android:persistent="true">
+        <receiver android:name=".MultiDisplayServiceReceiver" >
+            <intent-filter>
+                <action android:name="com.android.emulator.multidisplay.START" />
+            </intent-filter>
+        </receiver>
+
+        <service android:name=".MultiDisplayService"
+                android:label="@string/app_name"
+                android:exported="true">
+        </service>
+
+    </application>
+</manifest>
diff --git a/MultiDisplayProvider/jni/Android.mk b/MultiDisplayProvider/jni/Android.mk
new file mode 100644
index 0000000000000000000000000000000000000000..7ab3c03c0d394f14d6edbb82332fc7979f28ef74
--- /dev/null
+++ b/MultiDisplayProvider/jni/Android.mk
@@ -0,0 +1,41 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    com_android_emulator_multidisplay.cpp
+
+LOCAL_C_INCLUDES += \
+    $(JNI_H_INCLUDE) \
+    system/core/base/include \
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid_runtime \
+    libnativehelper \
+    libcutils \
+    libutils \
+    liblog \
+    libui \
+    libgui \
+
+LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter
+
+LOCAL_MODULE := libemulator_multidisplay_jni
+LOCAL_MODULE_TAGS := optional
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/MultiDisplayProvider/jni/com_android_emulator_multidisplay.cpp b/MultiDisplayProvider/jni/com_android_emulator_multidisplay.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef4a053ea52002075766415f905f8a180afa59a3
--- /dev/null
+++ b/MultiDisplayProvider/jni/com_android_emulator_multidisplay.cpp
@@ -0,0 +1,194 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "android_emulator_multidisplay_JNI"
+#include <gui/BufferQueue.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+
+#include <sys/epoll.h>
+
+#include "utils/Log.h"
+#include "../../include/qemu_pipe.h"
+#include "nativehelper/JNIHelp.h"
+#include <nativehelper/ScopedLocalRef.h>
+#include "jni.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_view_Surface.h"
+#include "../../../goldfish-opengl/shared/OpenglCodecCommon/gralloc_cb.h"
+
+#define MAX_DISPLAYS 10
+
+using namespace android;
+
+static int gFd = 0;
+static const uint8_t ADD = 1;
+static const uint8_t DEL = 2;
+static const uint8_t QUERY = 3;
+static const uint8_t BIND = 4;
+
+static void fillMsg(std::vector<uint8_t>& buf, uint8_t cmd, uint8_t* data, uint32_t size) {
+    // msg format is size(4B) + cmd(1B) + data(size B)
+    uint32_t totalSize = size + 1;
+    uint8_t* p = (uint8_t*)&totalSize;
+    buf.insert(buf.end(), p, p + 4);
+    buf.push_back(cmd);
+    if (data) {
+        buf.insert(buf.end(), data, data + size);
+    }
+}
+
+struct FrameListener : public ConsumerBase::FrameAvailableListener {
+    sp<BufferItemConsumer> mConsumer;
+    uint32_t mId;
+    uint32_t mCb;
+public:
+    void onFrameAvailable(const BufferItem& item) override {
+        BufferItem bufferItem;
+        mConsumer->acquireBuffer(&bufferItem, 0);
+        ANativeWindowBuffer* b = bufferItem.mGraphicBuffer->getNativeBuffer();
+        if (b && b->handle) {
+            cb_handle_t* cb = (cb_handle_t*)(b->handle);
+            if (mCb != cb->hostHandle) {
+                ALOGI("sent cb %d", cb->hostHandle);
+                mCb = cb->hostHandle;
+                uint32_t data[] = {mId, mCb};
+                std::vector<uint8_t> buf;
+                fillMsg(buf, BIND, (uint8_t*)data, sizeof(data));
+                WriteFully(gFd, buf.data(), buf.size());
+            }
+        }
+        else {
+            ALOGE("cannot get native buffer handler");
+        }
+        mConsumer->releaseBuffer(bufferItem);
+    }
+    void setDefaultBufferSize(uint32_t w, uint32_t h) {
+        mConsumer->setDefaultBufferSize(w, h);
+    }
+    FrameListener(sp<BufferItemConsumer>& consumer, uint32_t id)
+        : mConsumer(consumer), mId(id), mCb(0) { }
+};
+
+sp<FrameListener> gFrameListener[MAX_DISPLAYS + 1];
+
+static jobject nativeCreateSurface(JNIEnv *env, jobject obj, jint id, jint width, jint height)
+{
+    ALOGI("create surface for %d", id);
+    // Create surface for this new display
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    sp<BufferItemConsumer> bufferItemConsumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    bufferItemConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_RENDER);
+    gFrameListener[id] = new FrameListener(bufferItemConsumer, id);
+    gFrameListener[id]->setDefaultBufferSize(width, height);
+    bufferItemConsumer->setFrameAvailableListener(gFrameListener[id]);
+    return android_view_Surface_createFromIGraphicBufferProducer(env, producer);
+}
+
+static jint nativeOpen(JNIEnv* env, jobject obj) {
+    // Open pipe
+    gFd = qemu_pipe_open("multidisplay");
+    if (gFd < 0) {
+        ALOGE("Error opening multidisplay pipe %d", gFd);
+    } else {
+        std::vector<uint8_t> buf;
+        fillMsg(buf, QUERY, nullptr, 0);
+        WriteFully(gFd, buf.data(), buf.size());
+        ALOGI("multidisplay pipe connected!!!");
+    }
+    return gFd;
+}
+
+static bool nativeReadPipe(JNIEnv* env, jobject obj, jintArray arr) {
+    int* arrp = env->GetIntArrayElements(arr, 0);
+    uint32_t length;
+    ReadFully(gFd, &length, sizeof(length));
+    std::vector<uint8_t> args(length, 0);
+    ReadFully(gFd, args.data(), (size_t)length);
+    switch(args[0]) {
+        case ADD: {
+            ALOGV("received add event");
+            *arrp = ADD;
+            for (int i = 1; i < 6; i++) {
+                *(arrp + i) = *(uint32_t*)(&args[(i - 1) * 4 + 1]);
+            }
+            env->ReleaseIntArrayElements(arr, arrp, JNI_COMMIT);
+            break;
+        }
+        case DEL: {
+            ALOGV("received del event");
+            *arrp = DEL;
+            *(arrp + 1) = *(uint32_t*)(&args[1]);
+            env->ReleaseIntArrayElements(arr, arrp, JNI_COMMIT);
+            break;
+        }
+        default: {
+            ALOGE("unexpected event %d", args[0]);
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool nativeReleaseListener(JNIEnv* env, jobject obj, jint id) {
+    if (gFrameListener[id].get()) {
+        ALOGV("clear gFrameListener %d", id);
+        gFrameListener[id].clear();
+        gFrameListener[id] = nullptr;
+    }
+    return true;
+}
+
+static bool nativeResizeListener(JNIEnv* env, jobject obj, jint id, jint w, jint h) {
+    if (gFrameListener[id]) {
+        gFrameListener[id]->setDefaultBufferSize(w, h);
+        return true;
+    }
+    return false;
+}
+
+static JNINativeMethod sMethods[] = {
+    { "nativeOpen", "()I", (void*) nativeOpen },
+    { "nativeCreateSurface", "(III)Landroid/view/Surface;", (void*) nativeCreateSurface },
+    { "nativeReadPipe", "([I)Z", (void*) nativeReadPipe},
+    { "nativeReleaseListener", "(I)Z", (void*) nativeReleaseListener},
+    { "nativeResizeListener", "(III)Z", (void*) nativeResizeListener},
+};
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM *jvm, void *reserved)
+{
+    JNIEnv *env;
+
+    // Check JNI version
+    if (jvm->GetEnv((void **)&env, JNI_VERSION_1_6)) {
+        ALOGE("JNI version mismatch error");
+        return JNI_ERR;
+    }
+
+    jniRegisterNativeMethods(env, "com/android/emulator/multidisplay/MultiDisplayService",
+                                    sMethods, NELEM(sMethods));
+
+    return JNI_VERSION_1_6;
+}
diff --git a/MultiDisplayProvider/res/values/strings.xml b/MultiDisplayProvider/res/values/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dfe8d68530888fdc958ae88f6adfab411226158b
--- /dev/null
+++ b/MultiDisplayProvider/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">Emulator Multi Display Provider</string>
+</resources>
diff --git a/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayService.java b/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayService.java
new file mode 100644
index 0000000000000000000000000000000000000000..608b590a85b6c997262f20b06156e054d87c3b03
--- /dev/null
+++ b/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayService.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.emulator.multidisplay;
+
+import android.content.Context;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Display;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.view.Surface;
+import android.os.Messenger;
+import android.os.Message;
+
+
+public class MultiDisplayService extends Service {
+    private static final String TAG = "MultiDisplayService";
+    private static final String DISPLAY_NAME = "Emulator 2D Display";
+    private static final String[] UNIQUE_DISPLAY_ID = new String[]{"notUsed", "1234562",
+                                                                   "1234563", "1234564",
+                                                                   "1234565", "1234566",
+                                                                   "1234567", "1234568",
+                                                                   "1234569", "1234570",
+                                                                   "1234571"};
+    private static final int MAX_DISPLAYS = 10;
+    private static final int ADD = 1;
+    private static final int DEL = 2;
+    private static final int mFlags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+                                      DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
+                                      1 << 6 |//DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
+                                      1 << 9; //DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
+    private DisplayManager mDisplayManager;
+    private VirtualDisplay mVirtualDisplay[];
+    private Surface mSurface[];
+    private Messenger mMessenger;
+    private ListenerThread mListner;
+
+    private final Handler mHandler = new Handler();
+
+    class MultiDisplay {
+        public int width;
+        public int height;
+        public int dpi;
+        public int flag;
+        public VirtualDisplay virtualDisplay;
+        public Surface surface;
+        public boolean enabled;
+        MultiDisplay() {
+            clear();
+        }
+        public void clear() {
+            width = 0;
+            height = 0;
+            dpi = 0;
+            flag = 0;
+            virtualDisplay = null;
+            surface = null;
+            enabled = false;
+        }
+        public void set(int w, int h, int d, int f) {
+            width = w;
+            height = h;
+            dpi = d;
+            flag = f;
+            enabled = true;
+        }
+        public boolean match(int w, int h, int d, int f) {
+            return (w == width && h == height && d == dpi && f == flag);
+        }
+    }
+    private MultiDisplay mMultiDisplay[];
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        try {
+            System.loadLibrary("emulator_multidisplay_jni");
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to loadLibrary: " + e);
+        }
+
+        mListner = new ListenerThread();
+        mListner.start();
+
+        mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
+        mMultiDisplay = new MultiDisplay[MAX_DISPLAYS + 1];
+        for (int i = 0; i < MAX_DISPLAYS + 1; i++) {
+            mMultiDisplay[i] = new MultiDisplay();
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if(mMessenger == null)
+            mMessenger = new Messenger(mHandler);
+        return mMessenger.getBinder();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        // keep it alive.
+        return START_STICKY;
+    }
+
+    class ListenerThread extends Thread {
+        ListenerThread() {
+            super(TAG);
+        }
+
+        private void deleteVirtualDisplay(int displayId) {
+            int i = displayId;
+            if (mMultiDisplay[i].enabled == false) {
+                return;
+            }
+            if (mMultiDisplay[i].virtualDisplay != null) {
+                mMultiDisplay[i].virtualDisplay.release();
+            }
+            if (mMultiDisplay[i].surface != null) {
+                mMultiDisplay[i].surface.release();
+            }
+            mMultiDisplay[i].clear();
+            nativeReleaseListener(i);
+        }
+
+        private void createVirtualDisplay(int displayId, int w, int h, int dpi, int flag) {
+            int i = displayId;
+            mMultiDisplay[i].surface = nativeCreateSurface(i, w, h);
+            mMultiDisplay[i].virtualDisplay = mDisplayManager.createVirtualDisplay(
+                                              null /* projection */,
+                                              DISPLAY_NAME, w, h, dpi,
+                                              mMultiDisplay[i].surface, flag,
+                                              null /* callback */,
+                                              null /* handler */,
+                                              UNIQUE_DISPLAY_ID[i]);
+            mMultiDisplay[i].set(w, h, dpi, flag);
+        }
+
+        private void addVirtualDisplay(int displayId, int w, int h, int dpi, int flag) {
+            int i = displayId;
+            if (mMultiDisplay[i].match(w, h, dpi, flag)) {
+                return;
+            }
+            if (mMultiDisplay[i].virtualDisplay == null) {
+                createVirtualDisplay(i, w, h, dpi, flag);
+                return;
+            }
+            if (mMultiDisplay[i].flag != flag) {
+                deleteVirtualDisplay(i);
+                createVirtualDisplay(i, w, h, dpi, flag);
+                return;
+            }
+            if (mMultiDisplay[i].width != w || mMultiDisplay[i].height != h) {
+                nativeResizeListener(i, w, h);
+            }
+            // only dpi changes
+            mMultiDisplay[i].virtualDisplay.resize(w, h, dpi);
+            mMultiDisplay[i].set(w, h, dpi, flag);
+        }
+
+        @Override
+        public void run() {
+            while(nativeOpen() <= 0) {
+                Log.e(TAG, "failed to open multiDisplay pipe, retry");
+            }
+            while(true) {
+                int[] array = {0, 0, 0, 0, 0, 0};
+                if (!nativeReadPipe(array)) {
+                    continue;
+                }
+                switch (array[0]) {
+                    case ADD: {
+                        for (int j = 0; j < 6; j++) {
+                            Log.d(TAG, "received " + array[j]);
+                        }
+                        int i = array[1];
+                        int width = array[2];
+                        int height = array[3];
+                        int dpi = array[4];
+                        int flag = (array[5] != 0) ? array[5] : mFlags;
+                        if (i < 1 || i > MAX_DISPLAYS || width <=0 || height <=0 || dpi <=0
+                            || flag < 0) {
+                            Log.e(TAG, "invalid parameters for add/modify display");
+                            break;
+                        }
+                        addVirtualDisplay(i, width, height, dpi, flag);
+                        break;
+                    }
+                    case DEL: {
+                        int i = array[1];
+                        Log.d(TAG, "DEL " + i);
+                        if (i < 1 || i > MAX_DISPLAYS) {
+                            Log.e(TAG, "invalid parameters for delete display");
+                            break;
+                        }
+                        deleteVirtualDisplay(i);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    private native int nativeOpen();
+    private native Surface nativeCreateSurface(int displayId, int width, int height);
+    private native boolean nativeReadPipe(int[] arr);
+    private native boolean nativeReleaseListener(int displayId);
+    private native boolean nativeResizeListener(int displayId, int with, int height);
+}
diff --git a/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayServiceReceiver.java b/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayServiceReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..c84c43afebfae8ba02cfe2fb58d89022cd3e7e1b
--- /dev/null
+++ b/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayServiceReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.emulator.multidisplay;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class MultiDisplayServiceReceiver extends BroadcastReceiver {
+    private static final String TAG = "MultiDisplayServiceReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (isMyServiceRunning(MultiDisplayService.class, context) == false) {
+            Log.v(TAG, "startService");
+            context.startService(new Intent(context, MultiDisplayService.class));
+        }
+    }
+
+    private boolean isMyServiceRunning(Class<?> serviceClass, Context context) {
+        ActivityManager manager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
+        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+            if (serviceClass.getName().equals(service.service.getClassName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/data/etc/user/advancedFeatures.ini b/data/etc/google/user/advancedFeatures.ini
similarity index 92%
rename from data/etc/user/advancedFeatures.ini
rename to data/etc/google/user/advancedFeatures.ini
index a63f367450a637945f2c2024a3480dd808218f04..7ad2fa81b2f616cdf2b79f57b5faf27a1fcb3a93 100644
--- a/data/etc/user/advancedFeatures.ini
+++ b/data/etc/google/user/advancedFeatures.ini
@@ -9,3 +9,4 @@ IntelPerformanceMonitoringUnit = on
 Wifi = on
 HostComposition = on
 DynamicPartition = on
+MultiDisplay = on
diff --git a/data/etc/google/userdebug/advancedFeatures.ini b/data/etc/google/userdebug/advancedFeatures.ini
new file mode 100644
index 0000000000000000000000000000000000000000..775e5af7d1e43f8f26a04b8732e718117345c860
--- /dev/null
+++ b/data/etc/google/userdebug/advancedFeatures.ini
@@ -0,0 +1,13 @@
+GrallocSync = on
+LogcatPipe = on
+GLAsyncSwap = on
+GLESDynamicVersion = on
+GLDMA = on
+EncryptUserData = on
+IntelPerformanceMonitoringUnit = on
+Wifi = on
+HostComposition = on
+RefCountPipe = on
+VirtioInput = on
+DynamicPartition = on
+MultiDisplay = on
diff --git a/include/qemu_pipe.h b/include/qemu_pipe.h
index 1056bb3c90e779741ecb4e5d5a4a113985c3cda0..986c3da29e161b2b0a0fe58c50d124642de3ef9f 100644
--- a/include/qemu_pipe.h
+++ b/include/qemu_pipe.h
@@ -30,6 +30,10 @@
 #  define  D(...)   do{}while(0)
 #endif
 
+typedef int QEMU_PIPE_HANDLE;
+
+#define QEMU_PIPE_INVALID_HANDLE -1
+
 static bool ReadFully(int fd, void* data, size_t byte_count) {
   uint8_t* p = (uint8_t*)(data);
   size_t remaining = byte_count;
@@ -109,4 +113,8 @@ qemu_pipe_open(const char*  pipeName)
     return fd;
 }
 
+static __inline__ bool
+qemu_pipe_valid(QEMU_PIPE_HANDLE pipe) {
+    return pipe >= 0;
+}
 #endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/input/virtio_input_multi_touch_1.idc b/input/virtio_input_multi_touch_1.idc
new file mode 100644
index 0000000000000000000000000000000000000000..78af51131794021496b5f28036e489a15ccc858e
--- /dev/null
+++ b/input/virtio_input_multi_touch_1.idc
@@ -0,0 +1,6 @@
+device.internal = 1
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+cursor.mode = navigation
+cursor.orientationAware = 1
+
diff --git a/input/virtio_input_multi_touch_10.idc b/input/virtio_input_multi_touch_10.idc
new file mode 100644
index 0000000000000000000000000000000000000000..47dbd42a18edf712b5f48af7e26cd288f77a0ffc
--- /dev/null
+++ b/input/virtio_input_multi_touch_10.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234570
diff --git a/input/virtio_input_multi_touch_11.idc b/input/virtio_input_multi_touch_11.idc
new file mode 100644
index 0000000000000000000000000000000000000000..a845bec7122ef22cb0e23b2b5582f77a2322f766
--- /dev/null
+++ b/input/virtio_input_multi_touch_11.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234571
diff --git a/input/virtio_input_multi_touch_2.idc b/input/virtio_input_multi_touch_2.idc
new file mode 100644
index 0000000000000000000000000000000000000000..7222cab29966e24732d896d07aa530ffdee7c03e
--- /dev/null
+++ b/input/virtio_input_multi_touch_2.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234562
diff --git a/input/virtio_input_multi_touch_3.idc b/input/virtio_input_multi_touch_3.idc
new file mode 100644
index 0000000000000000000000000000000000000000..9750e95952ba1251dd1dcbaa1c43ac2dfe39bce7
--- /dev/null
+++ b/input/virtio_input_multi_touch_3.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234563
diff --git a/input/virtio_input_multi_touch_4.idc b/input/virtio_input_multi_touch_4.idc
new file mode 100644
index 0000000000000000000000000000000000000000..8cc357e63e6b7b2ae0bbe12d43db94c2da19ef12
--- /dev/null
+++ b/input/virtio_input_multi_touch_4.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234564
diff --git a/input/virtio_input_multi_touch_5.idc b/input/virtio_input_multi_touch_5.idc
new file mode 100644
index 0000000000000000000000000000000000000000..9ceeb8bac9f796fa35b15acda5da5ee7abc51eaf
--- /dev/null
+++ b/input/virtio_input_multi_touch_5.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234565
diff --git a/input/virtio_input_multi_touch_6.idc b/input/virtio_input_multi_touch_6.idc
new file mode 100644
index 0000000000000000000000000000000000000000..f8cfb76aa5529cb9ceec32e6f0935710510f699c
--- /dev/null
+++ b/input/virtio_input_multi_touch_6.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234566
diff --git a/input/virtio_input_multi_touch_7.idc b/input/virtio_input_multi_touch_7.idc
new file mode 100644
index 0000000000000000000000000000000000000000..7147fb738c19fbd225c415a1814b4804cec4ddbb
--- /dev/null
+++ b/input/virtio_input_multi_touch_7.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234567
diff --git a/input/virtio_input_multi_touch_8.idc b/input/virtio_input_multi_touch_8.idc
new file mode 100644
index 0000000000000000000000000000000000000000..84ae7936efd9afc7a4d5a24f90c626634722816a
--- /dev/null
+++ b/input/virtio_input_multi_touch_8.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234568
diff --git a/input/virtio_input_multi_touch_9.idc b/input/virtio_input_multi_touch_9.idc
new file mode 100644
index 0000000000000000000000000000000000000000..4b1511604c9fa2257a6517a694a00df1c43ff3e4
--- /dev/null
+++ b/input/virtio_input_multi_touch_9.idc
@@ -0,0 +1,12 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+cursor.mode = navigation
+cursor.orientationAware = 1
+
+# This displayID matches the unique ID of the virtual display created for Emulator.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:com.android.emulator.multidisplay:1234569
diff --git a/vendor.mk b/vendor.mk
index 2d2642d1be68dda0d8d8bcaedb126a672fb6b1f2..16e7e50e736afe054b001c8a3f1e521e3d0a475f 100644
--- a/vendor.mk
+++ b/vendor.mk
@@ -107,6 +107,7 @@ PRODUCT_PACKAGES += \
 
 PRODUCT_PROPERTY_OVERRIDES += ro.control_privapp_permissions=enforce
 PRODUCT_PROPERTY_OVERRIDES += ro.hardware.power=ranchu
+PRODUCT_PROPERTY_OVERRIDES += ro.crypto.volume.filenames_mode=aes-256-cts
 
 PRODUCT_PROPERTY_OVERRIDES += persist.sys.zram_enabled=1 \
 
@@ -153,6 +154,17 @@ PRODUCT_COPY_FILES += \
     device/generic/goldfish/fstab.ranchu:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu \
     device/generic/goldfish/ueventd.ranchu.rc:$(TARGET_COPY_OUT_VENDOR)/ueventd.rc \
     device/generic/goldfish/input/goldfish_rotary.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/goldfish_rotary.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_1.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_1.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_2.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_2.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_3.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_3.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_4.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_4.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_5.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_5.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_6.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_6.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_7.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_7.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_8.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_8.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_9.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_9.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_10.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_10.idc \
+    device/generic/goldfish/input/virtio_input_multi_touch_11.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_11.idc \
     device/generic/goldfish/manifest.xml:$(TARGET_COPY_OUT_VENDOR)/manifest.xml \
     device/generic/goldfish/data/etc/config.ini:config.ini \
     device/generic/goldfish/wifi/simulated_hostapd.conf:$(TARGET_COPY_OUT_VENDOR)/etc/simulated_hostapd.conf \