Merge "Handle DEAD_OBJECT correctly in H2BGBP"
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 86da4d3..0f336dd 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -39,13 +39,13 @@
     int32_t physicalBottom;
     int32_t deviceWidth;
     int32_t deviceHeight;
-    String8 uniqueId;
+    std::string 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) {
+            deviceWidth(0), deviceHeight(0), uniqueId() {
     }
 
     bool operator==(const DisplayViewport& other) const {
diff --git a/include/input/Input.h b/include/input/Input.h
index 7c4379e..819a89f 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -25,7 +25,6 @@
 #include <utils/BitSet.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
 #include <stdint.h>
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1ea69d3..34d164c 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -31,9 +31,9 @@
     }
 
     // Information provided by the kernel.
-    String8 name;
-    String8 location;
-    String8 uniqueId;
+    std::string name;
+    std::string location;
+    std::string uniqueId;
     uint16_t bus;
     uint16_t vendor;
     uint16_t product;
@@ -45,7 +45,7 @@
     // It is hashed from whatever kernel provided information is available.
     // Ideally, the way this value is computed should not change between Android releases
     // because that would invalidate persistent settings that rely on it.
-    String8 descriptor;
+    std::string descriptor;
 
     // A value added to uniquely identify a device in the absence of a unique id. This
     // is intended to be a minimum way to distinguish from other active devices and may
@@ -73,16 +73,16 @@
     };
 
     void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
-            const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+            const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
             bool hasMic);
 
     inline int32_t getId() const { return mId; }
     inline int32_t getControllerNumber() const { return mControllerNumber; }
     inline int32_t getGeneration() const { return mGeneration; }
     inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; }
-    inline const String8& getAlias() const { return mAlias; }
-    inline const String8& getDisplayName() const {
-        return mAlias.isEmpty() ? mIdentifier.name : mAlias;
+    inline const std::string& getAlias() const { return mAlias; }
+    inline const std::string& getDisplayName() const {
+        return mAlias.empty() ? mIdentifier.name : mAlias;
     }
     inline bool isExternal() const { return mIsExternal; }
     inline bool hasMic() const { return mHasMic; }
@@ -121,7 +121,7 @@
     int32_t mGeneration;
     int32_t mControllerNumber;
     InputDeviceIdentifier mIdentifier;
-    String8 mAlias;
+    std::string mAlias;
     bool mIsExternal;
     bool mHasMic;
     uint32_t mSources;
@@ -149,7 +149,7 @@
  *
  * Returns an empty string if not found.
  */
-extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+extern std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
         const InputDeviceIdentifier& deviceIdentifier,
         InputDeviceConfigurationFileType type);
 
@@ -162,8 +162,8 @@
  *
  * Returns an empty string if not found.
  */
-extern String8 getInputDeviceConfigurationFilePathByName(
-        const String8& name, InputDeviceConfigurationFileType type);
+extern std::string getInputDeviceConfigurationFilePathByName(
+        const std::string& name, InputDeviceConfigurationFileType type);
 
 } // namespace android
 
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index e8d1345..5fd86b4 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -27,6 +27,8 @@
  * The InputConsumer is used by the application to receive events from the input dispatcher.
  */
 
+#include <string>
+
 #include <input/Input.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 33d2757..9f4559f 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -27,7 +27,6 @@
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Tokenizer.h>
-#include <utils/String8.h>
 #include <utils/Unicode.h>
 #include <utils/RefBase.h>
 
@@ -75,10 +74,10 @@
     };
 
     /* Loads a key character map from a file. */
-    static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap);
+    static status_t load(const std::string& filename, Format format, sp<KeyCharacterMap>* outMap);
 
     /* Loads a key character map from its string contents. */
-    static status_t loadContents(const String8& filename,
+    static status_t loadContents(const std::string& filename,
             const char* contents, Format format, sp<KeyCharacterMap>* outMap);
 
     /* Combines a base key character map and an overlay. */
@@ -221,7 +220,7 @@
         status_t parseKey();
         status_t parseKeyProperty();
         status_t finishKey(Key* key);
-        status_t parseModifier(const String8& token, int32_t* outMetaState);
+        status_t parseModifier(const std::string& token, int32_t* outMetaState);
         status_t parseCharacterLiteral(char16_t* outCharacter);
     };
 
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index 1e8de71..73815fe 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -62,7 +62,7 @@
  */
 class KeyLayoutMap : public RefBase {
 public:
-    static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap);
+    static status_t load(const std::string& filename, sp<KeyLayoutMap>* outMap);
 
     status_t mapKey(int32_t scanCode, int32_t usageCode,
             int32_t* outKeyCode, uint32_t* outFlags) const;
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index d4903e9..8b66f69 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -21,7 +21,6 @@
 #include <input/InputDevice.h>
 #include <input/InputEventLabels.h>
 #include <utils/Errors.h>
-#include <utils/String8.h>
 #include <utils/PropertyMap.h>
 
 namespace android {
@@ -43,10 +42,10 @@
  */
 class KeyMap {
 public:
-    String8 keyLayoutFile;
+    std::string keyLayoutFile;
     sp<KeyLayoutMap> keyLayoutMap;
 
-    String8 keyCharacterMapFile;
+    std::string keyCharacterMapFile;
     sp<KeyCharacterMap> keyCharacterMap;
 
     KeyMap();
@@ -56,11 +55,11 @@
             const PropertyMap* deviceConfiguration);
 
     inline bool haveKeyLayout() const {
-        return !keyLayoutFile.isEmpty();
+        return !keyLayoutFile.empty();
     }
 
     inline bool haveKeyCharacterMap() const {
-        return !keyCharacterMapFile.isEmpty();
+        return !keyCharacterMapFile.empty();
     }
 
     inline bool isComplete() const {
@@ -68,12 +67,12 @@
     }
 
 private:
-    bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
-    status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+    bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
+    status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
     status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-            const String8& name);
-    String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
-            const String8& name, InputDeviceConfigurationFileType type);
+            const std::string& name);
+    std::string getPath(const InputDeviceIdentifier& deviceIdentifier,
+            const std::string& name, InputDeviceConfigurationFileType type);
 };
 
 /**
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index e245ead..24e0e0e 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -23,7 +23,6 @@
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Tokenizer.h>
-#include <utils/String8.h>
 #include <utils/Unicode.h>
 
 namespace android {
@@ -50,7 +49,7 @@
 public:
     ~VirtualKeyMap();
 
-    static status_t load(const String8& filename, VirtualKeyMap** outMap);
+    static status_t load(const std::string& filename, VirtualKeyMap** outMap);
 
     inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
         return mVirtualKeys;
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index d516eb1..857bbf9 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -189,7 +189,7 @@
                 // them out without going through the buffer.
                 
                 // Slurp up all of the lines.
-                const char* lastLine = txt+1;
+                const char* lastLine = txt;
                 while (txt < end) {
                     if (*txt++ == '\n') lastLine = txt;
                 }
diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/AIBinder.cpp
index d0ce98d..83972f7 100644
--- a/libs/binder/ndk/AIBinder.cpp
+++ b/libs/binder/ndk/AIBinder.cpp
@@ -28,14 +28,29 @@
 using ::android::String16;
 using ::android::wp;
 
+namespace ABBinderTag {
+
+static const void* kId = "ABBinder";
+static void* kValue = static_cast<void*>(new bool{true});
+void cleanId(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
+
+static void attach(const sp<IBinder>& binder) {
+    binder->attachObject(kId, kValue, nullptr /*cookie*/, cleanId);
+}
+static bool has(const sp<IBinder>& binder) {
+    return binder != nullptr && binder->findObject(kId) == kValue;
+}
+
+} // namespace ABBinderTag
+
 AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
 AIBinder::~AIBinder() {}
 
-sp<AIBinder> AIBinder::associateClass(const AIBinder_Class* clazz) {
+bool AIBinder::associateClass(const AIBinder_Class* clazz) {
     using ::android::String8;
 
-    if (clazz == nullptr) return nullptr;
-    if (mClazz == clazz) return this;
+    if (clazz == nullptr) return false;
+    if (mClazz == clazz) return true;
 
     String8 newDescriptor(clazz->getInterfaceDescriptor());
 
@@ -45,42 +60,31 @@
             LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
                        << "' match during associateClass, but they are different class objects. "
                           "Class descriptor collision?";
-            return nullptr;
+        } else {
+            LOG(ERROR) << __func__
+                       << ": Class cannot be associated on object which already has a class. "
+                          "Trying to associate to '"
+                       << newDescriptor.c_str() << "' but already set to '"
+                       << currentDescriptor.c_str() << "'.";
         }
 
-        LOG(ERROR) << __func__
-                   << ": Class cannot be associated on object which already has a class. Trying to "
-                      "associate to '"
-                   << newDescriptor.c_str() << "' but already set to '" << currentDescriptor.c_str()
-                   << "'.";
-        return nullptr;
+        // always a failure because we know mClazz != clazz
+        return false;
     }
 
+    CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
+
     String8 descriptor(getBinder()->getInterfaceDescriptor());
     if (descriptor != newDescriptor) {
         LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor.c_str()
                    << "' but descriptor is actually '" << descriptor.c_str() << "'.";
-        return nullptr;
+        return false;
     }
 
-    // The descriptor matches, so if it is local, this is guaranteed to be the libbinder_ndk class.
-    // An error here can occur if there is a conflict between descriptors (two unrelated classes
-    // define the same descriptor), but this should never happen.
-
-    // if this is a local ABBinder, mClazz should be non-null
-    CHECK(asABBinder() == nullptr);
-    CHECK(asABpBinder() != nullptr);
-
-    if (!isRemote()) {
-        // ABpBinder but proxy to a local object. Therefore that local object must be an ABBinder.
-        ABBinder* binder = static_cast<ABBinder*>(getBinder().get());
-        return binder;
-    }
-
-    // This is a remote object
+    // if this is a local object, it's not one known to libbinder_ndk
     mClazz = clazz;
 
-    return this;
+    return true;
 }
 
 ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
@@ -111,24 +115,45 @@
     }
 }
 
-ABpBinder::ABpBinder(::android::sp<::android::IBinder> binder)
+ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
       : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
     CHECK(binder != nullptr);
 }
 ABpBinder::~ABpBinder() {}
 
+sp<AIBinder> ABpBinder::fromBinder(const ::android::sp<::android::IBinder>& binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+    if (ABBinderTag::has(binder)) {
+        return static_cast<ABBinder*>(binder.get());
+    }
+    return new ABpBinder(binder);
+}
+
 struct AIBinder_Weak {
     wp<AIBinder> binder;
 };
 AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder) {
-    if (binder == nullptr) return nullptr;
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
     return new AIBinder_Weak{wp<AIBinder>(binder)};
 }
-void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) {
-    delete weakBinder;
+void AIBinder_Weak_delete(AIBinder_Weak** weakBinder) {
+    if (weakBinder == nullptr) {
+        return;
+    }
+
+    delete *weakBinder;
+    *weakBinder = nullptr;
 }
 AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) {
-    if (weakBinder == nullptr) return nullptr;
+    if (weakBinder == nullptr) {
+        return nullptr;
+    }
+
     sp<AIBinder> binder = weakBinder->binder.promote();
     AIBinder_incStrong(binder.get());
     return binder.get();
@@ -162,12 +187,14 @@
 
     void* userData = clazz->onCreate(args);
 
-    AIBinder* ret = new ABBinder(clazz, userData);
-    AIBinder_incStrong(ret);
-    return ret;
+    sp<AIBinder> ret = new ABBinder(clazz, userData);
+    ABBinderTag::attach(ret->getBinder());
+
+    AIBinder_incStrong(ret.get());
+    return ret.get();
 }
 
-bool AIBinder_isRemote(AIBinder* binder) {
+bool AIBinder_isRemote(const AIBinder* binder) {
     if (binder == nullptr) {
         return true;
     }
@@ -175,6 +202,22 @@
     return binder->isRemote();
 }
 
+bool AIBinder_isAlive(const AIBinder* binder) {
+    if (binder == nullptr) {
+        return false;
+    }
+
+    return const_cast<AIBinder*>(binder)->getBinder()->isBinderAlive();
+}
+
+binder_status_t AIBinder_ping(AIBinder* binder) {
+    if (binder == nullptr) {
+        return EX_NULL_POINTER;
+    }
+
+    return binder->getBinder()->pingBinder();
+}
+
 void AIBinder_incStrong(AIBinder* binder) {
     if (binder == nullptr) {
         LOG(ERROR) << __func__ << ": on null binder";
@@ -200,23 +243,12 @@
     return binder->getStrongCount();
 }
 
-void AIBinder_associateClass(AIBinder** binder, const AIBinder_Class* clazz) {
-    if (binder == nullptr || *binder == nullptr) {
-        return;
+bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) {
+    if (binder == nullptr) {
+        return false;
     }
 
-    sp<AIBinder> result = (*binder)->associateClass(clazz);
-
-    // This function takes one refcount of 'binder' and delivers one refcount of 'result' to the
-    // callee. First we give the callee their refcount and then take it away from binder. This is
-    // done in this order in order to handle the case that the result and the binder are the same
-    // object.
-    if (result != nullptr) {
-        AIBinder_incStrong(result.get());
-    }
-    AIBinder_decStrong(*binder);
-
-    *binder = result.get(); // Maybe no-op
+    return binder->associateClass(clazz);
 }
 
 const AIBinder_Class* AIBinder_getClass(AIBinder* binder) {
@@ -263,12 +295,6 @@
     return status;
 }
 
-using AutoParcelDestroyer = std::unique_ptr<AParcel*, void (*)(AParcel**)>;
-static void destroy_parcel(AParcel** parcel) {
-    delete *parcel;
-    *parcel = nullptr;
-}
-
 binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
                                   AParcel** out, binder_flags_t flags) {
     if (in == nullptr) {
@@ -276,9 +302,10 @@
         return EX_NULL_POINTER;
     }
 
+    using AutoParcelDestroyer = std::unique_ptr<AParcel*, void (*)(AParcel**)>;
     // This object is the input to the transaction. This function takes ownership of it and deletes
     // it.
-    AutoParcelDestroyer forIn(in, destroy_parcel);
+    AutoParcelDestroyer forIn(in, AParcel_delete);
 
     if (!isUserCommand(code)) {
         LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK.";
@@ -313,33 +340,3 @@
 
     return parcelStatus;
 }
-
-binder_status_t AIBinder_finalizeTransaction(AIBinder* binder, AParcel** out) {
-    if (out == nullptr) {
-        LOG(ERROR) << __func__ << ": requires non-null out parameter";
-        return EX_NULL_POINTER;
-    }
-
-    // This object is the input to the transaction. This function takes ownership of it and deletes
-    // it.
-    AutoParcelDestroyer forOut(out, destroy_parcel);
-
-    if (binder == nullptr || *out == nullptr) {
-        LOG(ERROR) << __func__ << ": requires non-null parameters.";
-        return EX_NULL_POINTER;
-    }
-
-    if ((*out)->getBinder() != binder) {
-        LOG(ERROR) << __func__ << ": parcel is associated with binder object " << binder
-                   << " but called with " << (*out)->getBinder();
-        return EX_ILLEGAL_STATE;
-    }
-
-    if ((**out)->dataAvail() != 0) {
-        LOG(ERROR) << __func__
-                   << ": Only part of this transaction was read. There is remaining data left.";
-        return EX_ILLEGAL_STATE;
-    }
-
-    return EX_NONE;
-}
diff --git a/libs/binder/ndk/AIBinder_internal.h b/libs/binder/ndk/AIBinder_internal.h
index d44b937..23949bb 100644
--- a/libs/binder/ndk/AIBinder_internal.h
+++ b/libs/binder/ndk/AIBinder_internal.h
@@ -35,23 +35,16 @@
     AIBinder(const AIBinder_Class* clazz);
     virtual ~AIBinder();
 
-    // This returns an AIBinder object with this class associated. If the class is already
-    // associated, 'this' will be returned. If there is a local AIBinder implementation, that will
-    // be returned. If this is a remote object, the class will be associated and this will be ready
-    // to be used for transactions.
-    ::android::sp<AIBinder> associateClass(const AIBinder_Class* clazz);
+    bool associateClass(const AIBinder_Class* clazz);
     const AIBinder_Class* getClass() const { return mClazz; }
 
-    // This does not create the binder if it does not exist in the process.
     virtual ::android::sp<::android::IBinder> getBinder() = 0;
     virtual ABBinder* asABBinder() { return nullptr; }
     virtual ABpBinder* asABpBinder() { return nullptr; }
 
-    bool isRemote() {
-        auto binder = getBinder();
-        // if the binder is nullptr, then it is a local object which hasn't been sent out of process
-        // yet.
-        return binder != nullptr && binder->remoteBinder() != nullptr;
+    bool isRemote() const {
+        ::android::sp<::android::IBinder> binder = const_cast<AIBinder*>(this)->getBinder();
+        return binder->remoteBinder() != nullptr;
     }
 
 private:
@@ -63,7 +56,6 @@
 
 // This is a local AIBinder object with a known class.
 struct ABBinder : public AIBinder, public ::android::BBinder {
-    ABBinder(const AIBinder_Class* clazz, void* userData);
     virtual ~ABBinder();
 
     void* getUserData() { return mUserData; }
@@ -76,6 +68,11 @@
                                ::android::Parcel* reply, binder_flags_t flags) override;
 
 private:
+    ABBinder(const AIBinder_Class* clazz, void* userData);
+
+    // only thing that should create an ABBinder
+    friend AIBinder* AIBinder_new(const AIBinder_Class*, void*);
+
     // Can contain implementation if this is a local binder. This can still be nullptr for a local
     // binder. If it is nullptr, the implication is the implementation state is entirely external to
     // this object and the functionality provided in the AIBinder_Class is sufficient.
@@ -85,11 +82,15 @@
 // This binder object may be remote or local (even though it is 'Bp'). It is not yet associated with
 // a class.
 struct ABpBinder : public AIBinder, public ::android::BpRefBase {
-    ABpBinder(::android::sp<::android::IBinder> binder);
+    static ::android::sp<AIBinder> fromBinder(const ::android::sp<::android::IBinder>& binder);
+
     virtual ~ABpBinder();
 
     ::android::sp<::android::IBinder> getBinder() override { return remote(); }
     ABpBinder* asABpBinder() override { return this; }
+
+private:
+    ABpBinder(const ::android::sp<::android::IBinder>& binder);
 };
 
 struct AIBinder_Class {
diff --git a/libs/binder/ndk/AParcel.cpp b/libs/binder/ndk/AParcel.cpp
index b63b138..93384d6 100644
--- a/libs/binder/ndk/AParcel.cpp
+++ b/libs/binder/ndk/AParcel.cpp
@@ -25,6 +25,15 @@
 using ::android::Parcel;
 using ::android::sp;
 
+void AParcel_delete(AParcel** parcel) {
+    if (parcel == nullptr) {
+        return;
+    }
+
+    delete *parcel;
+    *parcel = nullptr;
+}
+
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
     return (*parcel)->writeStrongBinder(binder->getBinder());
 }
@@ -34,8 +43,9 @@
     if (status != EX_NONE) {
         return status;
     }
-    *binder = new ABpBinder(readBinder);
-    AIBinder_incStrong(*binder);
+    sp<AIBinder> ret = ABpBinder::fromBinder(readBinder);
+    AIBinder_incStrong(ret.get());
+    *binder = ret.get();
     return status;
 }
 binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) {
@@ -44,8 +54,9 @@
     if (status != EX_NONE) {
         return status;
     }
-    *binder = new ABpBinder(readBinder);
-    AIBinder_incStrong(*binder);
+    sp<AIBinder> ret = ABpBinder::fromBinder(readBinder);
+    AIBinder_incStrong(ret.get());
+    *binder = ret.get();
     return status;
 }
 
diff --git a/libs/binder/ndk/AServiceManager.cpp b/libs/binder/ndk/AServiceManager.cpp
index f61b914..3979945 100644
--- a/libs/binder/ndk/AServiceManager.cpp
+++ b/libs/binder/ndk/AServiceManager.cpp
@@ -41,7 +41,7 @@
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> binder = sm->getService(String16(instance));
 
-    AIBinder* ret = new ABpBinder(binder);
-    AIBinder_incStrong(ret);
-    return ret;
+    sp<AIBinder> ret = ABpBinder::fromBinder(binder);
+    AIBinder_incStrong(ret.get());
+    return ret.get();
 }
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 23136a2..aa29437 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -144,7 +144,23 @@
 /**
  * If this is hosted in a process other than the current one.
  */
-bool AIBinder_isRemote(AIBinder* binder);
+bool AIBinder_isRemote(const AIBinder* binder);
+
+/**
+ * If this binder is known to be alive. This will not send a transaction to a remote process and
+ * returns a result based on the last known information. That is, whenever a transaction is made,
+ * this is automatically updated to reflect the current alive status of this binder. This will be
+ * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
+ * based on the results of bookkeeping or other transactions made internally.
+ */
+bool AIBinder_isAlive(const AIBinder* binder);
+
+/**
+ * Built-in transaction for all binder objects. This sends a transaction which will immediately
+ * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
+ * sanity check.
+ */
+binder_status_t AIBinder_ping(AIBinder* binder);
 
 /**
  * This can only be called if a strong reference to this object already exists in process.
@@ -167,13 +183,12 @@
  * However, if an object is just intended to be passed through to another process or used as a
  * handle this need not be called.
  *
- * The binder parameter may or may not be updated. If it is updated, the ownership of the original
- * object is transferred to the new object. If the class association fails, ownership of the binder
- * is lost, and it is set to nullptr.
+ * This returns true if the class association succeeds. If it fails, no change is made to the
+ * binder object.
  */
-void AIBinder_associateClass(AIBinder** binder, const AIBinder_Class* clazz);
+bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz);
 
-/*
+/**
  * Returns the class that this binder was constructed with or associated with.
  */
 const AIBinder_Class* AIBinder_getClass(AIBinder* binder);
@@ -187,10 +202,9 @@
 /**
  * A transaction is a series of calls to these functions which looks this
  * - call AIBinder_prepareTransaction
- * - fill out parcel with in parameters (lifetime of the 'in' variable)
+ * - fill out the in parcel with parameters (lifetime of the 'in' variable)
  * - call AIBinder_transact
- * - fill out parcel with out parameters (lifetime of the 'out' variable)
- * - call AIBinder_finalizeTransaction
+ * - read results from the out parcel (lifetime of the 'out' variable)
  */
 
 /**
@@ -201,7 +215,10 @@
  * can be avoided. This AIBinder must be either built with a class or associated with a class before
  * using this API.
  *
- * This does not affect the ownership of binder.
+ * This does not affect the ownership of binder. When this function succeeds, the in parcel's
+ * ownership is passed to the caller. At this point, the parcel can be filled out and passed to
+ * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
+ * deleted with AParcel_delete.
  */
 binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in);
 
@@ -214,29 +231,22 @@
  * remote process has processed the transaction, and the out parcel will contain the output data
  * from transaction.
  *
- * This does not affect the ownership of binder.
+ * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
+ * and must be released with AParcel_delete when finished reading.
  */
 binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
                                   AParcel** out, binder_flags_t flags);
 
 /**
- * This takes ownership of the out parcel and automatically deletes it. Additional checks for
- * security or debugging maybe performed internally.
- *
- * This does not affect the ownership of binder.
- */
-binder_status_t AIBinder_finalizeTransaction(AIBinder* binder, AParcel** out);
-
-/*
  * This does not take any ownership of the input binder, but it can be used to retrieve it if
  * something else in some process still holds a reference to it.
  */
 __attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder);
 
-/*
+/**
  * Deletes the weak reference. This will have no impact on the lifetime of the binder.
  */
-void AIBinder_Weak_delete(AIBinder_Weak* weakBinder);
+void AIBinder_Weak_delete(AIBinder_Weak** weakBinder);
 
 /**
  * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 091ae8e..19925f7 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -35,6 +35,11 @@
 typedef struct AParcel AParcel;
 
 /**
+ * Cleans up a parcel and sets it to nullptr.
+ */
+void AParcel_delete(AParcel** parcel);
+
+/**
  * Writes an AIBinder to the next location in a non-null parcel. Can be null.
  */
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder);
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
index eed09f0..a1aa0fa 100644
--- a/libs/binder/ndk/test/iface.cpp
+++ b/libs/binder/ndk/test/iface.cpp
@@ -81,7 +81,8 @@
         int32_t out;
         CHECK(EX_NONE == AParcel_readInt32(parcelOut, &out));
 
-        CHECK(EX_NONE == AIBinder_finalizeTransaction(mBinder, &parcelOut));
+        AParcel_delete(&parcelOut);
+
         return out;
     }
 
@@ -91,7 +92,7 @@
 };
 
 IFoo::~IFoo() {
-    AIBinder_Weak_delete(mWeakBinder);
+    AIBinder_Weak_delete(&mWeakBinder);
 }
 
 binder_status_t IFoo::addService(const char* instance) {
@@ -105,7 +106,7 @@
         // or one strong refcount here
         binder = AIBinder_new(IFoo::kClass, static_cast<void*>(new IFoo_Class_Data{this}));
         if (mWeakBinder != nullptr) {
-            AIBinder_Weak_delete(mWeakBinder);
+            AIBinder_Weak_delete(&mWeakBinder);
         }
         mWeakBinder = AIBinder_Weak_new(binder);
     }
@@ -118,12 +119,15 @@
 
 sp<IFoo> IFoo::getService(const char* instance) {
     AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
-    AIBinder_associateClass(&binder, IFoo::kClass);
-
     if (binder == nullptr) {
         return nullptr;
     }
 
+    if (!AIBinder_associateClass(binder, IFoo::kClass)) {
+        AIBinder_decStrong(binder);
+        return nullptr;
+    }
+
     if (AIBinder_isRemote(binder)) {
         sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
         return ret;
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 7c53e51..967789f 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -38,6 +38,10 @@
 TEST(NdkBinder, RetrieveNonNdkService) {
     AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
     ASSERT_NE(nullptr, binder);
+    EXPECT_TRUE(AIBinder_isRemote(binder));
+    EXPECT_TRUE(AIBinder_isAlive(binder));
+    EXPECT_EQ(EX_NONE, AIBinder_ping(binder));
+
     AIBinder_decStrong(binder);
 }
 
diff --git a/libs/binder/tests/binderTextOutputTest.cpp b/libs/binder/tests/binderTextOutputTest.cpp
index f6dd22d..ce99f59 100644
--- a/libs/binder/tests/binderTextOutputTest.cpp
+++ b/libs/binder/tests/binderTextOutputTest.cpp
@@ -28,15 +28,14 @@
 #include <binder/TextOutput.h>
 #include <binder/Debug.h>
 
-static void CheckMessage(const CapturedStderr& cap,
+static void CheckMessage(CapturedStderr& cap,
                          const char* expected,
                          bool singleline) {
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
+    cap.Stop();
+    std::string output = cap.str();
     if (singleline)
         output.erase(std::remove(output.begin(), output.end(), '\n'));
-    ASSERT_STREQ(output.c_str(), expected);
+    ASSERT_EQ(output, expected);
 }
 
 #define CHECK_LOG_(input, expect, singleline)    \
@@ -60,28 +59,22 @@
 TEST(TextOutput, HandlesStdEndl) {
     CapturedStderr cap;
     android::aerr << "foobar" << std::endl;
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_STREQ(output.c_str(), "foobar\n");
+    cap.Stop();
+    ASSERT_EQ(cap.str(), "foobar\n");
 }
 
 TEST(TextOutput, HandlesCEndl) {
     CapturedStderr cap;
     android::aerr << "foobar" << "\n";
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_STREQ(output.c_str(), "foobar\n");
+    cap.Stop();
+    ASSERT_EQ(cap.str(), "foobar\n");
 }
 
 TEST(TextOutput, HandlesAndroidEndl) {
     CapturedStderr cap;
     android::aerr << "foobar" << android::endl;
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_STREQ(output.c_str(), "foobar\n");
+    cap.Stop();
+    ASSERT_EQ(cap.str(), "foobar\n");
 }
 
 TEST(TextOutput, HandleEmptyString) {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 5d27bf6..778c453 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -20,9 +20,12 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include <android-base/stringprintf.h>
 #include <input/InputDevice.h>
 #include <input/InputEventLabels.h>
 
+using android::base::StringPrintf;
+
 namespace android {
 
 static const char* CONFIGURATION_FILE_DIR[] = {
@@ -41,8 +44,8 @@
     return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
 }
 
-static void appendInputDeviceConfigurationFileRelativePath(String8& path,
-        const String8& name, InputDeviceConfigurationFileType type) {
+static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
+        const std::string& name, InputDeviceConfigurationFileType type) {
     path.append(CONFIGURATION_FILE_DIR[type]);
     for (size_t i = 0; i < name.length(); i++) {
         char ch = name[i];
@@ -54,28 +57,28 @@
     path.append(CONFIGURATION_FILE_EXTENSION[type]);
 }
 
-String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
         const InputDeviceIdentifier& deviceIdentifier,
         InputDeviceConfigurationFileType type) {
     if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
         if (deviceIdentifier.version != 0) {
             // Try vendor product version.
-            String8 versionPath(getInputDeviceConfigurationFilePathByName(
-                    String8::format("Vendor_%04x_Product_%04x_Version_%04x",
+            std::string versionPath = getInputDeviceConfigurationFilePathByName(
+                    StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
                             deviceIdentifier.vendor, deviceIdentifier.product,
                             deviceIdentifier.version),
-                    type));
-            if (!versionPath.isEmpty()) {
+                    type);
+            if (!versionPath.empty()) {
                 return versionPath;
             }
         }
 
         // Try vendor product.
-        String8 productPath(getInputDeviceConfigurationFilePathByName(
-                String8::format("Vendor_%04x_Product_%04x",
+        std::string productPath = getInputDeviceConfigurationFilePathByName(
+                StringPrintf("Vendor_%04x_Product_%04x",
                         deviceIdentifier.vendor, deviceIdentifier.product),
-                type));
-        if (!productPath.isEmpty()) {
+                type);
+        if (!productPath.empty()) {
             return productPath;
         }
     }
@@ -84,22 +87,25 @@
     return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
 }
 
-String8 getInputDeviceConfigurationFilePathByName(
-        const String8& name, InputDeviceConfigurationFileType type) {
+std::string getInputDeviceConfigurationFilePathByName(
+        const std::string& name, InputDeviceConfigurationFileType type) {
     // Search system repository.
-    String8 path;
+    std::string path;
 
     // Treblized input device config files will be located /odm/usr or /vendor/usr.
     const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
     for (size_t i = 0; i < size(rootsForPartition); i++) {
-        path.setTo(rootsForPartition[i]);
-        path.append("/usr/");
+        if (rootsForPartition[i] == nullptr) {
+            continue;
+        }
+        path = rootsForPartition[i];
+        path += "/usr/";
         appendInputDeviceConfigurationFileRelativePath(path, name, type);
 #if DEBUG_PROBE
         ALOGD("Probing for system provided input device configuration file: path='%s'",
-              path.string());
+              path.c_str());
 #endif
-        if (!access(path.string(), R_OK)) {
+        if (!access(path.c_str(), R_OK)) {
 #if DEBUG_PROBE
             ALOGD("Found");
 #endif
@@ -109,13 +115,17 @@
 
     // Search user repository.
     // TODO Should only look here if not in safe mode.
-    path.setTo(getenv("ANDROID_DATA"));
-    path.append("/system/devices/");
+    path = "";
+    char *androidData = getenv("ANDROID_DATA");
+    if (androidData != nullptr) {
+        path += androidData;
+    }
+    path += "/system/devices/";
     appendInputDeviceConfigurationFileRelativePath(path, name, type);
 #if DEBUG_PROBE
-    ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
+    ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
 #endif
-    if (!access(path.string(), R_OK)) {
+    if (!access(path.c_str(), R_OK)) {
 #if DEBUG_PROBE
         ALOGD("Found");
 #endif
@@ -125,16 +135,16 @@
     // Not found.
 #if DEBUG_PROBE
     ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
-            name.string(), type);
+            name.c_str(), type);
 #endif
-    return String8();
+    return "";
 }
 
 
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
-    initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
+    initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
 }
 
 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
@@ -150,7 +160,7 @@
 }
 
 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
-        const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+        const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
         bool hasMic) {
     mId = id;
     mGeneration = generation;
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 26747bd..e189d20 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -106,14 +106,14 @@
     }
 }
 
-status_t KeyCharacterMap::load(const String8& filename,
+status_t KeyCharacterMap::load(const std::string& filename,
         Format format, sp<KeyCharacterMap>* outMap) {
     outMap->clear();
 
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
+    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
     if (status) {
-        ALOGE("Error %d opening key character map file %s.", status, filename.string());
+        ALOGE("Error %d opening key character map file %s.", status, filename.c_str());
     } else {
         status = load(tokenizer, format, outMap);
         delete tokenizer;
@@ -121,12 +121,12 @@
     return status;
 }
 
-status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
+status_t KeyCharacterMap::loadContents(const std::string& filename, const char* contents,
         Format format, sp<KeyCharacterMap>* outMap) {
     outMap->clear();
 
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
+    status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
     if (status) {
         ALOGE("Error %d opening key character map.", status);
     } else {
@@ -944,7 +944,7 @@
             properties.add(Property(PROPERTY_NUMBER));
         } else {
             int32_t metaState;
-            status_t status = parseModifier(token, &metaState);
+            status_t status = parseModifier(token.string(), &metaState);
             if (status) {
                 ALOGE("%s: Expected a property name or modifier, got '%s'.",
                         mTokenizer->getLocation().string(), token.string());
@@ -1137,7 +1137,7 @@
     return NO_ERROR;
 }
 
-status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
+status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
     if (token == "base") {
         *outMetaState = 0;
         return NO_ERROR;
@@ -1145,7 +1145,7 @@
 
     int32_t combinedMeta = 0;
 
-    const char* str = token.string();
+    const char* str = token.c_str();
     const char* start = str;
     for (const char* cur = str; ; cur++) {
         char ch = *cur;
@@ -1164,7 +1164,7 @@
             }
             if (combinedMeta & metaState) {
                 ALOGE("%s: Duplicate modifier combination '%s'.",
-                        mTokenizer->getLocation().string(), token.string());
+                        mTokenizer->getLocation().string(), token.c_str());
                 return BAD_VALUE;
             }
 
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index c440078..88cb0db 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -49,13 +49,13 @@
 KeyLayoutMap::~KeyLayoutMap() {
 }
 
-status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
+status_t KeyLayoutMap::load(const std::string& filename, sp<KeyLayoutMap>* outMap) {
     outMap->clear();
 
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
+    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
     if (status) {
-        ALOGE("Error %d opening key layout map file %s.", status, filename.string());
+        ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
     } else {
         sp<KeyLayoutMap> map = new KeyLayoutMap();
         if (!map.get()) {
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 11842ee..0c22bfe 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -45,22 +45,22 @@
         String8 keyLayoutName;
         if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
                 keyLayoutName)) {
-            status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
+            status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
             if (status == NAME_NOT_FOUND) {
                 ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
                         "it was not found.",
-                        deviceIdenfifier.name.string(), keyLayoutName.string());
+                        deviceIdenfifier.name.c_str(), keyLayoutName.string());
             }
         }
 
         String8 keyCharacterMapName;
         if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
                 keyCharacterMapName)) {
-            status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
+            status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
             if (status == NAME_NOT_FOUND) {
                 ALOGE("Configuration for keyboard device '%s' requested keyboard character "
                         "map '%s' but it was not found.",
-                        deviceIdenfifier.name.string(), keyLayoutName.string());
+                        deviceIdenfifier.name.c_str(), keyLayoutName.string());
             }
         }
 
@@ -70,30 +70,30 @@
     }
 
     // Try searching by device identifier.
-    if (probeKeyMap(deviceIdenfifier, String8::empty())) {
+    if (probeKeyMap(deviceIdenfifier, "")) {
         return OK;
     }
 
     // Fall back on the Generic key map.
     // TODO Apply some additional heuristics here to figure out what kind of
     //      generic key map to use (US English, etc.) for typical external keyboards.
-    if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
+    if (probeKeyMap(deviceIdenfifier, "Generic")) {
         return OK;
     }
 
     // Try the Virtual key map as a last resort.
-    if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
+    if (probeKeyMap(deviceIdenfifier, "Virtual")) {
         return OK;
     }
 
     // Give up!
     ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
-            deviceIdenfifier.name.string());
+            deviceIdenfifier.name.c_str());
     return NAME_NOT_FOUND;
 }
 
 bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& keyMapName) {
+        const std::string& keyMapName) {
     if (!haveKeyLayout()) {
         loadKeyLayout(deviceIdentifier, keyMapName);
     }
@@ -104,10 +104,10 @@
 }
 
 status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name) {
-    String8 path(getPath(deviceIdentifier, name,
+        const std::string& name) {
+    std::string path(getPath(deviceIdentifier, name,
             INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
-    if (path.isEmpty()) {
+    if (path.empty()) {
         return NAME_NOT_FOUND;
     }
 
@@ -116,15 +116,15 @@
         return status;
     }
 
-    keyLayoutFile.setTo(path);
+    keyLayoutFile = path;
     return OK;
 }
 
 status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name) {
-    String8 path(getPath(deviceIdentifier, name,
-            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
-    if (path.isEmpty()) {
+        const std::string& name) {
+    std::string path = getPath(deviceIdentifier, name,
+            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP);
+    if (path.empty()) {
         return NAME_NOT_FOUND;
     }
 
@@ -134,13 +134,13 @@
         return status;
     }
 
-    keyCharacterMapFile.setTo(path);
+    keyCharacterMapFile = path;
     return OK;
 }
 
-String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name, InputDeviceConfigurationFileType type) {
-    return name.isEmpty()
+std::string KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
+        const std::string& name, InputDeviceConfigurationFileType type) {
+    return name.empty()
             ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
             : getInputDeviceConfigurationFilePathByName(name, type);
 }
@@ -174,7 +174,7 @@
         }
     }
 
-    return strstr(deviceIdentifier.name.string(), "-keypad");
+    return strstr(deviceIdentifier.name.c_str(), "-keypad");
 }
 
 static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 9932973..3ec53bf 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -46,13 +46,13 @@
 VirtualKeyMap::~VirtualKeyMap() {
 }
 
-status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
+status_t VirtualKeyMap::load(const std::string& filename, VirtualKeyMap** outMap) {
     *outMap = nullptr;
 
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
+    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
     if (status) {
-        ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
+        ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
     } else {
         VirtualKeyMap* map = new VirtualKeyMap();
         if (!map) {
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 77a474f..a964d29 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -76,16 +76,16 @@
     return value ? "true" : "false";
 }
 
-static String8 sha1(const String8& in) {
+static std::string sha1(const std::string& in) {
     SHA_CTX ctx;
     SHA1_Init(&ctx);
-    SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
+    SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.c_str()), in.size());
     u_char digest[SHA_DIGEST_LENGTH];
     SHA1_Final(digest, &ctx);
 
-    String8 out;
+    std::string out;
     for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) {
-        out.appendFormat("%02x", digest[i]);
+        out += StringPrintf("%02x", digest[i]);
     }
     return out;
 }
@@ -141,7 +141,7 @@
 
 // --- EventHub::Device ---
 
-EventHub::Device::Device(int fd, int32_t id, const String8& path,
+EventHub::Device::Device(int fd, int32_t id, const std::string& path,
         const InputDeviceIdentifier& identifier) :
         next(nullptr),
         fd(fd), id(id), path(path), identifier(identifier),
@@ -172,9 +172,9 @@
 }
 
 status_t EventHub::Device::enable() {
-    fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+    fd = open(path.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
     if(fd < 0) {
-        ALOGE("could not open %s, %s\n", path.string(), strerror(errno));
+        ALOGE("could not open %s, %s\n", path.c_str(), strerror(errno));
         return -errno;
     }
     enabled = true;
@@ -307,7 +307,7 @@
             struct input_absinfo info;
             if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
                 ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
-                     axis, device->identifier.name.string(), device->fd, errno);
+                     axis, device->identifier.name.c_str(), device->fd, errno);
                 return -errno;
             }
 
@@ -416,7 +416,7 @@
             struct input_absinfo info;
             if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
                 ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
-                     axis, device->identifier.name.string(), device->fd, errno);
+                     axis, device->identifier.name.c_str(), device->fd, errno);
                 return -errno;
             }
 
@@ -512,7 +512,7 @@
     return NAME_NOT_FOUND;
 }
 
-void EventHub::setExcludedDevices(const Vector<String8>& devices) {
+void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
     AutoMutex _l(mLock);
 
     mExcludedDevices = devices;
@@ -599,16 +599,16 @@
     return false;
 }
 
-static String8 generateDescriptor(InputDeviceIdentifier& identifier) {
-    String8 rawDescriptor;
-    rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor,
+static std::string generateDescriptor(InputDeviceIdentifier& identifier) {
+    std::string rawDescriptor;
+    rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor,
             identifier.product);
     // TODO add handling for USB devices to not uniqueify kbs that show up twice
-    if (!identifier.uniqueId.isEmpty()) {
-        rawDescriptor.append("uniqueId:");
-        rawDescriptor.append(identifier.uniqueId);
+    if (!identifier.uniqueId.empty()) {
+        rawDescriptor += "uniqueId:";
+        rawDescriptor += identifier.uniqueId;
     } else if (identifier.nonce != 0) {
-        rawDescriptor.appendFormat("nonce:%04x", identifier.nonce);
+        rawDescriptor += StringPrintf("nonce:%04x", identifier.nonce);
     }
 
     if (identifier.vendor == 0 && identifier.product == 0) {
@@ -616,12 +616,12 @@
         // built-in so we need to rely on other information to uniquely identify
         // the input device.  Usually we try to avoid relying on the device name or
         // location but for built-in input device, they are unlikely to ever change.
-        if (!identifier.name.isEmpty()) {
-            rawDescriptor.append("name:");
-            rawDescriptor.append(identifier.name);
-        } else if (!identifier.location.isEmpty()) {
-            rawDescriptor.append("location:");
-            rawDescriptor.append(identifier.location);
+        if (!identifier.name.empty()) {
+            rawDescriptor += "name:";
+            rawDescriptor += identifier.name;
+        } else if (!identifier.location.empty()) {
+            rawDescriptor += "location:";
+            rawDescriptor += identifier.location;
         }
     }
     identifier.descriptor = sha1(rawDescriptor);
@@ -637,8 +637,8 @@
     // Ideally, we also want the descriptor to be short and relatively opaque.
 
     identifier.nonce = 0;
-    String8 rawDescriptor = generateDescriptor(identifier);
-    if (identifier.uniqueId.isEmpty()) {
+    std::string rawDescriptor = generateDescriptor(identifier);
+    if (identifier.uniqueId.empty()) {
         // If it didn't have a unique id check for conflicts and enforce
         // uniqueness if necessary.
         while(getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) {
@@ -646,8 +646,8 @@
             rawDescriptor = generateDescriptor(identifier);
         }
     }
-    ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(),
-            identifier.descriptor.string());
+    ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(),
+            identifier.descriptor.c_str());
 }
 
 void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
@@ -664,7 +664,7 @@
         effect.replay.delay = 0;
         if (ioctl(device->fd, EVIOCSFF, &effect)) {
             ALOGW("Could not upload force feedback effect to device %s due to error %d.",
-                    device->identifier.name.string(), errno);
+                    device->identifier.name.c_str(), errno);
             return;
         }
         device->ffEffectId = effect.id;
@@ -677,7 +677,7 @@
         ev.value = 1;
         if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
             ALOGW("Could not start force feedback effect on device %s due to error %d.",
-                    device->identifier.name.string(), errno);
+                    device->identifier.name.c_str(), errno);
             return;
         }
         device->ffEffectPlaying = true;
@@ -699,18 +699,18 @@
             ev.value = 0;
             if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
                 ALOGW("Could not stop force feedback effect on device %s due to error %d.",
-                        device->identifier.name.string(), errno);
+                        device->identifier.name.c_str(), errno);
                 return;
             }
         }
     }
 }
 
-EventHub::Device* EventHub::getDeviceByDescriptorLocked(String8& descriptor) const {
+EventHub::Device* EventHub::getDeviceByDescriptorLocked(const std::string& descriptor) const {
     size_t size = mDevices.size();
     for (size_t i = 0; i < size; i++) {
         Device* device = mDevices.valueAt(i);
-        if (descriptor.compare(device->identifier.descriptor) == 0) {
+        if (descriptor == device->identifier.descriptor) {
             return device;
         }
     }
@@ -763,7 +763,7 @@
         while (mClosingDevices) {
             Device* device = mClosingDevices;
             ALOGV("Reporting device closed: id=%d, name=%s\n",
-                 device->id, device->path.string());
+                 device->id, device->path.c_str());
             mClosingDevices = device->next;
             event->when = now;
             event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
@@ -785,7 +785,7 @@
         while (mOpeningDevices != nullptr) {
             Device* device = mOpeningDevices;
             ALOGV("Reporting device opened: id=%d, name=%s\n",
-                 device->id, device->path.string());
+                 device->id, device->path.c_str());
             mOpeningDevices = device->next;
             event->when = now;
             event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
@@ -867,7 +867,7 @@
                     for (size_t i = 0; i < count; i++) {
                         struct input_event& iev = readBuffer[i];
                         ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
-                                device->path.string(),
+                                device->path.c_str(),
                                 (int) iev.time.tv_sec, (int) iev.time.tv_usec,
                                 iev.type, iev.code, iev.value);
 
@@ -936,7 +936,7 @@
                                         "event time %" PRId64 ", current time %" PRId64
                                         ", call time %" PRId64 ".  "
                                         "Using current time instead.",
-                                        device->path.string(), event->when, time, now);
+                                        device->path.c_str(), event->when, time, now);
                                 event->when = time;
                             } else {
                                 ALOGV("Event time is ok but failed the fast path and required "
@@ -962,12 +962,12 @@
                 }
             } else if (eventItem.events & EPOLLHUP) {
                 ALOGI("Removing device %s due to epoll hang-up event.",
-                        device->identifier.name.string());
+                        device->identifier.name.c_str());
                 deviceChanged = true;
                 closeDeviceLocked(device);
             } else {
                 ALOGW("Received unexpected epoll event 0x%08x for device %s.",
-                        eventItem.events, device->identifier.name.string());
+                        eventItem.events, device->identifier.name.c_str());
             }
         }
 
@@ -1125,14 +1125,14 @@
         //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
     } else {
         buffer[sizeof(buffer) - 1] = '\0';
-        identifier.name.setTo(buffer);
+        identifier.name = buffer;
     }
 
     // Check to see if the device is on our excluded list
     for (size_t i = 0; i < mExcludedDevices.size(); i++) {
-        const String8& item = mExcludedDevices.itemAt(i);
+        const std::string& item = mExcludedDevices[i];
         if (identifier.name == item) {
-            ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
+            ALOGI("ignoring event id %s driver %s\n", devicePath, item.c_str());
             close(fd);
             return -1;
         }
@@ -1163,7 +1163,7 @@
         //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
     } else {
         buffer[sizeof(buffer) - 1] = '\0';
-        identifier.location.setTo(buffer);
+        identifier.location = buffer;
     }
 
     // Get device unique id.
@@ -1171,7 +1171,7 @@
         //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
     } else {
         buffer[sizeof(buffer) - 1] = '\0';
-        identifier.uniqueId.setTo(buffer);
+        identifier.uniqueId = buffer;
     }
 
     // Fill in the descriptor.
@@ -1179,7 +1179,7 @@
 
     // Allocate device.  (The device object takes ownership of the fd at this point.)
     int32_t deviceId = mNextDeviceId++;
-    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
+    Device* device = new Device(fd, deviceId, devicePath, identifier);
 
     ALOGV("add device %d: %s\n", deviceId, devicePath);
     ALOGV("  bus:        %04x\n"
@@ -1187,10 +1187,10 @@
          "  product     %04x\n"
          "  version     %04x\n",
         identifier.bus, identifier.vendor, identifier.product, identifier.version);
-    ALOGV("  name:       \"%s\"\n", identifier.name.string());
-    ALOGV("  location:   \"%s\"\n", identifier.location.string());
-    ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.string());
-    ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.string());
+    ALOGV("  name:       \"%s\"\n", identifier.name.c_str());
+    ALOGV("  location:   \"%s\"\n", identifier.location.c_str());
+    ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.c_str());
+    ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.c_str());
     ALOGV("  driver:     v%d.%d.%d\n",
         driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
 
@@ -1343,7 +1343,7 @@
     // If the device isn't recognized as something we handle, don't monitor it.
     if (device->classes == 0) {
         ALOGV("Dropping device: id=%d, path='%s', name='%s'",
-                deviceId, devicePath, device->identifier.name.string());
+                deviceId, devicePath, device->identifier.name.c_str());
         delete device;
         return -1;
     }
@@ -1374,11 +1374,11 @@
 
     ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
             "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
-         deviceId, fd, devicePath, device->identifier.name.string(),
+         deviceId, fd, devicePath, device->identifier.name.c_str(),
          device->classes,
-         device->configurationFile.string(),
-         device->keyMap.keyLayoutFile.string(),
-         device->keyMap.keyCharacterMapFile.string(),
+         device->configurationFile.c_str(),
+         device->keyMap.keyLayoutFile.c_str(),
+         device->keyMap.keyCharacterMapFile.c_str(),
          toString(mBuiltInKeyboardId == deviceId));
 
     addDeviceLocked(device);
@@ -1392,11 +1392,11 @@
         unsigned int repeatRate[] = {0, 0};
         if (ioctl(device->fd, EVIOCSREP, repeatRate)) {
             ALOGW("Unable to disable kernel key repeat for %s: %s",
-                  device->path.string(), strerror(errno));
+                  device->path.c_str(), strerror(errno));
         }
     }
 
-    String8 wakeMechanism("EPOLLWAKEUP");
+    std::string wakeMechanism = "EPOLLWAKEUP";
     if (!mUsingEpollWakeup) {
 #ifndef EVIOCSSUSPENDBLOCK
         // uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels
@@ -1416,7 +1416,7 @@
     // clock.
     int clockId = CLOCK_MONOTONIC;
     bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);
-    ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(),
+    ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(),
           toString(usingClockIoctl));
 }
 
@@ -1473,7 +1473,7 @@
     identifier.uniqueId = "<virtual>";
     assignDescriptorLocked(identifier);
 
-    Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier);
+    Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, "<virtual>", identifier);
     device->classes = INPUT_DEVICE_CLASS_KEYBOARD
             | INPUT_DEVICE_CLASS_ALPHAKEY
             | INPUT_DEVICE_CLASS_DPAD
@@ -1491,26 +1491,26 @@
 void EventHub::loadConfigurationLocked(Device* device) {
     device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
             device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
-    if (device->configurationFile.isEmpty()) {
+    if (device->configurationFile.empty()) {
         ALOGD("No input device configuration file found for device '%s'.",
-                device->identifier.name.string());
+                device->identifier.name.c_str());
     } else {
-        status_t status = PropertyMap::load(device->configurationFile,
+        status_t status = PropertyMap::load(String8(device->configurationFile.c_str()),
                 &device->configuration);
         if (status) {
             ALOGE("Error loading input device configuration file for device '%s'.  "
                     "Using default configuration.",
-                    device->identifier.name.string());
+                    device->identifier.name.c_str());
         }
     }
 }
 
 status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
     // The virtual key map is supplied by the kernel as a system board property file.
-    String8 path;
-    path.append("/sys/board_properties/virtualkeys.");
-    path.append(device->identifier.name);
-    if (access(path.string(), R_OK)) {
+    std::string path;
+    path += "/sys/board_properties/virtualkeys.";
+    path += device->identifier.name;
+    if (access(path.c_str(), R_OK)) {
         return NAME_NOT_FOUND;
     }
     return VirtualKeyMap::load(path, &device->virtualKeyMap);
@@ -1543,7 +1543,7 @@
 int32_t EventHub::getNextControllerNumberLocked(Device* device) {
     if (mControllerNumbers.isFull()) {
         ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
-                device->identifier.name.string());
+                device->identifier.name.c_str());
         return 0;
     }
     // Since the controller number 0 is reserved for non-controllers, translate all numbers up by
@@ -1617,12 +1617,12 @@
 
 void EventHub::closeDeviceLocked(Device* device) {
     ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
-         device->path.string(), device->identifier.name.string(), device->id,
+         device->path.c_str(), device->identifier.name.c_str(), device->id,
          device->fd, device->classes);
 
     if (device->id == mBuiltInKeyboardId) {
         ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
-                device->path.string(), mBuiltInKeyboardId);
+                device->path.c_str(), mBuiltInKeyboardId);
         mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
     }
 
@@ -1648,7 +1648,7 @@
         // Unlink the device from the opening devices list then delete it.
         // We don't need to tell the client that the device was closed because
         // it does not even know it was opened in the first place.
-        ALOGI("Device %s was immediately closed after opening.", device->path.string());
+        ALOGI("Device %s was immediately closed after opening.", device->path.c_str());
         if (pred) {
             pred->next = device->next;
         } else {
@@ -1750,28 +1750,28 @@
             const Device* device = mDevices.valueAt(i);
             if (mBuiltInKeyboardId == device->id) {
                 dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
-                        device->id, device->identifier.name.string());
+                        device->id, device->identifier.name.c_str());
             } else {
                 dump += StringPrintf(INDENT2 "%d: %s\n", device->id,
-                        device->identifier.name.string());
+                        device->identifier.name.c_str());
             }
             dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes);
-            dump += StringPrintf(INDENT3 "Path: %s\n", device->path.string());
+            dump += StringPrintf(INDENT3 "Path: %s\n", device->path.c_str());
             dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(device->enabled));
-            dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
-            dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.string());
+            dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.c_str());
+            dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.c_str());
             dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
-            dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
+            dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.c_str());
             dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
                     "product=0x%04x, version=0x%04x\n",
                     device->identifier.bus, device->identifier.vendor,
                     device->identifier.product, device->identifier.version);
             dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n",
-                    device->keyMap.keyLayoutFile.string());
+                    device->keyMap.keyLayoutFile.c_str());
             dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
-                    device->keyMap.keyCharacterMapFile.string());
+                    device->keyMap.keyCharacterMapFile.c_str());
             dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
-                    device->configurationFile.string());
+                    device->configurationFile.c_str());
             dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
                     toString(device->overlayKeyMap != nullptr));
         }
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index dfe3def..ea663b7 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -18,6 +18,8 @@
 #ifndef _RUNTIME_EVENT_HUB_H
 #define _RUNTIME_EVENT_HUB_H
 
+#include <vector>
+
 #include <input/Input.h>
 #include <input/InputDevice.h>
 #include <input/Keyboard.h>
@@ -29,7 +31,6 @@
 #include <utils/List.h>
 #include <utils/Errors.h>
 #include <utils/PropertyMap.h>
-#include <utils/Vector.h>
 #include <utils/KeyedVector.h>
 #include <utils/BitSet.h>
 
@@ -207,7 +208,7 @@
 
     // Sets devices that are excluded from opening.
     // This can be used to ignore input devices for sensors.
-    virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
+    virtual void setExcludedDevices(const std::vector<std::string>& devices) = 0;
 
     /*
      * Wait for events to become available and returns them.
@@ -303,7 +304,7 @@
     virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
             AxisInfo* outAxisInfo) const;
 
-    virtual void setExcludedDevices(const Vector<String8>& devices);
+    virtual void setExcludedDevices(const std::vector<std::string>& devices);
 
     virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
     virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
@@ -344,7 +345,7 @@
 
         int fd; // may be -1 if device is closed
         const int32_t id;
-        const String8 path;
+        const std::string path;
         const InputDeviceIdentifier identifier;
 
         uint32_t classes;
@@ -357,7 +358,7 @@
         uint8_t ffBitmask[(FF_MAX + 1) / 8];
         uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
 
-        String8 configurationFile;
+        std::string configurationFile;
         PropertyMap* configuration;
         VirtualKeyMap* virtualKeyMap;
         KeyMap keyMap;
@@ -373,7 +374,8 @@
         int32_t timestampOverrideSec;
         int32_t timestampOverrideUsec;
 
-        Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
+        Device(int fd, int32_t id, const std::string& path,
+                const InputDeviceIdentifier& identifier);
         ~Device();
 
         void close();
@@ -413,7 +415,7 @@
     void scanDevicesLocked();
     status_t readNotifyLocked();
 
-    Device* getDeviceByDescriptorLocked(String8& descriptor) const;
+    Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
     Device* getDeviceLocked(int32_t deviceId) const;
     Device* getDeviceByPathLocked(const char* devicePath) const;
 
@@ -457,7 +459,7 @@
     bool mNeedToSendFinishedDeviceScan;
     bool mNeedToReopenDevices;
     bool mNeedToScanDevices;
-    Vector<String8> mExcludedDevices;
+    std::vector<std::string> mExcludedDevices;
 
     int mEpollFd;
     int mINotifyFd;
diff --git a/services/inputflinger/InputApplication.h b/services/inputflinger/InputApplication.h
index 724fc2c..9b365b9 100644
--- a/services/inputflinger/InputApplication.h
+++ b/services/inputflinger/InputApplication.h
@@ -17,6 +17,8 @@
 #ifndef _UI_INPUT_APPLICATION_H
 #define _UI_INPUT_APPLICATION_H
 
+#include <string>
+
 #include <input/Input.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index c805805..d609573 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -515,9 +515,10 @@
 sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
         int32_t x, int32_t y) {
     // Traverse windows from front to back to find touched window.
-    size_t numWindows = mWindowHandles.size();
+    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+    size_t numWindows = windowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+        sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
         const InputWindowInfo* windowInfo = windowHandle->getInfo();
         if (windowInfo->displayId == displayId) {
             int32_t flags = windowInfo->layoutParamsFlags;
@@ -1247,9 +1248,10 @@
         bool isTouchModal = false;
 
         // Traverse windows from front to back to find touched window and outside targets.
-        size_t numWindows = mWindowHandles.size();
+        const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+        size_t numWindows = windowHandles.size();
         for (size_t i = 0; i < numWindows; i++) {
-            sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+            sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
             const InputWindowInfo* windowInfo = windowHandle->getInfo();
             if (windowInfo->displayId != displayId) {
                 continue; // wrong display
@@ -1472,8 +1474,10 @@
         sp<InputWindowHandle> foregroundWindowHandle =
                 mTempTouchState.getFirstForegroundWindowHandle();
         if (foregroundWindowHandle->getInfo()->hasWallpaper) {
-            for (size_t i = 0; i < mWindowHandles.size(); i++) {
-                sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+            const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+            size_t numWindows = windowHandles.size();
+            for (size_t i = 0; i < numWindows; i++) {
+                sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
                 const InputWindowInfo* info = windowHandle->getInfo();
                 if (info->displayId == displayId
                         && windowHandle->getInfo()->layoutParamsType
@@ -1658,9 +1662,10 @@
 bool InputDispatcher::isWindowObscuredAtPointLocked(
         const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
     int32_t displayId = windowHandle->getInfo()->displayId;
-    size_t numWindows = mWindowHandles.size();
+    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+    size_t numWindows = windowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+        sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
         if (otherHandle == windowHandle) {
             break;
         }
@@ -1678,10 +1683,11 @@
 
 bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
     int32_t displayId = windowHandle->getInfo()->displayId;
+    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
-    size_t numWindows = mWindowHandles.size();
+    size_t numWindows = windowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+        sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
         if (otherHandle == windowHandle) {
             break;
         }
@@ -2909,13 +2915,27 @@
     }
 }
 
+Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
+    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it =
+        mWindowHandlesByDisplay.find(displayId);
+    if(it != mWindowHandlesByDisplay.end()) {
+        return it->second;
+    }
+
+    // Return an empty one if nothing found.
+    return Vector<sp<InputWindowHandle>>();
+}
+
 sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
         const sp<InputChannel>& inputChannel) const {
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-        if (windowHandle->getInputChannel() == inputChannel) {
-            return windowHandle;
+    for (auto& it : mWindowHandlesByDisplay) {
+        const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+        size_t numWindows = windowHandles.size();
+        for (size_t i = 0; i < numWindows; i++) {
+            const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+            if (windowHandle->getInputChannel() == inputChannel) {
+                return windowHandle;
+            }
         }
     }
     return nullptr;
@@ -2923,45 +2943,90 @@
 
 bool InputDispatcher::hasWindowHandleLocked(
         const sp<InputWindowHandle>& windowHandle) const {
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        if (mWindowHandles.itemAt(i) == windowHandle) {
-            return true;
+    for (auto& it : mWindowHandlesByDisplay) {
+        const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+        size_t numWindows = windowHandles.size();
+        for (size_t i = 0; i < numWindows; i++) {
+            if (windowHandles.itemAt(i) == windowHandle) {
+                if (windowHandle->getInfo()->displayId != it.first) {
+                    ALOGE("Found window %s in display %d, but it should belong to display %d",
+                        windowHandle->getName().c_str(), it.first,
+                        windowHandle->getInfo()->displayId);
+                }
+                return true;
+            }
         }
     }
     return false;
 }
 
-void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
+/**
+ * Called from InputManagerService, update window handle list by displayId that can receive input.
+ * A window handle contains information about InputChannel, Touch Region, Types, Focused,...
+ * If set an empty list, remove all handles from the specific display.
+ * For focused handle, check if need to change and send a cancel event to previous one.
+ * For removed handle, check if need to send a cancel event if already in touch.
+ */
+void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
+        int32_t displayId) {
 #if DEBUG_FOCUS
     ALOGD("setInputWindows");
 #endif
     { // acquire lock
         AutoMutex _l(mLock);
 
-        Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
-        mWindowHandles = inputWindowHandles;
+        // Copy old handles for release if they are no longer present.
+        const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
 
-        sp<InputWindowHandle> newFocusedWindowHandle;
+        // TODO(b/111361570): multi-display focus, one focus window per display.
+        sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle;
+        // Reset newFocusedWindowHandle to nullptr if current display own the focus window,
+        // that will be updated below when going through all window handles in current display.
+        // And if list of window handles becomes empty then it will be updated by other display.
+        if (mFocusedWindowHandle != nullptr) {
+            const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
+            if (info == nullptr || info->displayId == displayId) {
+                newFocusedWindowHandle = nullptr;
+            }
+        }
+
         bool foundHoveredWindow = false;
-        for (size_t i = 0; i < mWindowHandles.size(); i++) {
-            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-            if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
-                mWindowHandles.removeAt(i--);
-                continue;
+
+        if (inputWindowHandles.isEmpty()) {
+            // Remove all handles on a display if there are no windows left.
+            mWindowHandlesByDisplay.erase(displayId);
+        } else {
+            size_t numWindows = inputWindowHandles.size();
+            for (size_t i = 0; i < numWindows; i++) {
+                const sp<InputWindowHandle>& windowHandle = inputWindowHandles.itemAt(i);
+                if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
+                    continue;
+                }
+
+                if (windowHandle->getInfo()->displayId != displayId) {
+                    ALOGE("Window %s updated by wrong display %d, should belong to display %d",
+                        windowHandle->getName().c_str(), displayId,
+                        windowHandle->getInfo()->displayId);
+                    continue;
+                }
+
+                if (windowHandle->getInfo()->hasFocus) {
+                    newFocusedWindowHandle = windowHandle;
+                }
+                if (windowHandle == mLastHoverWindowHandle) {
+                    foundHoveredWindow = true;
+                }
             }
-            if (windowHandle->getInfo()->hasFocus) {
-                newFocusedWindowHandle = windowHandle;
-            }
-            if (windowHandle == mLastHoverWindowHandle) {
-                foundHoveredWindow = true;
-            }
+
+            // Insert or replace
+            mWindowHandlesByDisplay[displayId] = inputWindowHandles;
         }
 
         if (!foundHoveredWindow) {
             mLastHoverWindowHandle = nullptr;
         }
 
+        // TODO(b/111361570): multi-display focus, one focus in all display in current.
         if (mFocusedWindowHandle != newFocusedWindowHandle) {
             if (mFocusedWindowHandle != nullptr) {
 #if DEBUG_FOCUS
@@ -2985,8 +3050,9 @@
             mFocusedWindowHandle = newFocusedWindowHandle;
         }
 
-        for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
-            TouchState& state = mTouchStatesByDisplay.editValueAt(d);
+        ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
+        if (stateIndex >= 0) {
+            TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex);
             for (size_t i = 0; i < state.windows.size(); ) {
                 TouchedWindow& touchedWindow = state.windows.editItemAt(i);
                 if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
@@ -3013,7 +3079,8 @@
         // This ensures that unused input channels are released promptly.
         // Otherwise, they might stick around until the window handle is destroyed
         // which might not happen until the next GC.
-        for (size_t i = 0; i < oldWindowHandles.size(); i++) {
+        size_t numWindows = oldWindowHandles.size();
+        for (size_t i = 0; i < numWindows; i++) {
             const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
             if (!hasWindowHandleLocked(oldWindowHandle)) {
 #if DEBUG_FOCUS
@@ -3266,36 +3333,44 @@
         dump += INDENT "TouchStates: <no displays touched>\n";
     }
 
-    if (!mWindowHandles.isEmpty()) {
-        dump += INDENT "Windows:\n";
-        for (size_t i = 0; i < mWindowHandles.size(); i++) {
-            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-            const InputWindowInfo* windowInfo = windowHandle->getInfo();
+    if (!mWindowHandlesByDisplay.empty()) {
+       for (auto& it : mWindowHandlesByDisplay) {
+            const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+            dump += StringPrintf(INDENT "Display: %d\n", it.first);
+            if (!windowHandles.isEmpty()) {
+                dump += INDENT2 "Windows:\n";
+                for (size_t i = 0; i < windowHandles.size(); i++) {
+                    const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+                    const InputWindowInfo* windowInfo = windowHandle->getInfo();
 
-            dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, "
-                    "paused=%s, hasFocus=%s, hasWallpaper=%s, "
-                    "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
-                    "frame=[%d,%d][%d,%d], scale=%f, "
-                    "touchableRegion=",
-                    i, windowInfo->name.c_str(), windowInfo->displayId,
-                    toString(windowInfo->paused),
-                    toString(windowInfo->hasFocus),
-                    toString(windowInfo->hasWallpaper),
-                    toString(windowInfo->visible),
-                    toString(windowInfo->canReceiveKeys),
-                    windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
-                    windowInfo->layer,
-                    windowInfo->frameLeft, windowInfo->frameTop,
-                    windowInfo->frameRight, windowInfo->frameBottom,
-                    windowInfo->scaleFactor);
-            dumpRegion(dump, windowInfo->touchableRegion);
-            dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
-            dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
-                    windowInfo->ownerPid, windowInfo->ownerUid,
-                    windowInfo->dispatchingTimeout / 1000000.0);
+                    dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
+                            "paused=%s, hasFocus=%s, hasWallpaper=%s, "
+                            "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
+                            "frame=[%d,%d][%d,%d], scale=%f, "
+                            "touchableRegion=",
+                            i, windowInfo->name.c_str(), windowInfo->displayId,
+                            toString(windowInfo->paused),
+                            toString(windowInfo->hasFocus),
+                            toString(windowInfo->hasWallpaper),
+                            toString(windowInfo->visible),
+                            toString(windowInfo->canReceiveKeys),
+                            windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
+                            windowInfo->layer,
+                            windowInfo->frameLeft, windowInfo->frameTop,
+                            windowInfo->frameRight, windowInfo->frameBottom,
+                            windowInfo->scaleFactor);
+                    dumpRegion(dump, windowInfo->touchableRegion);
+                    dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
+                    dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+                            windowInfo->ownerPid, windowInfo->ownerUid,
+                            windowInfo->dispatchingTimeout / 1000000.0);
+                }
+            } else {
+                dump += INDENT2 "Windows: <none>\n";
+            }
         }
     } else {
-        dump += INDENT "Windows: <none>\n";
+        dump += INDENT "Displays: <none>\n";
     }
 
     if (!mMonitoringChannels.isEmpty()) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 31ab339..fdf75f6 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -31,6 +31,7 @@
 #include <stddef.h>
 #include <unistd.h>
 #include <limits.h>
+#include <unordered_map>
 
 #include "InputWindow.h"
 #include "InputApplication.h"
@@ -307,7 +308,8 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
+    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+            int32_t displayId) = 0;
 
     /* Sets the focused application.
      *
@@ -387,7 +389,8 @@
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags);
 
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+            int32_t displayId);
     virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
     virtual void setInputDispatchMode(bool enabled, bool frozen);
     virtual void setInputFilterEnabled(bool enabled);
@@ -956,8 +959,9 @@
     bool mDispatchFrozen;
     bool mInputFilterEnabled;
 
-    Vector<sp<InputWindowHandle> > mWindowHandles;
-
+    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
+    // Get window handles by display, return an empty vector if not found.
+    Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
     sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
     bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
 
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index a213b2d..92e0af2 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -31,7 +31,6 @@
 #include <utils/Vector.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 
 namespace android {
 
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index a4f83b7..8f12129 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -257,11 +257,12 @@
 // --- InputReaderConfiguration ---
 
 bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
-        const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
+        const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
     const DisplayViewport* viewport = nullptr;
-    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != nullptr) {
+    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && !uniqueDisplayId.empty()) {
+
         for (const DisplayViewport& currentViewport : mVirtualDisplays) {
-            if (currentViewport.uniqueId == *uniqueDisplayId) {
+            if (currentViewport.uniqueId == uniqueDisplayId) {
                 viewport = &currentViewport;
                 break;
             }
@@ -473,10 +474,10 @@
 
     if (device->isIgnored()) {
         ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
-                identifier.name.string());
+                identifier.name.c_str());
     } else {
         ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
-                identifier.name.string(), device->getSources());
+                identifier.name.c_str(), device->getSources());
     }
 
     mDevices.add(deviceId, device);
@@ -501,10 +502,10 @@
 
     if (device->isIgnored()) {
         ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
-                device->getId(), device->getName().string());
+                device->getId(), device->getName().c_str());
     } else {
         ALOGI("Device removed: id=%d, name='%s', sources=0x%08x",
-                device->getId(), device->getName().string(), device->getSources());
+                device->getId(), device->getName().c_str(), device->getSources());
     }
 
     if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
@@ -687,7 +688,7 @@
     if (now < mDisableVirtualKeysTimeout) {
         ALOGI("Dropping virtual key from device %s because virtual keys are "
                 "temporarily disabled for the next %0.3fms.  keyCode=%d, scanCode=%d",
-                device->getName().string(),
+                device->getName().c_str(),
                 (mDisableVirtualKeysTimeout - now) * 0.000001,
                 keyCode, scanCode);
         return true;
@@ -894,7 +895,7 @@
         if (i != 0) {
             dump += ", ";
         }
-        dump += mConfig.excludedDeviceNames.itemAt(i).string();
+        dump += mConfig.excludedDeviceNames[i];
     }
     dump += "]\n";
     dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
@@ -1077,7 +1078,7 @@
     getDeviceInfo(& deviceInfo);
 
     dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
-            deviceInfo.getDisplayName().string());
+            deviceInfo.getDisplayName().c_str());
     dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
     dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
     dump += StringPrintf(INDENT2 "HasMic:     %s\n", toString(mHasMic));
@@ -1135,7 +1136,7 @@
 
         if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
             if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
-                String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
+                std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
                 if (mAlias != alias) {
                     mAlias = alias;
                     bumpGeneration();
@@ -1196,7 +1197,7 @@
 #endif
             }
         } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
-            ALOGI("Detected input event buffer overrun for device %s.", getName().string());
+            ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
             mDropUntilNextSync = true;
             reset(rawEvent->when);
         } else {
@@ -2294,7 +2295,7 @@
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         if (mParameters.orientationAware) {
             DisplayViewport dvp;
-            config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &dvp);
+            config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &dvp);
             mViewport = dvp;
         }
     }
@@ -2464,7 +2465,7 @@
             // key was not actually down
             ALOGI("Dropping key up from device %s because the key was not down.  "
                     "keyCode=%d, scanCode=%d",
-                    getDeviceName().string(), keyCode, scanCode);
+                    getDeviceName().c_str(), keyCode, scanCode);
             return;
         }
     }
@@ -2705,7 +2706,7 @@
         mOrientation = DISPLAY_ORIENTATION_0;
         if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
             DisplayViewport v;
-            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &v)) {
+            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
                 mOrientation = v.orientation;
             }
         }
@@ -3020,7 +3021,7 @@
     }
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         DisplayViewport v;
-        if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &v)) {
+        if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
             mOrientation = v.orientation;
         } else {
             mOrientation = DISPLAY_ORIENTATION_0;
@@ -3394,8 +3395,10 @@
         mParameters.hasAssociatedDisplay = true;
         if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
             mParameters.associatedDisplayIsExternal = getDevice()->isExternal();
+            String8 uniqueDisplayId;
             getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"),
-                    mParameters.uniqueDisplayId);
+                    uniqueDisplayId);
+            mParameters.uniqueDisplayId = uniqueDisplayId.c_str();
         }
     }
 
@@ -3506,7 +3509,7 @@
     // Ensure we have valid X and Y axes.
     if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
         ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis!  "
-                "The device will be inoperable.", getDeviceName().string());
+                "The device will be inoperable.", getDeviceName().c_str());
         mDeviceMode = DEVICE_MODE_DISABLED;
         return;
     }
@@ -3518,15 +3521,15 @@
     // Get associated display dimensions.
     DisplayViewport newViewport;
     if (mParameters.hasAssociatedDisplay) {
-        const String8* uniqueDisplayId = nullptr;
+        std::string uniqueDisplayId;
         ViewportType viewportTypeToUse;
 
         if (mParameters.associatedDisplayIsExternal) {
             viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
-        } else if (!mParameters.uniqueDisplayId.isEmpty()) {
+        } else if (!mParameters.uniqueDisplayId.empty()) {
             // 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;
+            uniqueDisplayId = mParameters.uniqueDisplayId;
             viewportTypeToUse = ViewportType::VIEWPORT_VIRTUAL;
         } else {
             viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
@@ -3536,7 +3539,7 @@
             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.",
-                    getDeviceName().string());
+                    getDeviceName().c_str());
             mDeviceMode = DEVICE_MODE_DISABLED;
             return;
         }
@@ -3642,7 +3645,7 @@
     if (viewportChanged || deviceModeChanged) {
         ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
                 "display id %d",
-                getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
+                getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight,
                 mSurfaceOrientation, mDeviceMode, mViewport.displayId);
 
         // Configure X and Y factors.
@@ -6925,7 +6928,7 @@
 #if DEBUG_POINTERS
             ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
                     "ignoring the rest.",
-                    getDeviceName().string(), MAX_POINTERS);
+                    getDeviceName().c_str(), MAX_POINTERS);
 #endif
             break; // too many fingers!
         }
@@ -7016,7 +7019,7 @@
         if (slotCount > MAX_SLOTS) {
             ALOGW("MultiTouch Device %s reported %zu slots but the framework "
                     "only supports a maximum of %zu slots at this time.",
-                    getDeviceName().string(), slotCount, MAX_SLOTS);
+                    getDeviceName().c_str(), slotCount, MAX_SLOTS);
             slotCount = MAX_SLOTS;
         }
         mMultiTouchMotionAccumulator.configure(getDevice(),
@@ -7259,7 +7262,7 @@
         // Prefer to keep explicitly mapped axes.
         if (mAxes.size() > PointerCoords::MAX_AXES) {
             ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.",
-                    getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES);
+                    getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES);
             pruneAxes(true);
             pruneAxes(false);
         }
@@ -7281,7 +7284,7 @@
                 } else {
                     ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
                             "have already been assigned to other axes.",
-                            getDeviceName().string(), mAxes.keyAt(i));
+                            getDeviceName().c_str(), mAxes.keyAt(i));
                     mAxes.removeItemsAt(i--);
                     numAxes -= 1;
                 }
@@ -7310,7 +7313,7 @@
             continue;
         }
         ALOGI("Discarding joystick '%s' axis %d because there are too many axes.",
-                getDeviceName().string(), mAxes.keyAt(i));
+                getDeviceName().c_str(), mAxes.keyAt(i));
         mAxes.removeItemsAt(i);
     }
 }
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index af26b4f..c06168d 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -101,7 +101,7 @@
 
     // The excluded device names for the platform.
     // Devices with these names will be ignored.
-    Vector<String8> excludedDeviceNames;
+    std::vector<std::string> excludedDeviceNames;
 
     // Velocity control parameters for mouse pointer movements.
     VelocityControlParameters pointerVelocityControlParameters;
@@ -201,7 +201,7 @@
             pointerGestureZoomSpeedRatio(0.3f),
             showTouches(false) { }
 
-    bool getDisplayViewport(ViewportType viewportType, const String8* displayId,
+    bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
             DisplayViewport* outViewport) const;
     void setPhysicalDisplayViewport(ViewportType viewportType, const DisplayViewport& viewport);
     void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
@@ -274,11 +274,11 @@
             const InputDeviceIdentifier& identifier) = 0;
 
     /* Gets a user-supplied alias for a particular input device, or an empty string if none. */
-    virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
+    virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
 
     /* Gets the affine calibration associated with the specified device. */
     virtual TouchAffineTransformation getTouchAffineTransformation(
-            const String8& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
+            const std::string& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
 };
 
 
@@ -553,8 +553,8 @@
     inline int32_t getId() const { return mId; }
     inline int32_t getControllerNumber() const { return mControllerNumber; }
     inline int32_t getGeneration() const { return mGeneration; }
-    inline const String8& getName() const { return mIdentifier.name; }
-    inline const String8& getDescriptor() { return mIdentifier.descriptor; }
+    inline const std::string getName() const { return mIdentifier.name; }
+    inline const std::string getDescriptor() { return mIdentifier.descriptor; }
     inline uint32_t getClasses() const { return mClasses; }
     inline uint32_t getSources() const { return mSources; }
 
@@ -625,7 +625,7 @@
     int32_t mGeneration;
     int32_t mControllerNumber;
     InputDeviceIdentifier mIdentifier;
-    String8 mAlias;
+    std::string mAlias;
     uint32_t mClasses;
 
     Vector<InputMapper*> mMappers;
@@ -981,7 +981,7 @@
 
     inline InputDevice* getDevice() { return mDevice; }
     inline int32_t getDeviceId() { return mDevice->getId(); }
-    inline const String8 getDeviceName() { return mDevice->getName(); }
+    inline const std::string getDeviceName() { return mDevice->getName(); }
     inline InputReaderContext* getContext() { return mContext; }
     inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); }
     inline InputListenerInterface* getListener() { return mContext->getListener(); }
@@ -1309,7 +1309,7 @@
         bool associatedDisplayIsExternal;
         bool orientationAware;
         bool hasButtonUnderPad;
-        String8 uniqueDisplayId;
+        std::string uniqueDisplayId;
 
         enum GestureMode {
             GESTURE_MODE_SINGLE_TOUCH,
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index bd11d56..2f046c3 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -217,18 +217,18 @@
     idi.product = id->productId;
     idi.version = id->version;
 
-    String8 configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
+    std::string configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
             idi, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
-    if (configFile.isEmpty()) {
+    if (configFile.empty()) {
         ALOGD("No input device configuration file found for device '%s'.",
-                idi.name.string());
+                idi.name.c_str());
     } else {
         auto propMap = new input_property_map_t();
-        status_t status = PropertyMap::load(configFile, &propMap->propertyMap);
+        status_t status = PropertyMap::load(String8(configFile.c_str()), &propMap->propertyMap);
         if (status) {
             ALOGE("Error loading input device configuration file for device '%s'. "
                     "Using default configuration.",
-                    idi.name.string());
+                    idi.name.c_str());
             delete propMap;
             return nullptr;
         }
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0e26d4a..61dcdd9 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -103,13 +103,20 @@
 protected:
     sp<FakeInputDispatcherPolicy> mFakePolicy;
     sp<InputDispatcher> mDispatcher;
+    sp<InputDispatcherThread> mDispatcherThread;
 
     virtual void SetUp() {
         mFakePolicy = new FakeInputDispatcherPolicy();
         mDispatcher = new InputDispatcher(mFakePolicy);
+        mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+        //Start InputDispatcher thread
+        mDispatcherThread = new InputDispatcherThread(mDispatcher);
+        mDispatcherThread->run("InputDispatcherTest", PRIORITY_URGENT_DISPLAY);
     }
 
     virtual void TearDown() {
+        mDispatcherThread->requestExit();
+        mDispatcherThread.clear();
         mFakePolicy.clear();
         mDispatcher.clear();
     }
@@ -253,4 +260,297 @@
             << "Should reject motion events with duplicate pointer ids.";
 }
 
+// --- InputDispatcherTest SetInputWindowTest ---
+static const int32_t INJECT_EVENT_TIMEOUT = 500;
+static const int32_t DISPATCHING_TIMEOUT = 100;
+
+class FakeApplicationHandle : public InputApplicationHandle {
+public:
+    FakeApplicationHandle() {}
+    virtual ~FakeApplicationHandle() {}
+
+    virtual bool updateInfo() {
+        if (!mInfo) {
+            mInfo = new InputApplicationInfo();
+        }
+        mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+        return true;
+    }
+};
+
+class FakeWindowHandle : public InputWindowHandle {
+public:
+    static const int32_t WIDTH = 600;
+    static const int32_t HEIGHT = 800;
+
+    FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+        const sp<InputDispatcher>& dispatcher, const std::string name) :
+            InputWindowHandle(inputApplicationHandle), mDispatcher(dispatcher),
+            mName(name), mFocused(false), mDisplayId(ADISPLAY_ID_DEFAULT) {
+        InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+        mConsumer = new InputConsumer(mClientChannel);
+        mDispatcher->registerInputChannel(mServerChannel, this, false);
+    }
+
+    virtual ~FakeWindowHandle() {
+        mDispatcher->unregisterInputChannel(mServerChannel);
+        mServerChannel.clear();
+        mClientChannel.clear();
+        mDispatcher.clear();
+
+        if (mConsumer != nullptr) {
+            delete mConsumer;
+        }
+    }
+
+    virtual bool updateInfo() {
+        if (!mInfo) {
+            mInfo = new InputWindowInfo();
+        }
+        mInfo->inputChannel = mServerChannel;
+        mInfo->name = mName;
+        mInfo->layoutParamsFlags = 0;
+        mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+        mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+        mInfo->frameLeft = 0;
+        mInfo->frameTop = 0;
+        mInfo->frameRight = WIDTH;
+        mInfo->frameBottom = HEIGHT;
+        mInfo->scaleFactor = 1.0;
+        mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+        mInfo->visible = true;
+        mInfo->canReceiveKeys = true;
+        mInfo->hasFocus = mFocused;
+        mInfo->hasWallpaper = false;
+        mInfo->paused = false;
+        mInfo->layer = 0;
+        mInfo->ownerPid = INJECTOR_PID;
+        mInfo->ownerUid = INJECTOR_UID;
+        mInfo->inputFeatures = 0;
+        mInfo->displayId = mDisplayId;
+
+        return true;
+    }
+
+    void setFocus() {
+        mFocused = true;
+    }
+
+    void setDisplayId(int32_t displayId) {
+        mDisplayId = displayId;
+    }
+
+    void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId) {
+        uint32_t consumeSeq;
+        InputEvent* event;
+        status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+            &consumeSeq, &event);
+
+        ASSERT_EQ(OK, status)
+                << mName.c_str() << ": consumer consume should return OK.";
+        ASSERT_TRUE(event != nullptr)
+                << mName.c_str() << ": consumer should have returned non-NULL event.";
+        ASSERT_EQ(expectedEventType, event->getType())
+                << mName.c_str() << ": consumer type should same as expected one.";
+
+        ASSERT_EQ(expectedDisplayId, event->getDisplayId())
+                << mName.c_str() << ": consumer displayId should same as expected one.";
+
+        status = mConsumer->sendFinishedSignal(consumeSeq, true /*handled*/);
+        ASSERT_EQ(OK, status)
+                << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
+    }
+
+    void assertNoEvents() {
+        uint32_t consumeSeq;
+        InputEvent* event;
+        status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+            &consumeSeq, &event);
+        ASSERT_NE(OK, status)
+                << mName.c_str()
+                << ": should not have received any events, so consume(..) should not return OK.";
+    }
+
+    private:
+        sp<InputDispatcher> mDispatcher;
+        sp<InputChannel> mServerChannel, mClientChannel;
+        InputConsumer *mConsumer;
+        PreallocatedInputEventFactory mEventFactory;
+
+        std::string mName;
+        bool mFocused;
+        int32_t mDisplayId;
+};
+
+static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) {
+    KeyEvent event;
+    nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+    // Define a valid key down event.
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+            AKEY_EVENT_ACTION_DOWN, /* flags */ 0,
+            AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime);
+
+    // Inject event until dispatch out.
+    return dispatcher->injectInputEvent(
+            &event,
+            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+            INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+}
+
+static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t displayId) {
+    MotionEvent event;
+    PointerProperties pointerProperties[1];
+    PointerCoords pointerCoords[1];
+
+    pointerProperties[0].clear();
+    pointerProperties[0].id = 0;
+    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+    pointerCoords[0].clear();
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200);
+
+    nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    // Define a valid motion down event.
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, displayId,
+            AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
+            AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+            /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
+            pointerCoords);
+
+    // Inject event until dispatch out.
+    return dispatcher->injectInputEvent(
+            &event,
+            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+            INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window");
+
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.add(window);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Window should receive motion event.
+    window->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+}
+
+// The foreground window should receive the first touch down event.
+TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
+    sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.add(windowTop);
+    inputWindowHandles.add(windowSecond);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Top window should receive the touch down event. Second window should not receive anything.
+    windowTop->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+    windowSecond->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
+    sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+
+    // Set focus application.
+    mDispatcher->setFocusedApplication(application);
+
+    // Expect one focus window exist in display.
+    windowSecond->setFocus();
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.add(windowTop);
+    inputWindowHandles.add(windowSecond);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Focused window should receive event.
+    windowTop->assertNoEvents();
+    windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
+    sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application, mDispatcher, "D_2");
+
+    // Test the primary display touch down.
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push(windowInPrimary);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+    windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+    windowInSecondary->assertNoEvents();
+
+    // Test the second display touch down.
+    constexpr int32_t SECOND_DISPLAY_ID = 1;
+    windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
+    Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+    inputWindowHandles_Second.push(windowInSecondary);
+
+    mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, SECOND_DISPLAY_ID))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+    windowInPrimary->assertNoEvents();
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
+}
+
+// TODO(b/111361570): multi-display focus, one focus window per display.
+TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
+    sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");
+
+    // Set focus to second display window.
+    mDispatcher->setFocusedApplication(application2);
+    windowInSecondary->setFocus();
+
+    // Update all windows per displays.
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push(windowInPrimary);
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+
+    constexpr int32_t SECOND_DISPLAY_ID = 1;
+    windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
+    Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+    inputWindowHandles_Second.push(windowInSecondary);
+    mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+
+    // Test inject a key down.
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+    windowInPrimary->assertNoEvents();
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+
+    // Remove secondary display.
+    inputWindowHandles_Second.clear();
+    mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+
+    // Expect old focus should receive a cancel event.
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+
+    // Test inject a key down, should timeout because of no target window.
+    ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+            << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+    windowInPrimary->assertNoEvents();
+    windowInSecondary->assertNoEvents();
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 286cf88..9b985dc 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -142,7 +142,7 @@
     }
 
     void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
-            const String8& uniqueId) {
+            const std::string& uniqueId) {
         DisplayViewport v = createDisplayViewport(displayId, width, height, orientation, uniqueId);
         // Set the size of both the internal and external display at the same time.
         mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL, v);
@@ -150,14 +150,14 @@
     }
 
     void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
-            const String8& uniqueId) {
+            const std::string& uniqueId) {
         Vector<DisplayViewport> viewports;
         viewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId));
         mConfig.setVirtualDisplayViewports(viewports);
     }
 
-    void addExcludedDeviceName(const String8& deviceName) {
-        mConfig.excludedDeviceNames.push(deviceName);
+    void addExcludedDeviceName(const std::string& deviceName) {
+        mConfig.excludedDeviceNames.push_back(deviceName);
     }
 
     void addDisabledDevice(int32_t deviceId) {
@@ -188,7 +188,7 @@
         return mInputDevices;
     }
 
-    TouchAffineTransformation getTouchAffineTransformation(const String8& inputDeviceDescriptor,
+    TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
             int32_t surfaceRotation) {
         return transform;
     }
@@ -203,7 +203,7 @@
 
 private:
     DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation, const String8& uniqueId) {
+            int32_t orientation, const std::string& uniqueId) {
         bool isRotated = (orientation == DISPLAY_ORIENTATION_90
                 || orientation == DISPLAY_ORIENTATION_270);
         DisplayViewport v;
@@ -239,8 +239,8 @@
         return nullptr;
     }
 
-    virtual String8 getDeviceAlias(const InputDeviceIdentifier&) {
-        return String8::empty();
+    virtual std::string getDeviceAlias(const InputDeviceIdentifier&) {
+        return "";
     }
 };
 
@@ -392,7 +392,7 @@
     };
 
     KeyedVector<int32_t, Device*> mDevices;
-    Vector<String8> mExcludedDevices;
+    std::vector<std::string> mExcludedDevices;
     List<RawEvent> mEvents;
 
 protected:
@@ -405,7 +405,7 @@
 public:
     FakeEventHub() { }
 
-    void addDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+    void addDevice(int32_t deviceId, const std::string& name, uint32_t classes) {
         Device* device = new Device(classes);
         device->identifier.name = name;
         mDevices.add(deviceId, device);
@@ -534,7 +534,7 @@
         return device->leds.valueFor(led);
     }
 
-    Vector<String8>& getExcludedDevices() {
+    std::vector<std::string>& getExcludedDevices() {
         return mExcludedDevices;
     }
 
@@ -566,7 +566,7 @@
 private:
     Device* getDevice(int32_t deviceId) const {
         ssize_t index = mDevices.indexOfKey(deviceId);
-        return index >= 0 ? mDevices.valueAt(index) : NULL;
+        return index >= 0 ? mDevices.valueAt(index) : nullptr;
     }
 
     virtual uint32_t getDeviceClasses(int32_t deviceId) const {
@@ -658,7 +658,7 @@
         return NAME_NOT_FOUND;
     }
 
-    virtual void setExcludedDevices(const Vector<String8>& devices) {
+    virtual void setExcludedDevices(const std::vector<std::string>& devices) {
         mExcludedDevices = devices;
     }
 
@@ -1052,7 +1052,7 @@
         mNextDevice = device;
     }
 
-    InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name,
+    InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
             uint32_t classes) {
         InputDeviceIdentifier identifier;
         identifier.name = name;
@@ -1101,7 +1101,7 @@
         mFakeEventHub.clear();
     }
 
-    void addDevice(int32_t deviceId, const String8& name, uint32_t classes,
+    void addDevice(int32_t deviceId, const std::string& name, uint32_t classes,
             const PropertyMap* configuration) {
         mFakeEventHub->addDevice(deviceId, name, classes);
 
@@ -1129,7 +1129,7 @@
     }
 
     FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
-            const String8& name, uint32_t classes, uint32_t sources,
+            const std::string& name, uint32_t classes, uint32_t sources,
             const PropertyMap* configuration) {
         InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
         FakeInputMapper* mapper = new FakeInputMapper(device, sources);
@@ -1141,17 +1141,18 @@
 };
 
 TEST_F(InputReaderTest, GetInputDevices) {
-    ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"),
+    ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard",
             INPUT_DEVICE_CLASS_KEYBOARD, nullptr));
-    ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"),
+    ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored",
             0, nullptr)); // no classes so device will be ignored
 
+
     Vector<InputDeviceInfo> inputDevices;
     mReader->getInputDevices(inputDevices);
 
     ASSERT_EQ(1U, inputDevices.size());
     ASSERT_EQ(1, inputDevices[0].getId());
-    ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
+    ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
     ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
     ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
     ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
@@ -1160,7 +1161,7 @@
     inputDevices = mFakePolicy->getInputDevices();
     ASSERT_EQ(1U, inputDevices.size());
     ASSERT_EQ(1, inputDevices[0].getId());
-    ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
+    ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
     ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
     ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
     ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
@@ -1169,12 +1170,12 @@
 TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
     constexpr int32_t deviceId = 1;
     constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
-    InputDevice* device = mReader->newDevice(deviceId, 0, String8("fake"), deviceClass);
+    InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
     // Must add at least one mapper or the device will be ignored!
     FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
     device->addMapper(mapper);
     mReader->setNextDevice(device);
-    addDevice(deviceId, String8("fake"), deviceClass, nullptr);
+    addDevice(deviceId, "fake", deviceClass, nullptr);
 
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
 
@@ -1208,7 +1209,7 @@
 
 TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = nullptr;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
     mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
 
@@ -1235,7 +1236,7 @@
 
 TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = nullptr;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
     mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
 
@@ -1262,7 +1263,7 @@
 
 TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = nullptr;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
     mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
 
@@ -1289,8 +1290,9 @@
 
 TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = nullptr;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
+
     mapper->addSupportedKeyCode(AKEYCODE_A);
     mapper->addSupportedKeyCode(AKEYCODE_B);
 
@@ -1323,7 +1325,7 @@
 }
 
 TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) {
-    addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
+    addDevice(1, "ignored", INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
 
     NotifyConfigurationChangedArgs args;
 
@@ -1333,7 +1335,7 @@
 
 TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
     FakeInputMapper* mapper = nullptr;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
 
     mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
@@ -1373,7 +1375,7 @@
         mFakeListener = new FakeInputListener();
         mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
 
-        mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
+        mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
         InputDeviceIdentifier identifier;
         identifier.name = DEVICE_NAME;
         mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
@@ -1399,7 +1401,7 @@
 
 TEST_F(InputDeviceTest, ImmutableProperties) {
     ASSERT_EQ(DEVICE_ID, mDevice->getId());
-    ASSERT_STREQ(DEVICE_NAME, mDevice->getName());
+    ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str());
     ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
 }
 
@@ -1427,7 +1429,7 @@
     InputDeviceInfo info;
     mDevice->getDeviceInfo(&info);
     ASSERT_EQ(DEVICE_ID, info.getId());
-    ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
+    ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str());
     ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType());
     ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources());
 
@@ -1497,7 +1499,7 @@
     InputDeviceInfo info;
     mDevice->getDeviceInfo(&info);
     ASSERT_EQ(DEVICE_ID, info.getId());
-    ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
+    ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str());
     ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType());
     ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources());
 
@@ -1570,7 +1572,7 @@
         mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
                 DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
 
-        mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
+        mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
     }
 
     virtual void TearDown() {
@@ -1597,12 +1599,12 @@
 
     void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
             int32_t orientation) {
-        mFakePolicy->setDisplayViewport(displayId, width, height, orientation, String8::empty());
+        mFakePolicy->setDisplayViewport(displayId, width, height, orientation, "");
         configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
 
     void setVirtualDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation, const String8& uniqueId) {
+            int32_t orientation, const std::string& uniqueId) {
         mFakePolicy->setVirtualDisplayViewport(displayId, width, height, orientation, uniqueId);
         configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
@@ -3048,7 +3050,7 @@
 
 void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) {
     setVirtualDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
-        VIRTUAL_DISPLAY_HEIGHT, orientation, String8(VIRTUAL_DISPLAY_UNIQUE_ID));
+        VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID);
 }
 
 void TouchInputMapperTest::prepareVirtualKeys() {
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 2712b1c..e94200e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -184,97 +184,6 @@
     return SyncFeatures::getInstance().useWaitSync();
 }
 
-base::unique_fd RenderEngine::flush() {
-    if (!GLExtensions::getInstance().hasNativeFenceSync()) {
-        return base::unique_fd();
-    }
-
-    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
-    if (sync == EGL_NO_SYNC_KHR) {
-        ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
-        return base::unique_fd();
-    }
-
-    // native fence fd will not be populated until flush() is done.
-    glFlush();
-
-    // get the fence fd
-    base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
-    eglDestroySyncKHR(mEGLDisplay, sync);
-    if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-        ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
-    }
-
-    return fenceFd;
-}
-
-bool RenderEngine::finish() {
-    if (!GLExtensions::getInstance().hasFenceSync()) {
-        ALOGW("no synchronization support");
-        return false;
-    }
-
-    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
-    if (sync == EGL_NO_SYNC_KHR) {
-        ALOGW("failed to create EGL fence sync: %#x", eglGetError());
-        return false;
-    }
-
-    EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
-                                         2000000000 /*2 sec*/);
-    EGLint error = eglGetError();
-    eglDestroySyncKHR(mEGLDisplay, sync);
-    if (result != EGL_CONDITION_SATISFIED_KHR) {
-        if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-            ALOGW("fence wait timed out");
-        } else {
-            ALOGW("error waiting on EGL fence: %#x", error);
-        }
-        return false;
-    }
-
-    return true;
-}
-
-bool RenderEngine::waitFence(base::unique_fd fenceFd) {
-    if (!GLExtensions::getInstance().hasNativeFenceSync() ||
-        !GLExtensions::getInstance().hasWaitSync()) {
-        return false;
-    }
-
-    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
-    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
-    if (sync == EGL_NO_SYNC_KHR) {
-        ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
-        return false;
-    }
-
-    // fenceFd is now owned by EGLSync
-    (void)fenceFd.release();
-
-    // XXX: The spec draft is inconsistent as to whether this should return an
-    // EGLint or void.  Ignore the return value for now, as it's not strictly
-    // needed.
-    eglWaitSyncKHR(mEGLDisplay, sync, 0);
-    EGLint error = eglGetError();
-    eglDestroySyncKHR(mEGLDisplay, sync);
-    if (error != EGL_SUCCESS) {
-        ALOGE("failed to wait for EGL native fence sync: %#x", error);
-        return false;
-    }
-
-    return true;
-}
-
-void RenderEngine::checkErrors() const {
-    do {
-        // there could be more than one error flag
-        GLenum error = glGetError();
-        if (error == GL_NO_ERROR) break;
-        ALOGE("GL error 0x%04x", int(error));
-    } while (true);
-}
-
 RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) {
     int major, minor;
     if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
@@ -293,56 +202,6 @@
     return GLES_VERSION_1_0;
 }
 
-void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
-                                       float green, float blue, float alpha) {
-    size_t c;
-    Rect const* r = region.getArray(&c);
-    Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
-    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    for (size_t i = 0; i < c; i++, r++) {
-        position[i * 6 + 0].x = r->left;
-        position[i * 6 + 0].y = height - r->top;
-        position[i * 6 + 1].x = r->left;
-        position[i * 6 + 1].y = height - r->bottom;
-        position[i * 6 + 2].x = r->right;
-        position[i * 6 + 2].y = height - r->bottom;
-        position[i * 6 + 3].x = r->left;
-        position[i * 6 + 3].y = height - r->top;
-        position[i * 6 + 4].x = r->right;
-        position[i * 6 + 4].y = height - r->bottom;
-        position[i * 6 + 5].x = r->right;
-        position[i * 6 + 5].y = height - r->top;
-    }
-    setupFillWithColor(red, green, blue, alpha);
-    drawMesh(mesh);
-}
-
-void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
-    glClearColor(red, green, blue, alpha);
-    glClear(GL_COLOR_BUFFER_BIT);
-}
-
-void RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
-    glScissor(left, bottom, right, top);
-    glEnable(GL_SCISSOR_TEST);
-}
-
-void RenderEngine::disableScissor() {
-    glDisable(GL_SCISSOR_TEST);
-}
-
-void RenderEngine::genTextures(size_t count, uint32_t* names) {
-    glGenTextures(count, names);
-}
-
-void RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
-    glDeleteTextures(count, names);
-}
-
-void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
-    glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-}
-
 void RenderEngine::dump(String8& result) {
     const GLExtensions& extensions = GLExtensions::getInstance();
 
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index bfabf4d..61df675 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -34,6 +34,7 @@
 #include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
 #include <ui/Rect.h>
+#include <ui/Region.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
 #include "GLExtensions.h"
@@ -195,6 +196,134 @@
     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 }
 
+base::unique_fd GLES20RenderEngine::flush() {
+    if (!GLExtensions::getInstance().hasNativeFenceSync()) {
+        return base::unique_fd();
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+        return base::unique_fd();
+    }
+
+    // native fence fd will not be populated until flush() is done.
+    glFlush();
+
+    // get the fence fd
+    base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+        ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+    }
+
+    return fenceFd;
+}
+
+bool GLES20RenderEngine::finish() {
+    if (!GLExtensions::getInstance().hasFenceSync()) {
+        ALOGW("no synchronization support");
+        return false;
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+                                         2000000000 /*2 sec*/);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (result != EGL_CONDITION_SATISFIED_KHR) {
+        if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            ALOGW("fence wait timed out");
+        } else {
+            ALOGW("error waiting on EGL fence: %#x", error);
+        }
+        return false;
+    }
+
+    return true;
+}
+
+bool GLES20RenderEngine::waitFence(base::unique_fd fenceFd) {
+    if (!GLExtensions::getInstance().hasNativeFenceSync() ||
+        !GLExtensions::getInstance().hasWaitSync()) {
+        return false;
+    }
+
+    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    // fenceFd is now owned by EGLSync
+    (void)fenceFd.release();
+
+    // XXX: The spec draft is inconsistent as to whether this should return an
+    // EGLint or void.  Ignore the return value for now, as it's not strictly
+    // needed.
+    eglWaitSyncKHR(mEGLDisplay, sync, 0);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (error != EGL_SUCCESS) {
+        ALOGE("failed to wait for EGL native fence sync: %#x", error);
+        return false;
+    }
+
+    return true;
+}
+
+void GLES20RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
+                                             float green, float blue, float alpha) {
+    size_t c;
+    Rect const* r = region.getArray(&c);
+    Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
+    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+    for (size_t i = 0; i < c; i++, r++) {
+        position[i * 6 + 0].x = r->left;
+        position[i * 6 + 0].y = height - r->top;
+        position[i * 6 + 1].x = r->left;
+        position[i * 6 + 1].y = height - r->bottom;
+        position[i * 6 + 2].x = r->right;
+        position[i * 6 + 2].y = height - r->bottom;
+        position[i * 6 + 3].x = r->left;
+        position[i * 6 + 3].y = height - r->top;
+        position[i * 6 + 4].x = r->right;
+        position[i * 6 + 4].y = height - r->bottom;
+        position[i * 6 + 5].x = r->right;
+        position[i * 6 + 5].y = height - r->top;
+    }
+    setupFillWithColor(red, green, blue, alpha);
+    drawMesh(mesh);
+}
+
+void GLES20RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+    glClearColor(red, green, blue, alpha);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void GLES20RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
+    glScissor(left, bottom, right, top);
+    glEnable(GL_SCISSOR_TEST);
+}
+
+void GLES20RenderEngine::disableScissor() {
+    glDisable(GL_SCISSOR_TEST);
+}
+
+void GLES20RenderEngine::genTextures(size_t count, uint32_t* names) {
+    glGenTextures(count, names);
+}
+
+void GLES20RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+    glDeleteTextures(count, names);
+}
+
 void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName,
                                                   const Image& image) {
     const GLImage& glImage = static_cast<const GLImage&>(image);
@@ -207,6 +336,10 @@
     }
 }
 
+void GLES20RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
+    glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+}
+
 status_t GLES20RenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
     GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
     EGLImageKHR eglImage = glFramebuffer->getEGLImage();
@@ -245,6 +378,15 @@
     disableScissor();
 }
 
+void GLES20RenderEngine::checkErrors() const {
+    do {
+        // there could be more than one error flag
+        GLenum error = glGetError();
+        if (error == GL_NO_ERROR) break;
+        ALOGE("GL error 0x%04x", int(error));
+    } while (true);
+}
+
 void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                                   ui::Transform::orientation_flags rotation) {
     int32_t l = sourceCrop.left;
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
index 3113e53..04dc1b1 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
@@ -48,14 +48,24 @@
     std::unique_ptr<Image> createImage() override;
 
     void primeCache() const override;
-
-    bool isCurrent() const;
+    bool isCurrent() const override;
     bool setCurrentSurface(const Surface& surface) override;
     void resetCurrentSurface() override;
-
+    base::unique_fd flush() override;
+    bool finish() override;
+    bool waitFence(base::unique_fd fenceFd) override;
+    void clearWithColor(float red, float green, float blue, float alpha) override;
+    void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
+                                     float blue, float alpha) override;
+    void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
+    void disableScissor() override;
+    void genTextures(size_t count, uint32_t* names) override;
+    void deleteTextures(size_t count, uint32_t const* names) override;
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
+    void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) override;
     status_t bindFrameBuffer(Framebuffer* framebuffer) override;
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
+    void checkErrors() const override;
 
 protected:
     void dump(String8& result) override;
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.cpp b/services/surfaceflinger/RenderEngine/gl/Program.cpp
index 4d6839b..c8d6cf9 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/Program.cpp
@@ -20,7 +20,6 @@
 
 #include <log/log.h>
 #include <math/mat4.h>
-#include <renderengine/private/Description.h>
 #include <utils/String8.h>
 #include "ProgramCache.h"
 
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
index 7777202..86a1264 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
@@ -25,8 +25,8 @@
 #include <EGL/eglext.h>
 #include <android-base/unique_fd.h>
 #include <math/mat4.h>
-#include <renderengine/Image.h>
 #include <renderengine/Framebuffer.h>
+#include <renderengine/Image.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Transform.h>
 
@@ -105,7 +105,7 @@
     virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
 
     // set-up
-    virtual void checkErrors() const;
+    virtual void checkErrors() const = 0;
     virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                           ui::Transform::orientation_flags rotation) = 0;
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
@@ -188,33 +188,6 @@
     bool useNativeFenceSync() const override;
     bool useWaitSync() const override;
 
-    // synchronization
-
-    // flush submits RenderEngine command stream for execution and returns a
-    // native fence fd that is signaled when the execution has completed.  It
-    // returns -1 on errors.
-    base::unique_fd flush() override;
-    // finish waits until RenderEngine command stream has been executed.  It
-    // returns false on errors.
-    bool finish() override;
-    // waitFence inserts a wait on an external fence fd to RenderEngine
-    // command stream.  It returns false on errors.
-    bool waitFence(base::unique_fd fenceFd) override;
-
-    // helpers
-    void clearWithColor(float red, float green, float blue, float alpha) override;
-    void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
-                             float blue, float alpha) override;
-
-    // common to all GL versions
-    void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
-    void disableScissor() override;
-    void genTextures(size_t count, uint32_t* names) override;
-    void deleteTextures(size_t count, uint32_t const* names) override;
-    void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) override;
-
-    void checkErrors() const override;
-
     void setupColorTransform(const mat4& /* colorTransform */) override {}
 
     // internal to RenderEngine
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index a7c08cf..bb85f4c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -29,8 +29,15 @@
 
 namespace android {
 
+#define RETURN_VALUE_IF_INVALID(value) \
+    if (handle == nullptr || mConnections.count(handle->id) == 0) return value
+#define RETURN_IF_INVALID() \
+    if (handle == nullptr || mConnections.count(handle->id) == 0) return
+
 std::atomic<int64_t> Scheduler::sNextId = 0;
 
+Scheduler::~Scheduler() = default;
+
 sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
         const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
         impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
@@ -38,11 +45,9 @@
     const int64_t id = sNextId++;
     ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
 
-    std::unique_ptr<VSyncSource> eventThreadSource =
-            std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
     std::unique_ptr<EventThread> eventThread =
-            std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
-                                                interceptCallback, connectionName);
+            makeEventThread(connectionName, dispSync, phaseOffsetNs, resyncCallback,
+                            interceptCallback);
     auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
                                                    eventThread->createEventConnection(),
                                                    std::move(eventThread));
@@ -50,56 +55,55 @@
     return mConnections[id]->handle;
 }
 
+std::unique_ptr<EventThread> Scheduler::makeEventThread(
+        const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+        impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
+    std::unique_ptr<VSyncSource> eventThreadSource =
+            std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+    return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
+                                               interceptCallback, connectionName);
+}
+
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
         const sp<Scheduler::ConnectionHandle>& handle) {
-    if (mConnections.count(handle->id) != 0) {
-        return mConnections[handle->id]->thread->createEventConnection();
-    }
-    return nullptr;
+    RETURN_VALUE_IF_INVALID(nullptr);
+    return mConnections[handle->id]->thread->createEventConnection();
 }
 
 EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
-    if (mConnections.count(handle->id) != 0) {
-        return mConnections[handle->id]->thread.get();
-    }
-    return nullptr;
+    RETURN_VALUE_IF_INVALID(nullptr);
+    return mConnections[handle->id]->thread.get();
 }
 
 sp<BnDisplayEventConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
-    if (mConnections.find(handle->id) != mConnections.end()) {
-        return mConnections[handle->id]->eventConnection;
-    }
-    return nullptr;
+    RETURN_VALUE_IF_INVALID(nullptr);
+    return mConnections[handle->id]->eventConnection;
 }
 
 void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
                                 EventThread::DisplayType displayType, bool connected) {
-    if (mConnections.find(handle->id) != mConnections.end()) {
-        mConnections[handle->id]->thread->onHotplugReceived(displayType, connected);
-    }
+    RETURN_IF_INVALID();
+    mConnections[handle->id]->thread->onHotplugReceived(displayType, connected);
 }
 
 void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
-    if (mConnections.find(handle->id) != mConnections.end()) {
-        mConnections[handle->id]->thread->onScreenAcquired();
-    }
+    RETURN_IF_INVALID();
+    mConnections[handle->id]->thread->onScreenAcquired();
 }
 
 void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
-    if (mConnections.find(handle->id) != mConnections.end()) {
-        mConnections[handle->id]->thread->onScreenReleased();
-    }
+    RETURN_IF_INVALID();
+    mConnections[handle->id]->thread->onScreenReleased();
 }
 
 void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, String8& result) const {
-    if (mConnections.find(handle->id) != mConnections.end()) {
-        mConnections.at(handle->id)->thread->dump(result);
-    }
+    RETURN_IF_INVALID();
+    mConnections.at(handle->id)->thread->dump(result);
 }
 
 void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
-    if (mConnections.find(handle->id) != mConnections.end()) {
-        mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
-    }
+    RETURN_IF_INVALID();
+    mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
 }
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index caccd6f..8efbff4 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -52,7 +52,7 @@
     };
 
     Scheduler() = default;
-    ~Scheduler() = default;
+    virtual ~Scheduler();
 
     /** Creates an EventThread connection. */
     sp<ConnectionHandle> createConnection(
@@ -77,6 +77,12 @@
     // Offers ability to modify phase offset in the event thread.
     void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
 
+protected:
+    virtual std::unique_ptr<EventThread> makeEventThread(
+            const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+            impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+            impl::EventThread::InterceptVSyncsCallback interceptCallback);
+
 private:
     static std::atomic<int64_t> sNextId;
     std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 8f1f5e5..f1f0fbf 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -22,6 +22,7 @@
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
         "EventThreadTest.cpp",
+        "SchedulerTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockDisplaySurface.cpp",
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
new file mode 100644
index 0000000..c809e82
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -0,0 +1,186 @@
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include "AsyncCallRecorder.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/Scheduler.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventThread.h"
+
+using testing::_;
+using testing::Return;
+
+namespace android {
+
+class SchedulerTest : public testing::Test {
+protected:
+    class MockEventThreadConnection : public BnDisplayEventConnection {
+    public:
+        MockEventThreadConnection() = default;
+        ~MockEventThreadConnection() = default;
+
+        MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
+        MOCK_METHOD1(setVsyncRate, status_t(uint32_t count));
+        MOCK_METHOD0(requestNextVsync, void());
+    };
+
+    /**
+     * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
+     * the same.
+     */
+    class MockScheduler : public android::Scheduler {
+    public:
+        MockScheduler(std::unique_ptr<EventThread> eventThread)
+              : mEventThread(std::move(eventThread)) {}
+
+        std::unique_ptr<EventThread> makeEventThread(
+                const char* /* connectionName */, DispSync* /* dispSync */,
+                nsecs_t /* phaseOffsetNs */,
+                impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */,
+                impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
+            return std::move(mEventThread);
+        }
+
+        MockScheduler() = default;
+        ~MockScheduler() override = default;
+
+        std::unique_ptr<EventThread> mEventThread;
+    };
+
+    SchedulerTest();
+    ~SchedulerTest() override;
+
+    sp<Scheduler::ConnectionHandle> mConnectionHandle;
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+    mock::EventThread* mEventThread;
+    std::unique_ptr<MockScheduler> mScheduler;
+    sp<MockEventThreadConnection> mEventThreadConnection;
+
+    AsyncCallRecorder<void (*)()> mResyncCallRecorder;
+    AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
+};
+
+SchedulerTest::SchedulerTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+    std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
+    mEventThread = eventThread.get();
+    mScheduler = std::make_unique<MockScheduler>(std::move(eventThread));
+    mEventThreadConnection = new MockEventThreadConnection();
+
+    // createConnection call to scheduler makes a createEventConnection call to EventThread. Make
+    // sure that call gets executed and returns an EventThread::Connection object.
+    EXPECT_CALL(*mEventThread, createEventConnection())
+            .WillRepeatedly(Return(mEventThreadConnection));
+
+    mConnectionHandle = mScheduler->createConnection("appConnection", mPrimaryDispSync, 16,
+                                                     mResyncCallRecorder.getInvocable(),
+                                                     mInterceptVSyncCallRecorder.getInvocable());
+}
+
+SchedulerTest::~SchedulerTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(SchedulerTest, canCreateAndDestroyTest) {
+    EXPECT_FALSE(mResyncCallRecorder.waitForCall().has_value());
+    EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall().has_value());
+    EXPECT_EQ(0, mConnectionHandle->id);
+}
+
+TEST_F(SchedulerTest, testNullPtr) {
+    // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
+    // exceptions, just gracefully continues.
+    sp<IDisplayEventConnection> returnedValue;
+    ASSERT_NO_FATAL_FAILURE(returnedValue = mScheduler->createDisplayEventConnection(nullptr));
+    EXPECT_TRUE(returnedValue == nullptr);
+    EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
+    EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
+    ASSERT_NO_FATAL_FAILURE(
+            mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false));
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
+    String8 testString;
+    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString));
+    EXPECT_TRUE(testString == "");
+    ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10));
+}
+
+TEST_F(SchedulerTest, invalidConnectionHandle) {
+    // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any
+    // exceptions, just gracefully continues.
+    sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
+
+    sp<IDisplayEventConnection> returnedValue;
+    ASSERT_NO_FATAL_FAILURE(returnedValue =
+                                    mScheduler->createDisplayEventConnection(connectionHandle));
+    EXPECT_TRUE(returnedValue == nullptr);
+    EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
+    EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
+
+    // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
+    EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle,
+                                                        EventThread::DisplayType::Primary, false));
+
+    EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
+
+    EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle));
+
+    String8 testString;
+    EXPECT_CALL(*mEventThread, dump(_)).Times(0);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString));
+    EXPECT_TRUE(testString == "");
+
+    EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10));
+}
+
+TEST_F(SchedulerTest, validConnectionHandle) {
+    sp<IDisplayEventConnection> returnedValue;
+    ASSERT_NO_FATAL_FAILURE(returnedValue =
+                                    mScheduler->createDisplayEventConnection(mConnectionHandle));
+    EXPECT_TRUE(returnedValue != nullptr);
+    ASSERT_EQ(returnedValue, mEventThreadConnection);
+
+    EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
+    EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
+
+    EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false))
+            .Times(1);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle,
+                                                        EventThread::DisplayType::Primary, false));
+
+    EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
+
+    EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle));
+
+    String8 testString("dump");
+    EXPECT_CALL(*mEventThread, dump(testString)).Times(1);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString));
+    EXPECT_TRUE(testString != "");
+
+    EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file