Merge "Add Flags<F>::Iterator."
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
index 97c057f..eb9008b 100644
--- a/cmds/idlcli/vibrator/CommandCompose.cpp
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -37,7 +37,7 @@
                 {"-b", {"Block for duration of vibration."}},
                 {"<delay>", {"In milliseconds"}},
                 {"<primitive>", {"Primitive ID."}},
-                {"<scale>", {"0.0 (exclusive) - 1.0 (inclusive)."}},
+                {"<scale>", {"0.0 (inclusive) - 1.0 (inclusive)."}},
                 {"...", {"May repeat multiple times."}},
         };
         return details;
@@ -72,7 +72,7 @@
                 return USAGE;
             }
             if (auto scale = args.pop<decltype(effect.scale)>();
-                scale && *scale > 0.0 && scale <= 1.0) {
+                scale && *scale >= 0.0 && scale <= 1.0) {
                 effect.scale = *scale;
                 std::cout << "Scale: " << effect.scale << std::endl;
             } else {
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index dc37bbd..e65b224 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -321,6 +321,46 @@
     OMX_VIDEO_DolbyVisionLevelmax     = 0x7FFFFFFF
 } OMX_VIDEO_DOLBYVISIONLEVELTYPE;
 
+/** AV1 Profile enum type */
+typedef enum OMX_VIDEO_AV1PROFILETYPE {
+    OMX_VIDEO_AV1ProfileMain8           = 0x00000001,
+    OMX_VIDEO_AV1ProfileMain10          = 0x00000002,
+    OMX_VIDEO_AV1ProfileMain10HDR10     = 0x00001000,
+    OMX_VIDEO_AV1ProfileMain10HDR10Plus = 0x00002000,
+    OMX_VIDEO_AV1ProfileUnknown         = 0x6EFFFFFF,
+    OMX_VIDEO_AV1ProfileMax             = 0x7FFFFFFF
+} OMX_VIDEO_AV1PROFILETYPE;
+
+/** AV1 Level enum type */
+typedef enum OMX_VIDEO_AV1LEVELTYPE {
+    OMX_VIDEO_AV1Level2         = 0x1,
+    OMX_VIDEO_AV1Level21        = 0x2,
+    OMX_VIDEO_AV1Level22        = 0x4,
+    OMX_VIDEO_AV1Level23        = 0x8,
+    OMX_VIDEO_AV1Level3         = 0x10,
+    OMX_VIDEO_AV1Level31        = 0x20,
+    OMX_VIDEO_AV1Level32        = 0x40,
+    OMX_VIDEO_AV1Level33        = 0x80,
+    OMX_VIDEO_AV1Level4         = 0x100,
+    OMX_VIDEO_AV1Level41        = 0x200,
+    OMX_VIDEO_AV1Level42        = 0x400,
+    OMX_VIDEO_AV1Level43        = 0x800,
+    OMX_VIDEO_AV1Level5         = 0x1000,
+    OMX_VIDEO_AV1Level51        = 0x2000,
+    OMX_VIDEO_AV1Level52        = 0x4000,
+    OMX_VIDEO_AV1Level53        = 0x8000,
+    OMX_VIDEO_AV1Level6         = 0x10000,
+    OMX_VIDEO_AV1Level61        = 0x20000,
+    OMX_VIDEO_AV1Level62        = 0x40000,
+    OMX_VIDEO_AV1Level63        = 0x80000,
+    OMX_VIDEO_AV1Level7         = 0x100000,
+    OMX_VIDEO_AV1Level71        = 0x200000,
+    OMX_VIDEO_AV1Level72        = 0x400000,
+    OMX_VIDEO_AV1Level73        = 0x800000,
+    OMX_VIDEO_AV1LevelUnknown   = 0x6EFFFFFF,
+    OMX_VIDEO_AV1LevelMax       = 0x7FFFFFFF
+} OMX_VIDEO_AV1LEVELTYPE;
+
 /**
  * Structure for configuring video compression intra refresh period
  *
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index bdf11e4..e9f559c 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -130,6 +130,13 @@
  * This api is thread-safe. Any thread is allowed to register a new refresh
  * rate callback for the choreographer instance.
  *
+ * Note that in API level 30, this api is not guaranteed to be atomic with
+ * DisplayManager. That is, calling Display#getRefreshRate very soon after
+ * a refresh rate callback is invoked may return a stale refresh rate. If any
+ * Display properties would be required by this callback, then it is recommended
+ * to listen directly to DisplayManager.DisplayListener#onDisplayChanged events
+ * instead.
+ *
  * Available since API level 30.
  */
 void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
diff --git a/include/input/Input.h b/include/input/Input.h
index 40d655f..9525bcb 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -87,6 +87,13 @@
 constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
         AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
 
+/**
+ * This flag indicates that the point up event has been canceled.
+ * Typically this is used for palm event when the user has accidental touches.
+ * TODO: Adjust flag to public api
+ */
+constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20;
+
 enum {
     /* Used when a motion event is not associated with any display.
      * Typically used for non-pointer events. */
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 09cebef..24f8e77 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -183,18 +183,6 @@
     }
 };
 
-struct InputChannelInfo : public Parcelable {
-    std::string mName;
-    android::base::unique_fd mFd;
-    sp<IBinder> mToken;
-
-    InputChannelInfo() = default;
-    InputChannelInfo(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
-          : mName(name), mFd(std::move(fd)), mToken(token){};
-    status_t readFromParcel(const android::Parcel* parcel) override;
-    status_t writeToParcel(android::Parcel* parcel) const override;
-};
-
 /*
  * An input channel consists of a local unix domain socket used to send and receive
  * input messages across processes.  Each channel has a descriptive name for debugging purposes.
@@ -203,14 +191,15 @@
  *
  * The input channel is closed when all references to it are released.
  */
-class InputChannel : public RefBase {
+class InputChannel : public Parcelable {
 public:
-    InputChannel();
+    static std::unique_ptr<InputChannel> create(const std::string& name,
+                                                android::base::unique_fd fd, sp<IBinder> token);
+    InputChannel() = default;
+    InputChannel(const InputChannel& other)
+          : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){};
+    InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
     virtual ~InputChannel();
-
-    static sp<InputChannel> create(const std::string& name, android::base::unique_fd fd,
-                                   sp<IBinder> token);
-
     /**
      * Create a pair of input channels.
      * The two returned input channels are equivalent, and are labeled as "server" and "client"
@@ -219,12 +208,12 @@
      * Return OK on success.
      */
     static status_t openInputChannelPair(const std::string& name,
-            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
+                                         std::unique_ptr<InputChannel>& outServerChannel,
+                                         std::unique_ptr<InputChannel>& outClientChannel);
 
-    inline std::string getName() const { return mInfo.mName; }
-    inline int getFd() const { return mInfo.mFd.get(); }
-    inline sp<IBinder> getToken() const { return mInfo.mToken; }
-    inline InputChannelInfo& getInfo() { return mInfo; }
+    inline std::string getName() const { return mName; }
+    inline const android::base::unique_fd& getFd() const { return mFd; }
+    inline sp<IBinder> getToken() const { return mToken; }
 
     /* Send a message to the other endpoint.
      *
@@ -252,11 +241,10 @@
     status_t receiveMessage(InputMessage* msg);
 
     /* Return a new object that has a duplicate of this channel's fd. */
-    sp<InputChannel> dup() const;
+    std::unique_ptr<InputChannel> dup() const;
 
-    status_t readFromParcel(const android::Parcel* parcel);
-
-    status_t writeToParcel(android::Parcel* parcel) const;
+    status_t readFromParcel(const android::Parcel* parcel) override;
+    status_t writeToParcel(android::Parcel* parcel) const override;
 
     /**
      * The connection token is used to identify the input connection, i.e.
@@ -273,22 +261,23 @@
     sp<IBinder> getConnectionToken() const;
 
     bool operator==(const InputChannel& inputChannel) const {
-        struct stat lhsInfo, rhsInfo;
-        if (fstat(mInfo.mFd.get(), &lhsInfo) != 0) {
+        struct stat lhs, rhs;
+        if (fstat(mFd.get(), &lhs) != 0) {
             return false;
         }
-        if (fstat(inputChannel.getFd(), &rhsInfo) != 0) {
+        if (fstat(inputChannel.getFd(), &rhs) != 0) {
             return false;
         }
         // If file descriptors are pointing to same inode they are duplicated fds.
-        return inputChannel.getName() == getName() &&
-                inputChannel.getConnectionToken() == mInfo.mToken &&
-                lhsInfo.st_ino == rhsInfo.st_ino;
+        return inputChannel.getName() == getName() && inputChannel.getConnectionToken() == mToken &&
+                lhs.st_ino == rhs.st_ino;
     }
 
 private:
-    InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token);
-    InputChannelInfo mInfo;
+    std::string mName;
+    android::base::unique_fd mFd;
+
+    sp<IBinder> mToken;
 };
 
 /*
@@ -297,13 +286,13 @@
 class InputPublisher {
 public:
     /* Creates a publisher associated with an input channel. */
-    explicit InputPublisher(const sp<InputChannel>& channel);
+    explicit InputPublisher(const std::shared_ptr<InputChannel>& channel);
 
     /* Destroys the publisher and releases its input channel. */
     ~InputPublisher();
 
     /* Gets the underlying input channel. */
-    inline sp<InputChannel> getChannel() { return mChannel; }
+    inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
 
     /* Publishes a key event to the input channel.
      *
@@ -360,7 +349,7 @@
     status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
 
 private:
-    sp<InputChannel> mChannel;
+    std::shared_ptr<InputChannel> mChannel;
 };
 
 /*
@@ -369,13 +358,13 @@
 class InputConsumer {
 public:
     /* Creates a consumer associated with an input channel. */
-    explicit InputConsumer(const sp<InputChannel>& channel);
+    explicit InputConsumer(const std::shared_ptr<InputChannel>& channel);
 
     /* Destroys the consumer and releases its input channel. */
     ~InputConsumer();
 
     /* Gets the underlying input channel. */
-    inline sp<InputChannel> getChannel() { return mChannel; }
+    inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
 
     /* Consumes an input event from the input channel and copies its contents into
      * an InputEvent object created using the specified factory.
@@ -451,8 +440,7 @@
     // True if touch resampling is enabled.
     const bool mResampleTouch;
 
-    // The input channel.
-    sp<InputChannel> mChannel;
+    std::shared_ptr<InputChannel> mChannel;
 
     // The current input message.
     InputMessage mMsg;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 383d591..cca8ddd 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -68,11 +68,12 @@
 public:
     InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
         mSurfaceControl = sc;
-
-        InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
+        std::unique_ptr<InputChannel> clientChannel;
+        InputChannel::openInputChannelPair("testchannels", mServerChannel, clientChannel);
+        mClientChannel = std::move(clientChannel);
 
         mInputFlinger = getInputFlinger();
-        mInputFlinger->registerInputChannel(mServerChannel->getInfo());
+        mInputFlinger->registerInputChannel(*mServerChannel);
 
         populateInputInfo(width, height);
 
@@ -154,7 +155,7 @@
         EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
     }
 
-    ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel->getInfo()); }
+    ~InputSurface() { mInputFlinger->unregisterInputChannel(*mServerChannel); }
 
     void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
                     const sp<SurfaceControl>&)> transactionBody) {
@@ -211,7 +212,8 @@
     }
 public:
     sp<SurfaceControl> mSurfaceControl;
-    sp<InputChannel> mServerChannel, mClientChannel;
+    std::unique_ptr<InputChannel> mServerChannel;
+    std::shared_ptr<InputChannel> mClientChannel;
     sp<IInputFlinger> mInputFlinger;
 
     InputWindowInfo mInputInfo;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 60ad578..8dcc415 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -241,65 +241,42 @@
     }
 }
 
-// --- InputChannelInfo ---
-
-status_t InputChannelInfo::writeToParcel(android::Parcel* parcel) const {
-    if (parcel == nullptr) {
-        ALOGE("%s: Null parcel", __func__);
-        return BAD_VALUE;
-    }
-    status_t status = parcel->writeStrongBinder(mToken)
-            ?: parcel->writeUtf8AsUtf16(mName) ?: parcel->writeUniqueFileDescriptor(mFd);
-    return status;
-}
-
-status_t InputChannelInfo::readFromParcel(const android::Parcel* parcel) {
-    if (parcel == nullptr) {
-        ALOGE("%s: Null parcel", __func__);
-        return BAD_VALUE;
-    }
-    mToken = parcel->readStrongBinder();
-    status_t status = parcel->readUtf8FromUtf16(&mName) ?: parcel->readUniqueFileDescriptor(&mFd);
-    return status;
-}
-
 // --- InputChannel ---
 
-sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
-                                      sp<IBinder> token) {
+std::unique_ptr<InputChannel> InputChannel::create(const std::string& name,
+                                                   android::base::unique_fd fd, sp<IBinder> token) {
     const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
     if (result != 0) {
         LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
                          strerror(errno));
         return nullptr;
     }
-    return new InputChannel(name, std::move(fd), token);
+    // using 'new' to access a non-public constructor
+    return std::unique_ptr<InputChannel>(new InputChannel(name, std::move(fd), token));
 }
 
-InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
-      : mInfo(name, std::move(fd), token) {
+InputChannel::InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token)
+      : mName(std::move(name)), mFd(std::move(fd)), mToken(std::move(token)) {
     if (DEBUG_CHANNEL_LIFECYCLE) {
-        ALOGD("Input channel constructed: name='%s', fd=%d", mInfo.mName.c_str(), mInfo.mFd.get());
+        ALOGD("Input channel constructed: name='%s', fd=%d", getName().c_str(), getFd().get());
     }
 }
 
-InputChannel::InputChannel() {}
-
 InputChannel::~InputChannel() {
     if (DEBUG_CHANNEL_LIFECYCLE) {
-        ALOGD("Input channel destroyed: name='%s', fd=%d", getName().c_str(), getFd());
+        ALOGD("Input channel destroyed: name='%s', fd=%d", getName().c_str(), getFd().get());
     }
 }
 
 status_t InputChannel::openInputChannelPair(const std::string& name,
-        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
+                                            std::unique_ptr<InputChannel>& outServerChannel,
+                                            std::unique_ptr<InputChannel>& outClientChannel) {
     int sockets[2];
     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
         status_t result = -errno;
-        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
-                name.c_str(), errno);
-        outServerChannel.clear();
-        outClientChannel.clear();
+        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d", name.c_str(), errno);
+        outServerChannel.reset();
+        outClientChannel.reset();
         return result;
     }
 
@@ -399,10 +376,10 @@
     return OK;
 }
 
-sp<InputChannel> InputChannel::dup() const {
+std::unique_ptr<InputChannel> InputChannel::dup() const {
     android::base::unique_fd newFd(::dup(getFd()));
     if (!newFd.ok()) {
-        ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), getName().c_str(),
+        ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
               strerror(errno));
         const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
         // If this process is out of file descriptors, then throwing that might end up exploding
@@ -417,22 +394,30 @@
 }
 
 status_t InputChannel::writeToParcel(android::Parcel* parcel) const {
-    return mInfo.writeToParcel(parcel);
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+    return parcel->writeStrongBinder(mToken)
+            ?: parcel->writeUtf8AsUtf16(mName) ?: parcel->writeUniqueFileDescriptor(mFd);
 }
 
 status_t InputChannel::readFromParcel(const android::Parcel* parcel) {
-    return mInfo.readFromParcel(parcel);
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+    mToken = parcel->readStrongBinder();
+    return parcel->readUtf8FromUtf16(&mName) ?: parcel->readUniqueFileDescriptor(&mFd);
 }
 
 sp<IBinder> InputChannel::getConnectionToken() const {
-    return mInfo.mToken;
+    return mToken;
 }
 
 // --- InputPublisher ---
 
-InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
-        mChannel(channel) {
-}
+InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel) : mChannel(channel) {}
 
 InputPublisher::~InputPublisher() {
 }
@@ -596,10 +581,8 @@
 
 // --- InputConsumer ---
 
-InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
-        mResampleTouch(isTouchResamplingEnabled()),
-        mChannel(channel), mMsgDeferred(false) {
-}
+InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel)
+      : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) {}
 
 InputConsumer::~InputConsumer() {
 }
diff --git a/libs/input/android/InputChannelInfo.aidl b/libs/input/android/InputChannel.aidl
similarity index 91%
rename from libs/input/android/InputChannelInfo.aidl
rename to libs/input/android/InputChannel.aidl
index 2e83b96..c2d1112 100644
--- a/libs/input/android/InputChannelInfo.aidl
+++ b/libs/input/android/InputChannel.aidl
@@ -17,4 +17,4 @@
 
 package android;
 
-parcelable InputChannelInfo cpp_header "input/InputTransport.h";
+parcelable InputChannel cpp_header "input/InputTransport.h";
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 8b7c4fc..44bb66d 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.InputChannelInfo;
+import android.InputChannel;
 import android.InputWindowInfo;
 import android.os.ISetInputWindowsListener;
 
@@ -29,6 +29,6 @@
     // shouldn't be a concern.
     oneway void setInputWindows(in InputWindowInfo[] inputHandles,
             in @nullable ISetInputWindowsListener setInputWindowsListener);
-    void registerInputChannel(in InputChannelInfo info);
-    void unregisterInputChannel(in InputChannelInfo info);
+    void registerInputChannel(in InputChannel channel);
+    void unregisterInputChannel(in InputChannel channel);
 }
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index 4187ca9..0661261 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -33,9 +33,6 @@
 namespace android {
 
 class InputChannelTest : public testing::Test {
-protected:
-    virtual void SetUp() { }
-    virtual void TearDown() { }
 };
 
 
@@ -47,7 +44,7 @@
 
     android::base::unique_fd sendFd(pipe.sendFd);
 
-    sp<InputChannel> inputChannel =
+    std::unique_ptr<InputChannel> inputChannel =
             InputChannel::create("channel name", std::move(sendFd), new BBinder());
 
     EXPECT_NE(inputChannel, nullptr) << "channel should be successfully created";
@@ -62,14 +59,14 @@
 TEST_F(InputChannelTest, SetAndGetToken) {
     Pipe pipe;
     sp<IBinder> token = new BBinder();
-    sp<InputChannel> channel =
+    std::unique_ptr<InputChannel> channel =
             InputChannel::create("test channel", android::base::unique_fd(pipe.sendFd), token);
 
     EXPECT_EQ(token, channel->getConnectionToken());
 }
 
 TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
 
     status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
@@ -120,7 +117,7 @@
 }
 
 TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
 
     status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
@@ -134,7 +131,7 @@
 }
 
 TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
 
     status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
@@ -142,7 +139,7 @@
     ASSERT_EQ(OK, result)
             << "should have successfully opened a channel pair";
 
-    serverChannel.clear(); // close server channel
+    serverChannel.reset(); // close server channel
 
     InputMessage msg;
     EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
@@ -150,7 +147,7 @@
 }
 
 TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
 
     status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
@@ -158,7 +155,7 @@
     ASSERT_EQ(OK, result)
             << "should have successfully opened a channel pair";
 
-    serverChannel.clear(); // close server channel
+    serverChannel.reset(); // close server channel
 
     InputMessage msg;
     msg.header.type = InputMessage::Type::KEY;
@@ -167,7 +164,7 @@
 }
 
 TEST_F(InputChannelTest, SendAndReceive_MotionClassification) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
     status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
     ASSERT_EQ(OK, result)
@@ -199,7 +196,7 @@
 }
 
 TEST_F(InputChannelTest, InputChannelParcelAndUnparcel) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
 
     status_t result =
             InputChannel::openInputChannelPair("channel parceling", serverChannel, clientChannel);
@@ -218,14 +215,14 @@
 }
 
 TEST_F(InputChannelTest, DuplicateChannelAndAssertEqual) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
 
     status_t result =
             InputChannel::openInputChannelPair("channel dup", serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
 
-    sp<InputChannel> dupChan = serverChannel->dup();
+    std::unique_ptr<InputChannel> dupChan = serverChannel->dup();
 
     EXPECT_EQ(*serverChannel == *dupChan, true) << "inputchannel should be equal after duplication";
 }
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8e2eec8..5ddc858 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -30,33 +30,21 @@
 
 class InputPublisherAndConsumerTest : public testing::Test {
 protected:
-    sp<InputChannel> serverChannel, clientChannel;
-    InputPublisher* mPublisher;
-    InputConsumer* mConsumer;
+    std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
+    std::unique_ptr<InputPublisher> mPublisher;
+    std::unique_ptr<InputConsumer> mConsumer;
     PreallocatedInputEventFactory mEventFactory;
 
-    virtual void SetUp() {
+    void SetUp() override {
+        std::unique_ptr<InputChannel> serverChannel, clientChannel;
         status_t result = InputChannel::openInputChannelPair("channel name",
                 serverChannel, clientChannel);
         ASSERT_EQ(OK, result);
+        mServerChannel = std::move(serverChannel);
+        mClientChannel = std::move(clientChannel);
 
-        mPublisher = new InputPublisher(serverChannel);
-        mConsumer = new InputConsumer(clientChannel);
-    }
-
-    virtual void TearDown() {
-        if (mPublisher) {
-            delete mPublisher;
-            mPublisher = nullptr;
-        }
-
-        if (mConsumer) {
-            delete mConsumer;
-            mConsumer = nullptr;
-        }
-
-        serverChannel.clear();
-        clientChannel.clear();
+        mPublisher = std::make_unique<InputPublisher>(mServerChannel);
+        mConsumer = std::make_unique<InputConsumer>(mClientChannel);
     }
 
     void PublishAndConsumeKeyEvent();
@@ -65,8 +53,8 @@
 };
 
 TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
-    EXPECT_EQ(serverChannel.get(), mPublisher->getChannel().get());
-    EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
+    EXPECT_EQ(mServerChannel.get(), mPublisher->getChannel().get());
+    EXPECT_EQ(mClientChannel.get(), mConsumer->getChannel().get());
 }
 
 void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 5930f0a..d1a3e9a 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -100,6 +100,7 @@
         "InputListener.cpp",
         "InputReaderBase.cpp",
         "InputThread.cpp",
+        "VibrationElement.cpp"
     ],
 }
 
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index c5f60ad..088c6f1 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -119,7 +119,7 @@
 }
 
 // Used by tests only.
-binder::Status InputManager::registerInputChannel(const InputChannelInfo& info) {
+binder::Status InputManager::registerInputChannel(const InputChannel& channel) {
     IPCThreadState* ipc = IPCThreadState::self();
     const int uid = ipc->getCallingUid();
     if (uid != AID_SHELL && uid != AID_ROOT) {
@@ -127,15 +127,12 @@
                 "from non shell/root entity (PID: %d)", ipc->getCallingPid());
         return binder::Status::ok();
     }
-    android::base::unique_fd newFd(::dup(info.mFd));
-    sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
-    mDispatcher->registerInputChannel(channel);
+
+    mDispatcher->registerInputChannel(channel.dup());
     return binder::Status::ok();
 }
 
-binder::Status InputManager::unregisterInputChannel(const InputChannelInfo& info) {
-    android::base::unique_fd newFd(::dup(info.mFd));
-    sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
+binder::Status InputManager::unregisterInputChannel(const InputChannel& channel) {
     mDispatcher->unregisterInputChannel(channel);
     return binder::Status::ok();
 }
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 4993b54..0503e81 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -108,8 +108,8 @@
             const std::vector<InputWindowInfo>& handles,
             const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
 
-    binder::Status registerInputChannel(const InputChannelInfo& info) override;
-    binder::Status unregisterInputChannel(const InputChannelInfo& info) override;
+    binder::Status registerInputChannel(const InputChannel& channel) override;
+    binder::Status unregisterInputChannel(const InputChannel& channel) override;
 
 private:
     sp<InputReaderInterface> mReader;
diff --git a/services/inputflinger/VibrationElement.cpp b/services/inputflinger/VibrationElement.cpp
new file mode 100644
index 0000000..a69f5d0
--- /dev/null
+++ b/services/inputflinger/VibrationElement.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VibrationElement.h"
+
+#include <android-base/stringprintf.h>
+
+#include <algorithm>
+#include <cinttypes>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+// The sentinel to use the default amplitude
+static const int DEFAULT_AMPLITUDE = -1;
+
+// The vibration magnitude for the "DEFAULT_AMPLITUDE" magnitude constant.
+static const uint16_t DEFAULT_MAGNITUDE = 0xc000;
+
+void VibrationElement::dump(std::string& dump) const {
+    dump += StringPrintf("[duration=%lldms, channels=[", duration.count());
+
+    if (channels.size()) {
+        dump += std::to_string(channels[0]);
+        std::for_each(channels.begin() + 1, channels.end(), [&dump](int channel) {
+            dump += ", ";
+            dump += std::to_string(channel);
+        });
+    }
+    dump += "]]";
+}
+
+uint16_t VibrationElement::getChannel(int id) const {
+    if (id >= (int)channels.size()) {
+        return 0;
+    }
+
+    // android framework uses DEFAULT_AMPLITUDE to signal that the vibration
+    // should use some built-in default value, denoted here as DEFAULT_MAGNITUDE
+    if (channels[id] == DEFAULT_AMPLITUDE) {
+        return DEFAULT_MAGNITUDE;
+    }
+
+    // convert range [0,255] to [0,65535] (android framework to linux ff ranges)
+    return ((uint16_t)channels[id]) << 8;
+}
+
+bool VibrationElement::isOn() const {
+    return std::any_of(channels.begin(), channels.end(),
+                       [](uint16_t channel) { return channel != 0; });
+}
+
+} // namespace android
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index a15b7b2..1914a38 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -128,14 +128,17 @@
 protected:
     explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher, const std::string name)
           : mDispatcher(dispatcher) {
-        InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+        std::unique_ptr<InputChannel> serverChannel, clientChannel;
+        InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+        mServerChannel = std::move(serverChannel);
+        mClientChannel = std::move(clientChannel);
         mConsumer = std::make_unique<InputConsumer>(mClientChannel);
     }
 
     virtual ~FakeInputReceiver() {}
 
     sp<InputDispatcher> mDispatcher;
-    sp<InputChannel> mServerChannel, mClientChannel;
+    std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
     std::unique_ptr<InputConsumer> mConsumer;
     PreallocatedInputEventFactory mEventFactory;
 };
diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp
index f5ea563..cee9c39 100644
--- a/services/inputflinger/dispatcher/Connection.cpp
+++ b/services/inputflinger/dispatcher/Connection.cpp
@@ -20,7 +20,7 @@
 
 namespace android::inputdispatcher {
 
-Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor,
+Connection::Connection(const std::shared_ptr<InputChannel>& inputChannel, bool monitor,
                        const IdGenerator& idGenerator)
       : status(STATUS_NORMAL),
         inputChannel(inputChannel),
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
index 3b33f29..c4262ad 100644
--- a/services/inputflinger/dispatcher/Connection.h
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -42,7 +42,7 @@
     };
 
     Status status;
-    sp<InputChannel> inputChannel; // never null
+    std::shared_ptr<InputChannel> inputChannel; // never null
     bool monitor;
     InputPublisher inputPublisher;
     InputState inputState;
@@ -59,7 +59,8 @@
     // yet received a "finished" response from the application.
     std::deque<DispatchEntry*> waitQueue;
 
-    Connection(const sp<InputChannel>& inputChannel, bool monitor, const IdGenerator& idGenerator);
+    Connection(const std::shared_ptr<InputChannel>& inputChannel, bool monitor,
+               const IdGenerator& idGenerator);
 
     inline const std::string getInputChannelName() const { return inputChannel->getName(); }
 
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 6b7697d..4147e41 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -262,7 +262,7 @@
     int32_t userActivityEventType;
     uint32_t seq;
     bool handled;
-    sp<InputChannel> inputChannel;
+    std::shared_ptr<InputChannel> inputChannel;
     sp<IBinder> oldToken;
     sp<IBinder> newToken;
 };
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 3bdbcce..da09898 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -433,7 +433,7 @@
 
     while (!mConnectionsByFd.empty()) {
         sp<Connection> connection = mConnectionsByFd.begin()->second;
-        unregisterInputChannel(connection->inputChannel);
+        unregisterInputChannel(*connection->inputChannel);
     }
 }
 
@@ -1105,7 +1105,7 @@
 }
 
 void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) {
-    sp<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
+    std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
     if (channel == nullptr) {
         return; // Window has gone away
     }
@@ -2029,7 +2029,8 @@
 
     if (it == inputTargets.end()) {
         InputTarget inputTarget;
-        sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
+        std::shared_ptr<InputChannel> inputChannel =
+                getInputChannelLocked(windowHandle->getToken());
         if (inputChannel == nullptr) {
             ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
             return;
@@ -2844,7 +2845,7 @@
         }
 
         // Unregister the channel.
-        d->unregisterInputChannelLocked(connection->inputChannel, notify);
+        d->unregisterInputChannelLocked(*connection->inputChannel, notify);
         return 0; // remove the callback
     }             // release lock
 }
@@ -2874,7 +2875,7 @@
 }
 
 void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
-        const sp<InputChannel>& channel, const CancelationOptions& options) {
+        const std::shared_ptr<InputChannel>& channel, const CancelationOptions& options) {
     sp<Connection> connection = getConnectionLocked(channel->getConnectionToken());
     if (connection == nullptr) {
         return;
@@ -3690,7 +3691,8 @@
     return false;
 }
 
-sp<InputChannel> InputDispatcher::getInputChannelLocked(const sp<IBinder>& token) const {
+std::shared_ptr<InputChannel> InputDispatcher::getInputChannelLocked(
+        const sp<IBinder>& token) const {
     size_t count = mInputChannelsByToken.count(token);
     if (count == 0) {
         return nullptr;
@@ -3815,7 +3817,7 @@
                 ALOGD("Focus left window: %s in display %" PRId32,
                       oldFocusedWindowHandle->getName().c_str(), displayId);
             }
-            sp<InputChannel> focusedInputChannel =
+            std::shared_ptr<InputChannel> focusedInputChannel =
                     getInputChannelLocked(oldFocusedWindowHandle->getToken());
             if (focusedInputChannel != nullptr) {
                 CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
@@ -3850,7 +3852,7 @@
                     ALOGD("Touched window was removed: %s in display %" PRId32,
                           touchedWindow.windowHandle->getName().c_str(), displayId);
                 }
-                sp<InputChannel> touchedInputChannel =
+                std::shared_ptr<InputChannel> touchedInputChannel =
                         getInputChannelLocked(touchedWindow.windowHandle->getToken());
                 if (touchedInputChannel != nullptr) {
                     CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -3929,7 +3931,7 @@
             sp<InputWindowHandle> oldFocusedWindowHandle =
                     getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
             if (oldFocusedWindowHandle != nullptr) {
-                sp<InputChannel> inputChannel =
+                std::shared_ptr<InputChannel> inputChannel =
                         getInputChannelLocked(oldFocusedWindowHandle->getToken());
                 if (inputChannel != nullptr) {
                     CancelationOptions
@@ -4376,13 +4378,13 @@
     const size_t numMonitors = monitors.size();
     for (size_t i = 0; i < numMonitors; i++) {
         const Monitor& monitor = monitors[i];
-        const sp<InputChannel>& channel = monitor.inputChannel;
+        const std::shared_ptr<InputChannel>& channel = monitor.inputChannel;
         dump += StringPrintf(INDENT2 "%zu: '%s', ", i, channel->getName().c_str());
         dump += "\n";
     }
 }
 
-status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
+status_t InputDispatcher::registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) {
 #if DEBUG_REGISTRATION
     ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
 #endif
@@ -4410,7 +4412,7 @@
     return OK;
 }
 
-status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChannel,
+status_t InputDispatcher::registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
                                                int32_t displayId, bool isGestureMonitor) {
     { // acquire lock
         std::scoped_lock _l(mLock);
@@ -4442,9 +4444,9 @@
     return OK;
 }
 
-status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
+status_t InputDispatcher::unregisterInputChannel(const InputChannel& inputChannel) {
 #if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().c_str());
+    ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel.getName().c_str());
 #endif
 
     { // acquire lock
@@ -4462,23 +4464,23 @@
     return OK;
 }
 
-status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
+status_t InputDispatcher::unregisterInputChannelLocked(const InputChannel& inputChannel,
                                                        bool notify) {
-    sp<Connection> connection = getConnectionLocked(inputChannel->getConnectionToken());
+    sp<Connection> connection = getConnectionLocked(inputChannel.getConnectionToken());
     if (connection == nullptr) {
         ALOGW("Attempted to unregister already unregistered input channel '%s'",
-              inputChannel->getName().c_str());
+              inputChannel.getName().c_str());
         return BAD_VALUE;
     }
 
     removeConnectionLocked(connection);
-    mInputChannelsByToken.erase(inputChannel->getConnectionToken());
+    mInputChannelsByToken.erase(inputChannel.getConnectionToken());
 
     if (connection->monitor) {
         removeMonitorChannelLocked(inputChannel);
     }
 
-    mLooper->removeFd(inputChannel->getFd());
+    mLooper->removeFd(inputChannel.getFd());
 
     nsecs_t currentTime = now();
     abortBrokenDispatchCycleLocked(currentTime, connection, notify);
@@ -4487,19 +4489,19 @@
     return OK;
 }
 
-void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
+void InputDispatcher::removeMonitorChannelLocked(const InputChannel& inputChannel) {
     removeMonitorChannelLocked(inputChannel, mGlobalMonitorsByDisplay);
     removeMonitorChannelLocked(inputChannel, mGestureMonitorsByDisplay);
 }
 
 void InputDispatcher::removeMonitorChannelLocked(
-        const sp<InputChannel>& inputChannel,
+        const InputChannel& inputChannel,
         std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) {
     for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end();) {
         std::vector<Monitor>& monitors = it->second;
         const size_t numMonitors = monitors.size();
         for (size_t i = 0; i < numMonitors; i++) {
-            if (monitors[i].inputChannel == inputChannel) {
+            if (*monitors[i].inputChannel == inputChannel) {
                 monitors.erase(monitors.begin() + i);
                 break;
             }
@@ -4550,7 +4552,8 @@
         options.deviceId = deviceId;
         options.displayId = displayId;
         for (const TouchedWindow& window : state.windows) {
-            sp<InputChannel> channel = getInputChannelLocked(window.windowHandle->getToken());
+            std::shared_ptr<InputChannel> channel =
+                    getInputChannelLocked(window.windowHandle->getToken());
             if (channel != nullptr) {
                 synthesizeCancelationEventsForInputChannelLocked(channel, options);
             }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 824bbf5..ba7ace0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -124,10 +124,11 @@
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken,
                                     const sp<IBinder>& toToken) override;
 
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) override;
-    virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId,
-                                          bool isGestureMonitor) override;
-    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override;
+    virtual status_t registerInputChannel(
+            const std::shared_ptr<InputChannel>& inputChannel) override;
+    virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
+                                          int32_t displayId, bool isGestureMonitor) override;
+    virtual status_t unregisterInputChannel(const InputChannel& inputChannel) override;
     virtual status_t pilferPointers(const sp<IBinder>& token) override;
 
 private:
@@ -210,8 +211,8 @@
             return std::hash<IBinder*>{}(b.get());
         }
     };
-    std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken
-            GUARDED_BY(mLock);
+    std::unordered_map<sp<IBinder>, std::shared_ptr<InputChannel>, IBinderHash>
+            mInputChannelsByToken GUARDED_BY(mLock);
 
     // Finds the display ID of the gesture monitor identified by the provided token.
     std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token)
@@ -301,7 +302,8 @@
             REQUIRES(mLock);
     sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
             REQUIRES(mLock);
-    sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
+    std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const
+            REQUIRES(mLock);
     bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
 
     /*
@@ -459,8 +461,8 @@
     void synthesizeCancelationEventsForMonitorsLocked(
             const CancelationOptions& options,
             std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
-    void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
-                                                          const CancelationOptions& options)
+    void synthesizeCancelationEventsForInputChannelLocked(
+            const std::shared_ptr<InputChannel>& channel, const CancelationOptions& options)
             REQUIRES(mLock);
     void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
                                                         const CancelationOptions& options)
@@ -481,11 +483,11 @@
     void logDispatchStateLocked() REQUIRES(mLock);
 
     // Registration.
-    void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+    void removeMonitorChannelLocked(const InputChannel& inputChannel) REQUIRES(mLock);
     void removeMonitorChannelLocked(
-            const sp<InputChannel>& inputChannel,
+            const InputChannel& inputChannel,
             std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
-    status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify)
+    status_t unregisterInputChannelLocked(const InputChannel& inputChannel, bool notify)
             REQUIRES(mLock);
 
     // Interesting events that we might like to log or tell the framework about.
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 499a75f..eeb6ee8 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -106,7 +106,7 @@
     };
 
     // The input channel to be targeted.
-    sp<InputChannel> inputChannel;
+    std::shared_ptr<InputChannel> inputChannel;
 
     // Flags for the input target.
     int32_t flags = 0;
diff --git a/services/inputflinger/dispatcher/Monitor.cpp b/services/inputflinger/dispatcher/Monitor.cpp
index 289b084..b347674 100644
--- a/services/inputflinger/dispatcher/Monitor.cpp
+++ b/services/inputflinger/dispatcher/Monitor.cpp
@@ -19,7 +19,7 @@
 namespace android::inputdispatcher {
 
 // --- Monitor ---
-Monitor::Monitor(const sp<InputChannel>& inputChannel) : inputChannel(inputChannel) {}
+Monitor::Monitor(const std::shared_ptr<InputChannel>& inputChannel) : inputChannel(inputChannel) {}
 
 // --- TouchedMonitor ---
 TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset)
diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h
index b67c9eb..fc0b020 100644
--- a/services/inputflinger/dispatcher/Monitor.h
+++ b/services/inputflinger/dispatcher/Monitor.h
@@ -22,9 +22,9 @@
 namespace android::inputdispatcher {
 
 struct Monitor {
-    sp<InputChannel> inputChannel; // never null
+    std::shared_ptr<InputChannel> inputChannel; // never null
 
-    explicit Monitor(const sp<InputChannel>& inputChannel);
+    explicit Monitor(const std::shared_ptr<InputChannel>& inputChannel);
 };
 
 // For tracking the offsets we need to apply when adding gesture monitor targets.
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index f25131c..272b0a6 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -152,7 +152,7 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0;
+    virtual status_t registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) = 0;
 
     /* Registers input channels to be used to monitor input events.
      *
@@ -162,14 +162,14 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId,
-                                          bool gestureMonitor) = 0;
+    virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
+                                          int32_t displayId, bool gestureMonitor) = 0;
 
     /* Unregister input channels that will no longer receive input events.
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
+    virtual status_t unregisterInputChannel(const InputChannel& inputChannel) = 0;
 
     /* Allows an input monitor steal the current pointer stream away from normal input windows.
      *
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 9364a2a..cd655e0 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -48,8 +48,8 @@
                                    const sp<ISetInputWindowsListener>&) {
         return binder::Status::ok();
     }
-    binder::Status registerInputChannel(const InputChannelInfo&) { return binder::Status::ok(); }
-    binder::Status unregisterInputChannel(const InputChannelInfo&) { return binder::Status::ok(); }
+    binder::Status registerInputChannel(const InputChannel&) { return binder::Status::ok(); }
+    binder::Status unregisterInputChannel(const InputChannel&) { return binder::Status::ok(); }
 
 private:
     virtual ~InputFlinger();
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 0fa8787..5a832e7 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -17,23 +17,24 @@
 #ifndef _UI_INPUT_READER_BASE_H
 #define _UI_INPUT_READER_BASE_H
 
-#include "PointerControllerInterface.h"
-
 #include <input/DisplayViewport.h>
 #include <input/Input.h>
 #include <input/InputDevice.h>
 #include <input/VelocityControl.h>
 #include <input/VelocityTracker.h>
+#include <stddef.h>
+#include <unistd.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
-#include <stddef.h>
-#include <unistd.h>
 #include <optional>
 #include <set>
 #include <unordered_map>
 #include <vector>
 
+#include "PointerControllerInterface.h"
+#include "VibrationElement.h"
+
 // Maximum supported size of a vibration pattern.
 // Must be at least 2.
 #define MAX_VIBRATE_PATTERN_SIZE 100
@@ -41,6 +42,7 @@
 // Maximum allowable delay value in a vibration pattern before
 // which the delay will be truncated.
 #define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL)
+#define MAX_VIBRATE_PATTERN_DELAY_MSECS (1000000 * 1000LL)
 
 namespace android {
 
@@ -104,8 +106,8 @@
     virtual void requestRefreshConfiguration(uint32_t changes) = 0;
 
     /* Controls the vibrator of a particular input device. */
-    virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
-            ssize_t repeat, int32_t token) = 0;
+    virtual void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
+                         ssize_t repeat, int32_t token) = 0;
     virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
 
     /* Return true if the device can send input events to the specified display. */
diff --git a/services/inputflinger/include/VibrationElement.h b/services/inputflinger/include/VibrationElement.h
new file mode 100644
index 0000000..8a134ee
--- /dev/null
+++ b/services/inputflinger/include/VibrationElement.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _VIBRATION_ELEMENT_H
+#define _VIBRATION_ELEMENT_H
+
+#include <chrono>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace android {
+
+/*
+ * Describes a rumble effect
+ */
+struct VibrationElement {
+    std::chrono::milliseconds duration;
+    std::vector<int> channels;
+
+    void dump(std::string& dump) const;
+    uint16_t getChannel(int id) const;
+    bool isOn() const;
+};
+
+} // namespace android
+
+#endif // _VIBRATION_ELEMENT_H
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 5e590d0..cef2b4c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -43,22 +43,11 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
-#include <utils/threads.h>
 
 #include <filesystem>
 
 #include "EventHub.h"
 
-/* this macro is used to tell if "bit" is set in "array"
- * it selects a byte from the array, and does a boolean AND
- * operation with a byte that only has the relevant bit set.
- * eg. to check for the 12th bit, we do (array[1] & 1<<4)
- */
-#define test_bit(bit, array) ((array)[(bit) / 8] & (1 << ((bit) % 8)))
-
-/* this macro computes the number of bytes needed to represent a bit array of the specified size */
-#define sizeof_bit_array(bits) (((bits) + 7) / 8)
-
 #define INDENT "  "
 #define INDENT2 "    "
 #define INDENT3 "      "
@@ -193,15 +182,7 @@
         ffEffectId(-1),
         controllerNumber(0),
         enabled(true),
-        isVirtual(fd < 0) {
-    memset(keyBitmask, 0, sizeof(keyBitmask));
-    memset(absBitmask, 0, sizeof(absBitmask));
-    memset(relBitmask, 0, sizeof(relBitmask));
-    memset(swBitmask, 0, sizeof(swBitmask));
-    memset(ledBitmask, 0, sizeof(ledBitmask));
-    memset(ffBitmask, 0, sizeof(ffBitmask));
-    memset(propBitmask, 0, sizeof(propBitmask));
-}
+        isVirtual(fd < 0) {}
 
 EventHub::Device::~Device() {
     close();
@@ -391,7 +372,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
+        if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
             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,
@@ -418,9 +399,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device) {
-            return test_bit(axis, device->relBitmask);
-        }
+        return device != nullptr ? device->relBitmask.test(axis) : false;
     }
     return false;
 }
@@ -430,9 +409,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device) {
-            return test_bit(property, device->propBitmask);
-        }
+        return device != nullptr ? device->propBitmask.test(property) : false;
     }
     return false;
 }
@@ -442,11 +419,9 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && device->hasValidFd() && test_bit(scanCode, device->keyBitmask)) {
-            uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
-            memset(keyState, 0, sizeof(keyState));
-            if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
-                return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
+        if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) {
+            if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
+                return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
             }
         }
     }
@@ -457,16 +432,14 @@
     AutoMutex _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
-    if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
+    if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
         std::vector<int32_t> scanCodes;
         device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
         if (scanCodes.size() != 0) {
-            uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
-            memset(keyState, 0, sizeof(keyState));
-            if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
+            if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
                 for (size_t i = 0; i < scanCodes.size(); i++) {
                     int32_t sc = scanCodes[i];
-                    if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) {
+                    if (sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc)) {
                         return AKEY_STATE_DOWN;
                     }
                 }
@@ -482,11 +455,9 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && device->hasValidFd() && test_bit(sw, device->swBitmask)) {
-            uint8_t swState[sizeof_bit_array(SW_MAX + 1)];
-            memset(swState, 0, sizeof(swState));
-            if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) {
-                return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
+        if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) {
+            if (device->readDeviceBitMask(EVIOCGSW(0), device->swState) >= 0) {
+                return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
             }
         }
     }
@@ -500,7 +471,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
+        if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
             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,
@@ -520,7 +491,7 @@
     AutoMutex _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
-    if (device && device->keyMap.haveKeyLayout()) {
+    if (device != nullptr && device->keyMap.haveKeyLayout()) {
         std::vector<int32_t> scanCodes;
         for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
             scanCodes.clear();
@@ -531,7 +502,7 @@
                 // check the possible scan codes identified by the layout map against the
                 // map of codes actually emitted by the driver
                 for (size_t sc = 0; sc < scanCodes.size(); sc++) {
-                    if (test_bit(scanCodes[sc], device->keyBitmask)) {
+                    if (device->keyBitmask.test(scanCodes[sc])) {
                         outFlags[codeIndex] = 1;
                         break;
                     }
@@ -549,7 +520,7 @@
     Device* device = getDeviceLocked(deviceId);
     status_t status = NAME_NOT_FOUND;
 
-    if (device) {
+    if (device != nullptr) {
         // Check the key character map first.
         sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
         if (kcm != nullptr) {
@@ -588,7 +559,7 @@
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
 
-    if (device && device->keyMap.haveKeyLayout()) {
+    if (device != nullptr && device->keyMap.haveKeyLayout()) {
         status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo);
         if (err == NO_ERROR) {
             return NO_ERROR;
@@ -607,10 +578,8 @@
 bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && scanCode >= 0 && scanCode <= KEY_MAX) {
-        if (test_bit(scanCode, device->keyBitmask)) {
-            return true;
-        }
+    if (device != nullptr && scanCode >= 0 && scanCode <= KEY_MAX) {
+        return device->keyBitmask.test(scanCode);
     }
     return false;
 }
@@ -619,10 +588,8 @@
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     int32_t sc;
-    if (device && mapLed(device, led, &sc) == NO_ERROR) {
-        if (test_bit(sc, device->ledBitmask)) {
-            return true;
-        }
+    if (device != nullptr && mapLed(device, led, &sc) == NO_ERROR) {
+        return device->ledBitmask.test(sc);
     }
     return false;
 }
@@ -635,7 +602,7 @@
 
 void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) {
     int32_t sc;
-    if (device && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
+    if (device != nullptr && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
         struct input_event ev;
         ev.time.tv_sec = 0;
         ev.time.tv_usec = 0;
@@ -656,7 +623,7 @@
 
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && device->virtualKeyMap) {
+    if (device != nullptr && device->virtualKeyMap) {
         const std::vector<VirtualKeyDefinition> virtualKeys =
                 device->virtualKeyMap->getVirtualKeys();
         outVirtualKeys.insert(outVirtualKeys.end(), virtualKeys.begin(), virtualKeys.end());
@@ -666,7 +633,7 @@
 sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device) {
+    if (device != nullptr) {
         return device->getKeyCharacterMap();
     }
     return nullptr;
@@ -675,7 +642,7 @@
 bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device) {
+    if (device != nullptr) {
         if (map != device->overlayKeyMap) {
             device->overlayKeyMap = map;
             device->combinedKeyMap = KeyCharacterMap::combine(device->keyMap.keyCharacterMap, map);
@@ -735,17 +702,18 @@
           identifier.descriptor.c_str());
 }
 
-void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
+void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && device->hasValidFd()) {
+    if (device != nullptr && device->hasValidFd()) {
         ff_effect effect;
         memset(&effect, 0, sizeof(effect));
         effect.type = FF_RUMBLE;
         effect.id = device->ffEffectId;
-        effect.u.rumble.strong_magnitude = 0xc000;
-        effect.u.rumble.weak_magnitude = 0xc000;
-        effect.replay.length = (duration + 999999LL) / 1000000LL;
+        // evdev FF_RUMBLE effect only supports two channels of vibration.
+        effect.u.rumble.strong_magnitude = element.getChannel(0);
+        effect.u.rumble.weak_magnitude = element.getChannel(1);
+        effect.replay.length = element.duration.count();
         effect.replay.delay = 0;
         if (ioctl(device->fd, EVIOCSFF, &effect)) {
             ALOGW("Could not upload force feedback effect to device %s due to error %d.",
@@ -772,7 +740,7 @@
 void EventHub::cancelVibrate(int32_t deviceId) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && device->hasValidFd()) {
+    if (device != nullptr && device->hasValidFd()) {
         if (device->ffEffectPlaying) {
             device->ffEffectPlaying = false;
 
@@ -1089,7 +1057,7 @@
     AutoMutex _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
-    if (!device || !device->videoDevice) {
+    if (device == nullptr || !device->videoDevice) {
         return {};
     }
     return device->videoDevice->consumeFrames();
@@ -1126,17 +1094,6 @@
 
 // ----------------------------------------------------------------------------
 
-static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
-    const uint8_t* end = array + endIndex;
-    array += startIndex;
-    while (array != end) {
-        if (*(array++) != 0) {
-            return true;
-        }
-    }
-    return false;
-}
-
 static const int32_t GAMEPAD_KEYCODES[] = {
         AKEYCODE_BUTTON_A,      AKEYCODE_BUTTON_B,      AKEYCODE_BUTTON_C,    //
         AKEYCODE_BUTTON_X,      AKEYCODE_BUTTON_Y,      AKEYCODE_BUTTON_Z,    //
@@ -1306,31 +1263,27 @@
     loadConfigurationLocked(device);
 
     // Figure out the kinds of events the device reports.
-    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
-    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
-    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
-    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
-    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
-    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
-    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
+    device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
+    device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0), device->absBitmask);
+    device->readDeviceBitMask(EVIOCGBIT(EV_REL, 0), device->relBitmask);
+    device->readDeviceBitMask(EVIOCGBIT(EV_SW, 0), device->swBitmask);
+    device->readDeviceBitMask(EVIOCGBIT(EV_LED, 0), device->ledBitmask);
+    device->readDeviceBitMask(EVIOCGBIT(EV_FF, 0), device->ffBitmask);
+    device->readDeviceBitMask(EVIOCGPROP(0), device->propBitmask);
 
     // See if this is a keyboard.  Ignore everything in the button range except for
     // joystick and gamepad buttons which are handled like keyboards for the most part.
     bool haveKeyboardKeys =
-            containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) ||
-            containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_WHEEL),
-                                sizeof_bit_array(KEY_MAX + 1));
-    bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
-                                                  sizeof_bit_array(BTN_MOUSE)) ||
-            containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
-                                sizeof_bit_array(BTN_DIGI));
+            device->keyBitmask.any(0, BTN_MISC) || device->keyBitmask.any(BTN_WHEEL, KEY_MAX + 1);
+    bool haveGamepadButtons = device->keyBitmask.any(BTN_MISC, BTN_MOUSE) ||
+            device->keyBitmask.any(BTN_JOYSTICK, BTN_DIGI);
     if (haveKeyboardKeys || haveGamepadButtons) {
         device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
     }
 
     // See if this is a cursor device such as a trackball or mouse.
-    if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) &&
-        test_bit(REL_Y, device->relBitmask)) {
+    if (device->keyBitmask.test(BTN_MOUSE) && device->relBitmask.test(REL_X) &&
+        device->relBitmask.test(REL_Y)) {
         device->classes |= INPUT_DEVICE_CLASS_CURSOR;
     }
 
@@ -1345,22 +1298,20 @@
 
     // See if this is a touch pad.
     // Is this a new modern multi-touch driver?
-    if (test_bit(ABS_MT_POSITION_X, device->absBitmask) &&
-        test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
+    if (device->absBitmask.test(ABS_MT_POSITION_X) && device->absBitmask.test(ABS_MT_POSITION_Y)) {
         // Some joysticks such as the PS3 controller report axes that conflict
         // with the ABS_MT range.  Try to confirm that the device really is
         // a touch screen.
-        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
+        if (device->keyBitmask.test(BTN_TOUCH) || !haveGamepadButtons) {
             device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
         }
         // Is this an old style single-touch driver?
-    } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) &&
-               test_bit(ABS_Y, device->absBitmask)) {
+    } else if (device->keyBitmask.test(BTN_TOUCH) && device->absBitmask.test(ABS_X) &&
+               device->absBitmask.test(ABS_Y)) {
         device->classes |= INPUT_DEVICE_CLASS_TOUCH;
         // Is this a BT stylus?
-    } else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
-                test_bit(BTN_TOUCH, device->keyBitmask)) &&
-               !test_bit(ABS_X, device->absBitmask) && !test_bit(ABS_Y, device->absBitmask)) {
+    } else if ((device->absBitmask.test(ABS_PRESSURE) || device->keyBitmask.test(BTN_TOUCH)) &&
+               !device->absBitmask.test(ABS_X) && !device->absBitmask.test(ABS_Y)) {
         device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
         // Keyboard will try to claim some of the buttons but we really want to reserve those so we
         // can fuse it with the touch screen data, so just take them back. Note this means an
@@ -1374,7 +1325,7 @@
     if (haveGamepadButtons) {
         uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
         for (int i = 0; i <= ABS_MAX; i++) {
-            if (test_bit(i, device->absBitmask) &&
+            if (device->absBitmask.test(i) &&
                 (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
                 device->classes = assumedClasses;
                 break;
@@ -1384,14 +1335,14 @@
 
     // Check whether this device has switches.
     for (int i = 0; i <= SW_MAX; i++) {
-        if (test_bit(i, device->swBitmask)) {
+        if (device->swBitmask.test(i)) {
             device->classes |= INPUT_DEVICE_CLASS_SWITCH;
             break;
         }
     }
 
     // Check whether this device supports the vibrator.
-    if (test_bit(FF_RUMBLE, device->ffBitmask)) {
+    if (device->ffBitmask.test(FF_RUMBLE)) {
         device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
     }
 
@@ -1703,7 +1654,7 @@
     const size_t N = scanCodes.size();
     for (size_t i = 0; i < N && i <= KEY_MAX; i++) {
         int32_t sc = scanCodes[i];
-        if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
+        if (sc >= 0 && sc <= KEY_MAX && device->keyBitmask.test(sc)) {
             return true;
         }
     }
@@ -1718,7 +1669,7 @@
 
     int32_t scanCode;
     if (device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) {
-        if (scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) {
+        if (scanCode >= 0 && scanCode <= LED_MAX && device->ledBitmask.test(scanCode)) {
             *outScanCode = scanCode;
             return NO_ERROR;
         }
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 4b19e5e..b4eaf7f 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -424,10 +424,10 @@
     return result;
 }
 
-void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+void InputDevice::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
                           int32_t token) {
-    for_each_mapper([pattern, patternSize, repeat, token](InputMapper& mapper) {
-        mapper.vibrate(pattern, patternSize, repeat, token);
+    for_each_mapper([pattern, repeat, token](InputMapper& mapper) {
+        mapper.vibrate(pattern, repeat, token);
     });
 }
 
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 06e3743..16fe865 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -559,12 +559,12 @@
     }
 }
 
-void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
+void InputReader::vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
                           ssize_t repeat, int32_t token) {
     AutoMutex _l(mLock);
     InputDevice* device = findInputDevice(deviceId);
     if (device) {
-        device->vibrate(pattern, patternSize, repeat, token);
+        device->vibrate(pattern, repeat, token);
     }
 }
 
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index ee62c9a..c5dfcfd 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -17,6 +17,8 @@
 #ifndef _RUNTIME_EVENT_HUB_H
 #define _RUNTIME_EVENT_HUB_H
 
+#include <bitset>
+#include <climits>
 #include <vector>
 
 #include <input/Input.h>
@@ -25,6 +27,8 @@
 #include <input/KeyLayoutMap.h>
 #include <input/Keyboard.h>
 #include <input/VirtualKeyMap.h>
+#include <linux/input.h>
+#include <sys/epoll.h>
 #include <utils/BitSet.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
@@ -33,15 +37,8 @@
 #include <utils/Mutex.h>
 #include <utils/PropertyMap.h>
 
-#include <linux/input.h>
-#include <sys/epoll.h>
-
 #include "TouchVideoDevice.h"
-
-/* Convenience constants. */
-
-#define BTN_FIRST 0x100 // first button code
-#define BTN_LAST 0x15f  // last button code
+#include "VibrationElement.h"
 
 namespace android {
 
@@ -231,7 +228,7 @@
     virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
 
     /* Control the vibrator. */
-    virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0;
+    virtual void vibrate(int32_t deviceId, const VibrationElement& effect) = 0;
     virtual void cancelVibrate(int32_t deviceId) = 0;
 
     /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
@@ -256,6 +253,76 @@
     virtual status_t disableDevice(int32_t deviceId) = 0;
 };
 
+template <std::size_t BITS>
+class BitArray {
+    /* Array element type and vector of element type. */
+    using Element = std::uint32_t;
+    /* Number of bits in each BitArray element. */
+    static constexpr size_t WIDTH = sizeof(Element) * CHAR_BIT;
+    /* Number of elements to represent a bit array of the specified size of bits. */
+    static constexpr size_t COUNT = (BITS + WIDTH - 1) / WIDTH;
+
+public:
+    /* BUFFER type declaration for BitArray */
+    using Buffer = std::array<Element, COUNT>;
+    /* To tell if a bit is set in array, it selects an element from the array, and test
+     * if the relevant bit set.
+     * Note the parameter "bit" is an index to the bit, 0 <= bit < BITS.
+     */
+    inline bool test(size_t bit) const {
+        return (bit < BITS) ? mData[bit / WIDTH].test(bit % WIDTH) : false;
+    }
+    /* Returns total number of bytes needed for the array */
+    inline size_t bytes() { return (BITS + CHAR_BIT - 1) / CHAR_BIT; }
+    /* Returns true if array contains any non-zero bit from the range defined by start and end
+     * bit index [startIndex, endIndex).
+     */
+    bool any(size_t startIndex, size_t endIndex) {
+        if (startIndex >= endIndex || startIndex > BITS || endIndex > BITS + 1) {
+            ALOGE("Invalid start/end index. start = %zu, end = %zu, total bits = %zu", startIndex,
+                  endIndex, BITS);
+            return false;
+        }
+        size_t se = startIndex / WIDTH; // Start of element
+        size_t ee = endIndex / WIDTH;   // End of element
+        size_t si = startIndex % WIDTH; // Start index in start element
+        size_t ei = endIndex % WIDTH;   // End index in end element
+        // Need to check first unaligned bitset for any non zero bit
+        if (si > 0) {
+            size_t nBits = se == ee ? ei - si : WIDTH - si;
+            // Generate the mask of interested bit range
+            Element mask = ((1 << nBits) - 1) << si;
+            if (mData[se++].to_ulong() & mask) {
+                return true;
+            }
+        }
+        // Check whole bitset for any bit set
+        for (; se < ee; se++) {
+            if (mData[se].any()) {
+                return true;
+            }
+        }
+        // Need to check last unaligned bitset for any non zero bit
+        if (ei > 0 && se <= ee) {
+            // Generate the mask of interested bit range
+            Element mask = (1 << ei) - 1;
+            if (mData[se].to_ulong() & mask) {
+                return true;
+            }
+        }
+        return false;
+    }
+    /* Load bit array values from buffer */
+    void loadFromBuffer(const Buffer& buffer) {
+        for (size_t i = 0; i < COUNT; i++) {
+            mData[i] = std::bitset<WIDTH>(buffer[i]);
+        }
+    }
+
+private:
+    std::array<std::bitset<WIDTH>, COUNT> mData;
+};
+
 class EventHub : public EventHubInterface {
 public:
     EventHub();
@@ -307,7 +374,7 @@
     virtual bool setKeyboardLayoutOverlay(int32_t deviceId,
                                           const sp<KeyCharacterMap>& map) override;
 
-    virtual void vibrate(int32_t deviceId, nsecs_t duration) override;
+    virtual void vibrate(int32_t deviceId, const VibrationElement& effect) override;
     virtual void cancelVibrate(int32_t deviceId) override;
 
     virtual void requestReopenDevices() override;
@@ -332,13 +399,15 @@
 
         uint32_t classes;
 
-        uint8_t keyBitmask[(KEY_MAX + 1) / 8];
-        uint8_t absBitmask[(ABS_MAX + 1) / 8];
-        uint8_t relBitmask[(REL_MAX + 1) / 8];
-        uint8_t swBitmask[(SW_MAX + 1) / 8];
-        uint8_t ledBitmask[(LED_MAX + 1) / 8];
-        uint8_t ffBitmask[(FF_MAX + 1) / 8];
-        uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
+        BitArray<KEY_MAX> keyBitmask;
+        BitArray<KEY_MAX> keyState;
+        BitArray<ABS_MAX> absBitmask;
+        BitArray<REL_MAX> relBitmask;
+        BitArray<SW_MAX> swBitmask;
+        BitArray<SW_MAX> swState;
+        BitArray<LED_MAX> ledBitmask;
+        BitArray<FF_MAX> ffBitmask;
+        BitArray<INPUT_PROP_MAX> propBitmask;
 
         std::string configurationFile;
         PropertyMap* configuration;
@@ -371,6 +440,21 @@
             }
             return keyMap.keyCharacterMap;
         }
+
+        template <std::size_t N>
+        status_t readDeviceBitMask(unsigned long ioctlCode, BitArray<N>& bitArray) {
+            if (!hasValidFd()) {
+                return BAD_VALUE;
+            }
+            if ((_IOC_SIZE(ioctlCode) == 0)) {
+                ioctlCode |= _IOC(0, 0, 0, bitArray.bytes());
+            }
+
+            typename BitArray<N>::Buffer buffer;
+            status_t ret = ioctl(fd, ioctlCode, buffer.data());
+            bitArray.loadFromBuffer(buffer);
+            return ret;
+        }
     };
 
     status_t openDeviceLocked(const std::string& devicePath);
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 71313fc..6cb86bd 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -81,7 +81,7 @@
     int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
                                uint8_t* outFlags);
-    void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
+    void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat, int32_t token);
     void cancelVibrate(int32_t token);
     void cancelTouch(nsecs_t when);
 
@@ -262,7 +262,9 @@
     inline bool setKeyboardLayoutOverlay(const sp<KeyCharacterMap>& map) {
         return mEventHub->setKeyboardLayoutOverlay(mId, map);
     }
-    inline void vibrate(nsecs_t duration) { return mEventHub->vibrate(mId, duration); }
+    inline void vibrate(const VibrationElement& element) {
+        return mEventHub->vibrate(mId, element);
+    }
     inline void cancelVibrate() { return mEventHub->cancelVibrate(mId); }
 
     inline bool hasAbsoluteAxis(int32_t code) const {
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 108b9c2..9cb2052 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -78,7 +78,7 @@
 
     virtual void requestRefreshConfiguration(uint32_t changes) override;
 
-    virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
+    virtual void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
                          ssize_t repeat, int32_t token) override;
     virtual void cancelVibrate(int32_t deviceId, int32_t token) override;
 
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index a8fe39a..1db829f 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -56,7 +56,7 @@
     return false;
 }
 
-void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+void InputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
                           int32_t token) {}
 
 void InputMapper::cancelVibrate(int32_t token) {}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 949c7ea..d9fc5cc 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -22,6 +22,7 @@
 #include "InputListener.h"
 #include "InputReaderContext.h"
 #include "StylusState.h"
+#include "VibrationElement.h"
 
 namespace android {
 
@@ -62,7 +63,8 @@
     virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
                                        const int32_t* keyCodes, uint8_t* outFlags);
-    virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
+    virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
+                         int32_t token);
     virtual void cancelVibrate(int32_t token);
     virtual void cancelTouch(nsecs_t when);
 
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 43bd9f1..0440f49 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -236,6 +236,20 @@
     mMultiTouchMotionAccumulator.process(rawEvent);
 }
 
+std::optional<int32_t> MultiTouchInputMapper::getActiveBitId(
+        const MultiTouchMotionAccumulator::Slot& inSlot) {
+    if (mHavePointerIds) {
+        int32_t trackingId = inSlot.getTrackingId();
+        for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
+            int32_t n = idBits.clearFirstMarkedBit();
+            if (mPointerTrackingIdMap[n] == trackingId) {
+                return std::make_optional(n);
+            }
+        }
+    }
+    return std::nullopt;
+}
+
 void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
     size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
     size_t outCount = 0;
@@ -250,10 +264,9 @@
         }
 
         if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
-            if (!mCurrentMotionAborted) {
-                ALOGI("Canceling touch gesture from device %s because the palm event was detected",
-                      getDeviceName().c_str());
-                cancelTouch(when);
+            std::optional<int32_t> id = getActiveBitId(*inSlot);
+            if (id) {
+                outState->rawPointerData.canceledIdBits.markBit(id.value());
             }
             continue;
         }
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 190282f..ea6f207 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -103,6 +103,8 @@
     bool hasStylus() const override;
 
 private:
+    // If the slot is in use, return the bit id. Return std::nullopt otherwise.
+    std::optional<int32_t> getActiveBitId(const MultiTouchMotionAccumulator::Slot& inSlot);
     MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
 
     // Specifies the pointer id bits that are in use, and their associated tracking id.
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 4274ca8..15d5288 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -104,6 +104,7 @@
     pointerCount = other.pointerCount;
     hoveringIdBits = other.hoveringIdBits;
     touchingIdBits = other.touchingIdBits;
+    canceledIdBits = other.canceledIdBits;
 
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointers[i] = other.pointers[i];
@@ -140,6 +141,7 @@
     pointerCount = 0;
     hoveringIdBits.clear();
     touchingIdBits.clear();
+    canceledIdBits.clear();
 }
 
 void CookedPointerData::copyFrom(const CookedPointerData& other) {
@@ -1444,10 +1446,11 @@
 
 #if DEBUG_RAW_EVENTS
     ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
-          "hovering ids 0x%08x -> 0x%08x",
+          "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x",
           last->rawPointerData.pointerCount, next->rawPointerData.pointerCount,
           last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value,
-          last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value);
+          last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value,
+          next->rawPointerData.canceledIdBits.value);
 #endif
 
     processRawTouches(false /*timeout*/);
@@ -1892,14 +1895,15 @@
         // Dispatch pointer up events.
         while (!upIdBits.isEmpty()) {
             uint32_t upId = upIdBits.clearFirstMarkedBit();
-
-            dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
-                           metaState, buttonState, 0,
+            bool isCanceled = mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId);
+            dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0,
+                           isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0,
                            mLastCookedState.cookedPointerData.pointerProperties,
                            mLastCookedState.cookedPointerData.pointerCoords,
                            mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
                            mOrientedXPrecision, mOrientedYPrecision, mDownTime);
             dispatchedIdBits.clearBit(upId);
+            mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
         }
 
         // Dispatch move events if any of the remaining pointers moved from their old locations.
@@ -2025,6 +2029,8 @@
             mCurrentRawState.rawPointerData.hoveringIdBits;
     mCurrentCookedState.cookedPointerData.touchingIdBits =
             mCurrentRawState.rawPointerData.touchingIdBits;
+    mCurrentCookedState.cookedPointerData.canceledIdBits =
+            mCurrentRawState.rawPointerData.canceledIdBits;
 
     if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
         mCurrentCookedState.buttonState = 0;
@@ -3563,7 +3569,11 @@
         if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
             action = AMOTION_EVENT_ACTION_DOWN;
         } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
-            action = AMOTION_EVENT_ACTION_UP;
+            if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
+                action = AMOTION_EVENT_ACTION_CANCEL;
+            } else {
+                action = AMOTION_EVENT_ACTION_UP;
+            }
         } else {
             // Can't happen.
             ALOG_ASSERT(false);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index d437e01..94486a6 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -71,7 +71,7 @@
 
     uint32_t pointerCount;
     Pointer pointers[MAX_POINTERS];
-    BitSet32 hoveringIdBits, touchingIdBits;
+    BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits;
     uint32_t idToIndex[MAX_POINTER_ID + 1];
 
     RawPointerData();
@@ -90,6 +90,7 @@
     inline void clearIdBits() {
         hoveringIdBits.clear();
         touchingIdBits.clear();
+        canceledIdBits.clear();
     }
 
     inline const Pointer& pointerForId(uint32_t id) const { return pointers[idToIndex[id]]; }
@@ -102,7 +103,7 @@
     uint32_t pointerCount;
     PointerProperties pointerProperties[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
-    BitSet32 hoveringIdBits, touchingIdBits;
+    BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits;
     uint32_t idToIndex[MAX_POINTER_ID + 1];
 
     CookedPointerData();
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 7665680..8c1e224 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -39,23 +39,17 @@
     // TODO: Handle FF_STATUS, although it does not seem to be widely supported.
 }
 
-void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+void VibratorInputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
                                   int32_t token) {
 #if DEBUG_VIBRATOR
     std::string patternStr;
-    for (size_t i = 0; i < patternSize; i++) {
-        if (i != 0) {
-            patternStr += ", ";
-        }
-        patternStr += StringPrintf("%" PRId64, pattern[i]);
-    }
+    dumpPattern(patternStr);
     ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(),
           patternStr.c_str(), repeat, token);
 #endif
 
     mVibrating = true;
-    memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t));
-    mPatternSize = patternSize;
+    mPattern = pattern;
     mRepeat = repeat;
     mToken = token;
     mIndex = -1;
@@ -85,7 +79,7 @@
 
 void VibratorInputMapper::nextStep() {
     mIndex += 1;
-    if (size_t(mIndex) >= mPatternSize) {
+    if (size_t(mIndex) >= mPattern.size()) {
         if (mRepeat < 0) {
             // We are done.
             stopVibrating();
@@ -94,13 +88,15 @@
         mIndex = mRepeat;
     }
 
-    bool vibratorOn = mIndex & 1;
-    nsecs_t duration = mPattern[mIndex];
-    if (vibratorOn) {
+    const VibrationElement& element = mPattern[mIndex];
+    if (element.isOn()) {
 #if DEBUG_VIBRATOR
-        ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration);
+        std::string description;
+        element.dump(description);
+        ALOGD("nextStep: sending vibrate deviceId=%d, element=%s", getDeviceId(),
+              description.c_str());
 #endif
-        getDeviceContext().vibrate(duration);
+        getDeviceContext().vibrate(element);
     } else {
 #if DEBUG_VIBRATOR
         ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId());
@@ -108,10 +104,12 @@
         getDeviceContext().cancelVibrate();
     }
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    mNextStepTime = now + duration;
+    std::chrono::nanoseconds duration =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(element.duration);
+    mNextStepTime = now + duration.count();
     getContext()->requestTimeoutAtTime(mNextStepTime);
 #if DEBUG_VIBRATOR
-    ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f);
+    ALOGD("nextStep: scheduled timeout in %lldms", element.duration.count());
 #endif
 }
 
@@ -126,6 +124,25 @@
 void VibratorInputMapper::dump(std::string& dump) {
     dump += INDENT2 "Vibrator Input Mapper:\n";
     dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating));
+    if (mVibrating) {
+        dump += INDENT3 "Pattern: ";
+        dumpPattern(dump);
+        dump += "\n";
+        dump += StringPrintf(INDENT3 "Repeat Index: %zd\n", mRepeat);
+    }
+}
+
+void VibratorInputMapper::dumpPattern(std::string& dump) const {
+    dump += "[";
+
+    if (mPattern.size() > 0) {
+        mPattern[0].dump(dump);
+        std::for_each(mPattern.begin() + 1, mPattern.end(), [&dump](const auto& element) {
+            dump += ", ";
+            element.dump(dump);
+        });
+    }
+    dump += "]";
 }
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index f69fdde..bfa5ec1 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -30,7 +30,7 @@
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
     virtual void process(const RawEvent* rawEvent) override;
 
-    virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+    virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
                          int32_t token) override;
     virtual void cancelVibrate(int32_t token) override;
     virtual void timeoutExpired(nsecs_t when) override;
@@ -38,13 +38,13 @@
 
 private:
     bool mVibrating;
-    nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE];
-    size_t mPatternSize;
+    std::vector<VibrationElement> mPattern;
     ssize_t mRepeat;
     int32_t mToken;
     ssize_t mIndex;
     nsecs_t mNextStepTime;
 
+    void dumpPattern(std::string& dump) const;
     void nextStep();
     void stopVibrating();
 };
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index 71731b0..ef68a84 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -199,3 +199,76 @@
         lastEventTime = event.when; // Ensure all returned events are monotonic
     }
 }
+
+// --- BitArrayTest ---
+class BitArrayTest : public testing::Test {
+protected:
+    static constexpr size_t SINGLE_ELE_BITS = 32UL;
+    static constexpr size_t MULTI_ELE_BITS = 256UL;
+
+    virtual void SetUp() override {
+        mBitmaskSingle.loadFromBuffer(mBufferSingle);
+        mBitmaskMulti.loadFromBuffer(mBufferMulti);
+    }
+
+    android::BitArray<SINGLE_ELE_BITS> mBitmaskSingle;
+    android::BitArray<MULTI_ELE_BITS> mBitmaskMulti;
+
+private:
+    const typename android::BitArray<SINGLE_ELE_BITS>::Buffer mBufferSingle = {
+            0x800F0F0FUL // bit 0 - 31
+    };
+    const typename android::BitArray<MULTI_ELE_BITS>::Buffer mBufferMulti = {
+            0xFFFFFFFFUL, // bit 0 - 31
+            0x01000001UL, // bit 32 - 63
+            0x00000000UL, // bit 64 - 95
+            0x80000000UL, // bit 96 - 127
+            0x00000000UL, // bit 128 - 159
+            0x00000000UL, // bit 160 - 191
+            0x80000008UL, // bit 192 - 223
+            0x00000000UL, // bit 224 - 255
+    };
+};
+
+TEST_F(BitArrayTest, SetBit) {
+    ASSERT_TRUE(mBitmaskSingle.test(0));
+    ASSERT_TRUE(mBitmaskSingle.test(31));
+    ASSERT_FALSE(mBitmaskSingle.test(7));
+
+    ASSERT_TRUE(mBitmaskMulti.test(32));
+    ASSERT_TRUE(mBitmaskMulti.test(56));
+    ASSERT_FALSE(mBitmaskMulti.test(192));
+    ASSERT_TRUE(mBitmaskMulti.test(223));
+    ASSERT_FALSE(mBitmaskMulti.test(255));
+}
+
+TEST_F(BitArrayTest, AnyBit) {
+    ASSERT_TRUE(mBitmaskSingle.any(31, 32));
+    ASSERT_FALSE(mBitmaskSingle.any(12, 16));
+
+    ASSERT_TRUE(mBitmaskMulti.any(31, 32));
+    ASSERT_FALSE(mBitmaskMulti.any(33, 33));
+    ASSERT_TRUE(mBitmaskMulti.any(32, 55));
+    ASSERT_TRUE(mBitmaskMulti.any(33, 57));
+    ASSERT_FALSE(mBitmaskMulti.any(33, 55));
+    ASSERT_FALSE(mBitmaskMulti.any(130, 190));
+
+    ASSERT_FALSE(mBitmaskMulti.any(128, 195));
+    ASSERT_TRUE(mBitmaskMulti.any(128, 196));
+    ASSERT_TRUE(mBitmaskMulti.any(128, 224));
+    ASSERT_FALSE(mBitmaskMulti.any(255, 256));
+}
+
+TEST_F(BitArrayTest, SetBit_InvalidBitIndex) {
+    ASSERT_FALSE(mBitmaskSingle.test(32));
+    ASSERT_FALSE(mBitmaskMulti.test(256));
+}
+
+TEST_F(BitArrayTest, AnyBit_InvalidBitIndex) {
+    ASSERT_FALSE(mBitmaskSingle.any(32, 32));
+    ASSERT_FALSE(mBitmaskSingle.any(33, 34));
+
+    ASSERT_FALSE(mBitmaskMulti.any(256, 256));
+    ASSERT_FALSE(mBitmaskMulti.any(257, 258));
+    ASSERT_FALSE(mBitmaskMulti.any(0, 0));
+}
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index 1edc089..755373b 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import android.InputChannelInfo;
+import android.InputChannel;
 import android.InputWindowInfo;
 import android.os.ISetInputWindowsListener;
 
@@ -23,5 +23,5 @@
 {
     /* Test interfaces */
     void getInputWindows(out InputWindowInfo[] inputHandles);
-    void getInputChannels(out InputChannelInfo[] infos);
+    void getInputChannels(out InputChannel[] channels);
 }
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c749806..ce4d17d 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -602,7 +602,8 @@
 
 class FakeInputReceiver {
 public:
-    explicit FakeInputReceiver(const sp<InputChannel>& clientChannel, const std::string name)
+    explicit FakeInputReceiver(const std::shared_ptr<InputChannel>& clientChannel,
+                               const std::string name)
           : mName(name) {
         mConsumer = std::make_unique<InputConsumer>(clientChannel);
     }
@@ -754,11 +755,11 @@
                      int32_t displayId, sp<IBinder> token = nullptr)
           : mName(name) {
         if (token == nullptr) {
-            sp<InputChannel> serverChannel, clientChannel;
+            std::unique_ptr<InputChannel> serverChannel, clientChannel;
             InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
-            mInputReceiver = std::make_unique<FakeInputReceiver>(clientChannel, name);
-            dispatcher->registerInputChannel(serverChannel);
+            mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
             token = serverChannel->getConnectionToken();
+            dispatcher->registerInputChannel(std::move(serverChannel));
         }
 
         inputApplicationHandle->updateInfo();
@@ -1767,10 +1768,10 @@
 public:
     FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
                         int32_t displayId, bool isGestureMonitor = false) {
-        sp<InputChannel> serverChannel, clientChannel;
+        std::unique_ptr<InputChannel> serverChannel, clientChannel;
         InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
-        mInputReceiver = std::make_unique<FakeInputReceiver>(clientChannel, name);
-        dispatcher->registerInputMonitor(serverChannel, displayId, isGestureMonitor);
+        mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
+        dispatcher->registerInputMonitor(std::move(serverChannel), displayId, isGestureMonitor);
     }
 
     sp<IBinder> getToken() { return mInputReceiver->getToken(); }
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index 193fe77..206e260 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -113,7 +113,7 @@
 
 private:
     sp<SetInputWindowsListener> mSetInputWindowsListener;
-    sp<InputChannel> mServerChannel, mClientChannel;
+    std::unique_ptr<InputChannel> mServerChannel, mClientChannel;
     InputWindowInfo mInfo;
     std::mutex mLock;
     std::condition_variable mSetInputWindowsFinishedCondition;
@@ -136,7 +136,7 @@
     void checkFdFlags(const android::base::unique_fd& fd);
 
     binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
-    binder::Status getInputChannels(std::vector<::android::InputChannelInfo>* infos);
+    binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
 
     status_t dump(int fd, const Vector<String16>& args) override;
 
@@ -144,20 +144,20 @@
             const std::vector<InputWindowInfo>& handles,
             const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
 
-    binder::Status registerInputChannel(const InputChannelInfo& channel) override;
-    binder::Status unregisterInputChannel(const InputChannelInfo& channel) override;
+    binder::Status registerInputChannel(const InputChannel& channel) override;
+    binder::Status unregisterInputChannel(const InputChannel& channel) override;
 
 private:
     mutable Mutex mLock;
     std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
-    std::vector<sp<InputChannel>> mInputChannels;
+    std::vector<std::shared_ptr<InputChannel>> mInputChannels;
 };
 
 class TestInputQuery : public BnInputFlingerQuery {
 public:
     TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
     binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
-    binder::Status getInputChannels(std::vector<::android::InputChannelInfo>* infos) override;
+    binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
 
 private:
     sp<android::TestInputManager> mManager;
@@ -168,8 +168,8 @@
     return mManager->getInputWindows(inputHandles);
 }
 
-binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannelInfo>* infos) {
-    return mManager->getInputChannels(infos);
+binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannel>* channels) {
+    return mManager->getInputChannels(channels);
 }
 
 binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
@@ -200,27 +200,23 @@
     EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
 }
 
-binder::Status TestInputManager::registerInputChannel(const InputChannelInfo& info) {
+binder::Status TestInputManager::registerInputChannel(const InputChannel& channel) {
     AutoMutex _l(mLock);
     // check Fd flags
-    checkFdFlags(info.mFd);
+    checkFdFlags(channel.getFd());
 
-    android::base::unique_fd newFd(::dup(info.mFd));
-    sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
-    mInputChannels.push_back(channel);
+    mInputChannels.push_back(channel.dup());
 
     return binder::Status::ok();
 }
 
-binder::Status TestInputManager::unregisterInputChannel(const InputChannelInfo& info) {
+binder::Status TestInputManager::unregisterInputChannel(const InputChannel& channel) {
     AutoMutex _l(mLock);
     // check Fd flags
-    checkFdFlags(info.mFd);
-    android::base::unique_fd newFd(::dup(info.mFd));
-    sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
+    checkFdFlags(channel.getFd());
 
     auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
-                           [&](sp<InputChannel>& it) { return *it == *channel; });
+                           [&](std::shared_ptr<InputChannel>& c) { return *c == channel; });
     if (it != mInputChannels.end()) {
         mInputChannels.erase(it);
     }
@@ -247,11 +243,10 @@
     return binder::Status::ok();
 }
 
-binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannelInfo>* infos) {
-    infos->clear();
-    for (auto& channel : mInputChannels) {
-        auto chanDup = channel->dup();
-        infos->push_back(std::move(chanDup->getInfo()));
+binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannel>* channels) {
+    channels->clear();
+    for (std::shared_ptr<InputChannel>& channel : mInputChannels) {
+        channels->push_back(*channel);
     }
     return binder::Status::ok();
 }
@@ -320,12 +315,6 @@
     mService->setInputWindows(infos, mSetInputWindowsListener);
     // Verify listener call
     EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout);
-    // Verify input windows from service
-    std::vector<::android::InputWindowInfo> inputHandles;
-    mQuery->getInputWindows(&inputHandles);
-    for (auto& inputInfo : inputHandles) {
-        verifyInputWindowInfo(inputInfo);
-    }
 }
 
 /**
@@ -334,54 +323,57 @@
 TEST_F(InputFlingerServiceTest, InputWindow_SetInputWindows) {
     std::vector<InputWindowInfo> infos = {getInfo()};
     setInputWindowsByInfos(infos);
+
+    // Verify input windows from service
+    std::vector<::android::InputWindowInfo> windowInfos;
+    mQuery->getInputWindows(&windowInfos);
+    for (const ::android::InputWindowInfo& windowInfo : windowInfos) {
+        verifyInputWindowInfo(windowInfo);
+    }
 }
 
 /**
  *  Test InputFlinger service interface registerInputChannel
  */
 TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannel) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
 
     InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
-    mService->registerInputChannel(serverChannel->getInfo());
+    mService->registerInputChannel(*serverChannel);
 
-    std::vector<::android::InputChannelInfo> infos(2);
-    mQuery->getInputChannels(&infos);
-    EXPECT_EQ(infos.size(), 1UL);
+    std::vector<::android::InputChannel> channels;
+    mQuery->getInputChannels(&channels);
+    ASSERT_EQ(channels.size(), 1UL);
+    EXPECT_EQ(channels[0], *serverChannel);
 
-    auto& info = infos[0];
-    android::base::unique_fd newFd(::dup(info.mFd));
-    sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
-    EXPECT_EQ(*channel, *serverChannel);
-
-    mService->unregisterInputChannel(serverChannel->getInfo());
-    mQuery->getInputChannels(&infos);
-    EXPECT_EQ(infos.size(), 0UL);
+    mService->unregisterInputChannel(*serverChannel);
+    mQuery->getInputChannels(&channels);
+    EXPECT_EQ(channels.size(), 0UL);
 }
 
 /**
  *  Test InputFlinger service interface registerInputChannel with invalid cases
  */
 TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannelInvalid) {
-    sp<InputChannel> serverChannel, clientChannel;
+    std::unique_ptr<InputChannel> serverChannel, clientChannel;
     InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
 
-    std::vector<::android::InputChannelInfo> infos(2);
-    mQuery->getInputChannels(&infos);
-    EXPECT_EQ(infos.size(), 0UL);
+    std::vector<::android::InputChannel> channels;
+    mQuery->getInputChannels(&channels);
+    EXPECT_EQ(channels.size(), 0UL);
 
-    mService->registerInputChannel(InputChannelInfo());
-    mService->unregisterInputChannel(clientChannel->getInfo());
+    mService->registerInputChannel(InputChannel());
+    mService->unregisterInputChannel(*clientChannel);
 
-    mService->registerInputChannel(serverChannel->getInfo());
-    mService->registerInputChannel(clientChannel->getInfo());
-    mQuery->getInputChannels(&infos);
-    EXPECT_EQ(infos.size(), 2UL);
+    mService->registerInputChannel(*serverChannel);
+    mService->registerInputChannel(*clientChannel);
+    mQuery->getInputChannels(&channels);
+    EXPECT_EQ(channels.size(), 2UL);
 
-    mService->unregisterInputChannel(clientChannel->getInfo());
-    mService->unregisterInputChannel(serverChannel->getInfo());
-    mQuery->getInputChannels(&infos);
-    EXPECT_EQ(infos.size(), 0UL);
+    mService->unregisterInputChannel(*clientChannel);
+    mService->unregisterInputChannel(*serverChannel);
+    mQuery->getInputChannels(&channels);
+    EXPECT_EQ(channels.size(), 0UL);
 }
 
 } // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index fae7e64..21dd3c7 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -45,16 +45,24 @@
 static const nsecs_t ARBITRARY_TIME = 1234;
 
 // Arbitrary display properties.
-static const int32_t DISPLAY_ID = 0;
-static const int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
-static const int32_t DISPLAY_WIDTH = 480;
-static const int32_t DISPLAY_HEIGHT = 800;
-static const int32_t VIRTUAL_DISPLAY_ID = 1;
-static const int32_t VIRTUAL_DISPLAY_WIDTH = 400;
-static const int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
+static constexpr int32_t DISPLAY_ID = 0;
+static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
+static constexpr int32_t DISPLAY_WIDTH = 480;
+static constexpr int32_t DISPLAY_HEIGHT = 800;
+static constexpr int32_t VIRTUAL_DISPLAY_ID = 1;
+static constexpr int32_t VIRTUAL_DISPLAY_WIDTH = 400;
+static constexpr int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
 static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "virtual:1";
 static constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified
 
+static constexpr int32_t FIRST_SLOT = 0;
+static constexpr int32_t SECOND_SLOT = 1;
+static constexpr int32_t THIRD_SLOT = 2;
+static constexpr int32_t INVALID_TRACKING_ID = -1;
+static constexpr int32_t FIRST_TRACKING_ID = 0;
+static constexpr int32_t SECOND_TRACKING_ID = 1;
+static constexpr int32_t THIRD_TRACKING_ID = 2;
+
 // Error tolerance for floating point assertions.
 static const float EPSILON = 0.001f;
 
@@ -813,8 +821,7 @@
         return false;
     }
 
-    virtual void vibrate(int32_t, nsecs_t) {
-    }
+    virtual void vibrate(int32_t, const VibrationElement&) {}
 
     virtual void cancelVibrate(int32_t) {
     }
@@ -1880,10 +1887,6 @@
 // --- TouchProcessTest ---
 class TouchIntegrationTest : public InputReaderIntegrationTest {
 protected:
-    static const int32_t FIRST_SLOT = 0;
-    static const int32_t SECOND_SLOT = 1;
-    static const int32_t FIRST_TRACKING_ID = 0;
-    static const int32_t SECOND_TRACKING_ID = 1;
     const std::string UNIQUE_ID = "local:0";
 
     virtual void SetUp() override {
@@ -1954,9 +1957,9 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
 
     // ACTION_POINTER_UP (Second slot)
-    mDevice->sendUp();
+    mDevice->sendPointerUp();
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
               args.action);
 
     // ACTION_UP
@@ -1971,11 +1974,13 @@
     const Point centerPoint = mDevice->getCenterPoint();
 
     // ACTION_DOWN
+    mDevice->sendSlot(FIRST_SLOT);
+    mDevice->sendTrackingId(FIRST_TRACKING_ID);
     mDevice->sendDown(centerPoint);
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
     ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
 
-    // ACTION_POINTER_DOWN (Second slot)
+    // ACTION_POINTER_DOWN (second slot)
     const Point secondPoint = centerPoint + Point(100, 100);
     mDevice->sendSlot(SECOND_SLOT);
     mDevice->sendTrackingId(SECOND_TRACKING_ID);
@@ -1984,26 +1989,31 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
               args.action);
 
-    // ACTION_MOVE (Second slot)
+    // ACTION_MOVE (second slot)
     mDevice->sendMove(secondPoint + Point(1, 1));
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
 
-    // Send MT_TOOL_PALM, which indicates that the touch IC has determined this to be a grip event.
-    // Expect to receive ACTION_CANCEL, to abort the entire gesture.
+    // Send MT_TOOL_PALM (second slot), which indicates that the touch IC has determined this to be
+    // a palm event.
+    // Expect to receive the ACTION_POINTER_UP with cancel flag.
     mDevice->sendToolType(MT_TOOL_PALM);
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, args.action);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              args.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, args.flags);
 
-    // ACTION_POINTER_UP (Second slot)
-    mDevice->sendUp();
+    // Send up to second slot, expect first slot send moving.
+    mDevice->sendPointerUp();
+    ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
 
-    // ACTION_UP
+    // Send ACTION_UP (first slot)
     mDevice->sendSlot(FIRST_SLOT);
     mDevice->sendUp();
 
-    // Expect no event received after abort the entire gesture.
-    ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
+    ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
 }
 
 // --- InputDeviceTest ---
@@ -7064,10 +7074,10 @@
 }
 
 /**
- * Test touch should be canceled when received the MT_TOOL_PALM event, and the following MOVE and
- * UP events should be ignored.
+ * Test single touch should be canceled when received the MT_TOOL_PALM event, and the following
+ * MOVE and UP events should be ignored.
  */
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) {
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(DISPLAY_ORIENTATION_0);
     prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
@@ -7077,7 +7087,7 @@
 
     // default tool type is finger
     constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
-    processId(mapper, 1);
+    processId(mapper, FIRST_TRACKING_ID);
     processPosition(mapper, x1, y1);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7091,19 +7101,19 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
 
     // Ignore the following MOVE and UP events if had detect a palm event.
-    processId(mapper, 1);
+    processId(mapper, FIRST_TRACKING_ID);
     processPosition(mapper, x2, y2);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 
     // finger up.
-    processId(mapper, -1);
+    processId(mapper, INVALID_TRACKING_ID);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 
     // new finger down
+    processId(mapper, FIRST_TRACKING_ID);
     processToolType(mapper, MT_TOOL_FINGER);
-    processId(mapper, 1);
     processPosition(mapper, x3, y3);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7112,11 +7122,10 @@
 }
 
 /**
- * Test multi-touch should be canceled when received the MT_TOOL_PALM event from some finger,
- * and could be allowed again after all non-MT_TOOL_PALM is release and the new point is
- * MT_TOOL_FINGER.
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger,
+ * and the rest active fingers could still be allowed to receive the events
  */
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) {
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(DISPLAY_ORIENTATION_0);
     prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
@@ -7125,8 +7134,8 @@
     NotifyMotionArgs motionArgs;
 
     // default tool type is finger
-    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
-    processId(mapper, 1);
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220;
+    processId(mapper, FIRST_TRACKING_ID);
     processPosition(mapper, x1, y1);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7134,51 +7143,232 @@
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
 
     // Second finger down.
-    processSlot(mapper, 1);
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
     processPosition(mapper, x2, y2);
-    processId(mapper, 2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
+
+    // If the tool type of the first finger changes to MT_TOOL_PALM,
+    // we expect to receive ACTION_POINTER_UP with cancel flag.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_PALM);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+    // The following MOVE events of second finger should be processed.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2 + 1, y2 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // First finger up. It used to be in palm mode, and we already generated ACTION_POINTER_UP for
+    // it. Second finger receive move.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // Second finger keeps moving.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2 + 2, y2 + 2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // Second finger up.
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+}
+
+/**
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event, if only 1 finger
+ * is active, it should send CANCEL after receiving the MT_TOOL_PALM event.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelWhenAllTouchIsPalm) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    NotifyMotionArgs motionArgs;
+
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+    // First finger down.
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // Second finger down.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
               motionArgs.action);
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
 
-    // If the tool type of the first pointer changes to MT_TOOL_PALM,
-    // the entire gesture should be aborted, so we expect to receive ACTION_CANCEL.
-    processSlot(mapper, 0);
-    processId(mapper, 1);
+    // If the tool type of the first finger changes to MT_TOOL_PALM,
+    // we expect to receive ACTION_POINTER_UP with cancel flag.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_PALM);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+    // Second finger keeps moving.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2 + 1, y2 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // second finger becomes palm, receive cancel due to only 1 finger is active.
+    processId(mapper, SECOND_TRACKING_ID);
     processToolType(mapper, MT_TOOL_PALM);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
 
-    // Ignore the following MOVE and UP events if had detect a palm event.
-    processSlot(mapper, 1);
-    processId(mapper, 2);
+    // third finger down.
+    processSlot(mapper, THIRD_SLOT);
+    processId(mapper, THIRD_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_FINGER);
     processPosition(mapper, x3, y3);
     processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
-    // second finger up.
-    processId(mapper, -1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
-    // first finger move, but still in palm
-    processSlot(mapper, 0);
-    processId(mapper, 1);
-    processPosition(mapper, x1 - 1, y1 - 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
-    // second finger down, expect as new finger down.
-    processSlot(mapper, 1);
-    processId(mapper, 2);
-    processPosition(mapper, x2, y2);
-    processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // third finger move
+    processId(mapper, THIRD_TRACKING_ID);
+    processPosition(mapper, x3 + 1, y3 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // first finger up, third finger receive move.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // second finger up, third finger receive move.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // third finger up.
+    processSlot(mapper, THIRD_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+}
+
+/**
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger,
+ * and the active finger could still be allowed to receive the events
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPointer) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    NotifyMotionArgs motionArgs;
+
+    // default tool type is finger
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220;
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // Second finger down.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // If the tool type of the second finger changes to MT_TOOL_PALM,
+    // we expect to receive ACTION_POINTER_UP with cancel flag.
+    processId(mapper, SECOND_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_PALM);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+    // The following MOVE event should be processed.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1 + 1, y1 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // second finger up.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // first finger keep moving
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1 + 2, y1 + 2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // first finger up.
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
 }
 
 // --- MultiTouchInputMapperTest_ExternalDevice ---
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 0659511..7fec2c8 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -179,6 +179,11 @@
     injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
+void UinputTouchScreen::sendPointerUp() {
+    sendTrackingId(0xffffffff);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
+}
+
 void UinputTouchScreen::sendUp() {
     sendTrackingId(0xffffffff);
     injectEvent(EV_KEY, BTN_TOUCH, 0);
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index 22d1f63..01a557c 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -139,6 +139,7 @@
     void sendTrackingId(int32_t trackingId);
     void sendDown(const Point& point);
     void sendMove(const Point& point);
+    void sendPointerUp();
     void sendUp();
     void sendToolType(int32_t toolType);
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8dd4b0a..b53e2dc 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -61,36 +61,46 @@
     } while (false)
 
 namespace android {
+
 namespace {
 
-std::unique_ptr<DispSync> createDispSync(bool supportKernelTimer) {
-    // TODO (140302863) remove this and use the vsync_reactor system.
-    if (property_get_bool("debug.sf.vsync_reactor", true)) {
+std::unique_ptr<scheduler::VSyncTracker> createVSyncTracker() {
+    // TODO (144707443) tune Predictor tunables.
+    static constexpr int default_rate = 60;
+    static constexpr auto initial_period =
+            std::chrono::duration<nsecs_t, std::ratio<1, default_rate>>(1);
+    static constexpr size_t vsyncTimestampHistorySize = 20;
+    static constexpr size_t minimumSamplesForPrediction = 6;
+    static constexpr uint32_t discardOutlierPercent = 20;
+    return std::make_unique<
+            scheduler::VSyncPredictor>(std::chrono::duration_cast<std::chrono::nanoseconds>(
+                                               initial_period)
+                                               .count(),
+                                       vsyncTimestampHistorySize, minimumSamplesForPrediction,
+                                       discardOutlierPercent);
+}
+
+std::unique_ptr<scheduler::VSyncDispatch> createVSyncDispatch(
+        const std::unique_ptr<scheduler::VSyncTracker>& vSyncTracker) {
+    if (!vSyncTracker) return {};
+
+    // TODO (144707443) tune Predictor tunables.
+    static constexpr auto vsyncMoveThreshold =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(3ms);
+    static constexpr auto timerSlack = std::chrono::duration_cast<std::chrono::nanoseconds>(500us);
+    return std::make_unique<
+            scheduler::VSyncDispatchTimerQueue>(std::make_unique<scheduler::Timer>(), *vSyncTracker,
+                                                timerSlack.count(), vsyncMoveThreshold.count());
+}
+
+std::unique_ptr<DispSync> createDispSync(
+        const std::unique_ptr<scheduler::VSyncTracker>& vSyncTracker,
+        const std::unique_ptr<scheduler::VSyncDispatch>& vSyncDispatch, bool supportKernelTimer) {
+    if (vSyncTracker && vSyncDispatch) {
         // TODO (144707443) tune Predictor tunables.
-        static constexpr int defaultRate = 60;
-        static constexpr auto initialPeriod =
-                std::chrono::duration<nsecs_t, std::ratio<1, defaultRate>>(1);
-        static constexpr size_t vsyncTimestampHistorySize = 20;
-        static constexpr size_t minimumSamplesForPrediction = 6;
-        static constexpr uint32_t discardOutlierPercent = 20;
-        auto tracker = std::make_unique<
-                scheduler::VSyncPredictor>(std::chrono::duration_cast<std::chrono::nanoseconds>(
-                                                   initialPeriod)
-                                                   .count(),
-                                           vsyncTimestampHistorySize, minimumSamplesForPrediction,
-                                           discardOutlierPercent);
-
-        static constexpr auto vsyncMoveThreshold =
-                std::chrono::duration_cast<std::chrono::nanoseconds>(3ms);
-        static constexpr auto timerSlack =
-                std::chrono::duration_cast<std::chrono::nanoseconds>(500us);
-        auto dispatch = std::make_unique<
-                scheduler::VSyncDispatchTimerQueue>(std::make_unique<scheduler::Timer>(), *tracker,
-                                                    timerSlack.count(), vsyncMoveThreshold.count());
-
         static constexpr size_t pendingFenceLimit = 20;
         return std::make_unique<scheduler::VSyncReactor>(std::make_unique<scheduler::SystemClock>(),
-                                                         std::move(dispatch), std::move(tracker),
+                                                         *vSyncDispatch, *vSyncTracker,
                                                          pendingFenceLimit, supportKernelTimer);
     } else {
         return std::make_unique<impl::DispSync>("SchedulerDispSync",
@@ -110,7 +120,11 @@
                      ISchedulerCallback& schedulerCallback, bool useContentDetectionV2,
                      bool useContentDetection)
       : mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
-        mPrimaryDispSync(createDispSync(mSupportKernelTimer)),
+        // TODO (140302863) remove this and use the vsync_reactor system.
+        mUseVsyncPredictor(property_get_bool("debug.sf.vsync_reactor", true)),
+        mVSyncTracker(mUseVsyncPredictor ? createVSyncTracker() : nullptr),
+        mVSyncDispatch(createVSyncDispatch(mVSyncTracker)),
+        mPrimaryDispSync(createDispSync(mVSyncTracker, mVSyncDispatch, mSupportKernelTimer)),
         mEventControlThread(new impl::EventControlThread(std::move(function))),
         mLayerHistory(createLayerHistory(refreshRateConfigs, useContentDetectionV2)),
         mSchedulerCallback(schedulerCallback),
@@ -156,6 +170,7 @@
                      std::unique_ptr<LayerHistory> layerHistory, bool useContentDetectionV2,
                      bool useContentDetection)
       : mSupportKernelTimer(false),
+        mUseVsyncPredictor(true),
         mPrimaryDispSync(std::move(primaryDispSync)),
         mEventControlThread(std::move(eventControlThread)),
         mLayerHistory(std::move(layerHistory)),
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 5fee4b4..2fe5629 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -44,7 +44,11 @@
 class DispSync;
 class FenceTime;
 class InjectVSyncSource;
-struct DisplayStateInfo;
+
+namespace scheduler {
+class VSyncDispatch;
+class VSyncTracker;
+} // namespace scheduler
 
 class ISchedulerCallback {
 public:
@@ -230,6 +234,9 @@
     // Whether to use idle timer callbacks that support the kernel timer.
     const bool mSupportKernelTimer;
 
+    const bool mUseVsyncPredictor;
+    const std::unique_ptr<scheduler::VSyncTracker> mVSyncTracker;
+    const std::unique_ptr<scheduler::VSyncDispatch> mVSyncDispatch;
     std::unique_ptr<DispSync> mPrimaryDispSync;
     std::unique_ptr<EventControlThread> mEventControlThread;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index efa8bab..a2b279b 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -55,15 +55,15 @@
     }
 };
 
-VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
-                           std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit,
+VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch,
+                           VSyncTracker& tracker, size_t pendingFenceLimit,
                            bool supportKernelIdleTimer)
       : mClock(std::move(clock)),
-        mTracker(std::move(tracker)),
-        mDispatch(std::move(dispatch)),
+        mTracker(tracker),
+        mDispatch(dispatch),
         mPendingLimit(pendingFenceLimit),
         mPredictedVsyncTracer(property_get_bool("debug.sf.show_predicted_vsync", false)
-                                      ? std::make_unique<PredictedVsyncTracer>(*mDispatch)
+                                      ? std::make_unique<PredictedVsyncTracer>(mDispatch)
                                       : nullptr),
         mSupportKernelIdleTimer(supportKernelIdleTimer) {}
 
@@ -182,7 +182,7 @@
         } else if (time == Fence::SIGNAL_TIME_INVALID) {
             it = mUnfiredFences.erase(it);
         } else {
-            timestampAccepted &= mTracker->addVsyncTimestamp(time);
+            timestampAccepted &= mTracker.addVsyncTimestamp(time);
 
             it = mUnfiredFences.erase(it);
         }
@@ -194,7 +194,7 @@
         }
         mUnfiredFences.push_back(fence);
     } else {
-        timestampAccepted &= mTracker->addVsyncTimestamp(signalTime);
+        timestampAccepted &= mTracker.addVsyncTimestamp(signalTime);
     }
 
     if (!timestampAccepted) {
@@ -224,12 +224,12 @@
 }
 
 nsecs_t VSyncReactor::computeNextRefresh(int periodOffset, nsecs_t now) const {
-    auto const currentPeriod = periodOffset ? mTracker->currentPeriod() : 0;
-    return mTracker->nextAnticipatedVSyncTimeFrom(now + periodOffset * currentPeriod);
+    auto const currentPeriod = periodOffset ? mTracker.currentPeriod() : 0;
+    return mTracker.nextAnticipatedVSyncTimeFrom(now + periodOffset * currentPeriod);
 }
 
 nsecs_t VSyncReactor::expectedPresentTime(nsecs_t now) {
-    return mTracker->nextAnticipatedVSyncTimeFrom(now);
+    return mTracker.nextAnticipatedVSyncTimeFrom(now);
 }
 
 void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
@@ -262,11 +262,11 @@
 }
 
 nsecs_t VSyncReactor::getPeriod() {
-    return mTracker->currentPeriod();
+    return mTracker.currentPeriod();
 }
 
 void VSyncReactor::beginResync() {
-    mTracker->resetModel();
+    mTracker.resetModel();
 }
 
 void VSyncReactor::endResync() {}
@@ -307,7 +307,7 @@
     if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
         ATRACE_NAME("VSR: period confirmed");
         if (mPeriodTransitioningTo) {
-            mTracker->setPeriod(*mPeriodTransitioningTo);
+            mTracker.setPeriod(*mPeriodTransitioningTo);
             for (auto& entry : mCallbacks) {
                 entry.second->setPeriod(*mPeriodTransitioningTo);
             }
@@ -315,12 +315,12 @@
         }
 
         if (mLastHwVsync) {
-            mTracker->addVsyncTimestamp(*mLastHwVsync);
+            mTracker.addVsyncTimestamp(*mLastHwVsync);
         }
-        mTracker->addVsyncTimestamp(timestamp);
+        mTracker.addVsyncTimestamp(timestamp);
 
         endPeriodTransition();
-        mMoreSamplesNeeded = mTracker->needsMoreSamples();
+        mMoreSamplesNeeded = mTracker.needsMoreSamples();
     } else if (mPeriodConfirmationInProgress) {
         ATRACE_NAME("VSR: still confirming period");
         mLastHwVsync = timestamp;
@@ -329,8 +329,8 @@
     } else {
         ATRACE_NAME("VSR: adding sample");
         *periodFlushed = false;
-        mTracker->addVsyncTimestamp(timestamp);
-        mMoreSamplesNeeded = mTracker->needsMoreSamples();
+        mTracker.addVsyncTimestamp(timestamp);
+        mMoreSamplesNeeded = mTracker.needsMoreSamples();
     }
 
     if (!mMoreSamplesNeeded) {
@@ -353,9 +353,9 @@
             return NO_MEMORY;
         }
 
-        auto const period = mTracker->currentPeriod();
-        auto repeater = std::make_unique<CallbackRepeater>(*mDispatch, callback, name, period,
-                                                           phase, mClock->now());
+        auto const period = mTracker.currentPeriod();
+        auto repeater = std::make_unique<CallbackRepeater>(mDispatch, callback, name, period, phase,
+                                                           mClock->now());
         it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first;
     }
 
@@ -409,9 +409,9 @@
     }
 
     StringAppendF(&result, "VSyncTracker:\n");
-    mTracker->dump(result);
+    mTracker.dump(result);
     StringAppendF(&result, "VSyncDispatch:\n");
-    mDispatch->dump(result);
+    mDispatch.dump(result);
 }
 
 void VSyncReactor::reset() {}
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 265d89c..22ceb39 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -35,9 +35,8 @@
 // TODO (b/145217110): consider renaming.
 class VSyncReactor : public android::DispSync {
 public:
-    VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
-                 std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit,
-                 bool supportKernelIdleTimer);
+    VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch, VSyncTracker& tracker,
+                 size_t pendingFenceLimit, bool supportKernelIdleTimer);
     ~VSyncReactor();
 
     bool addPresentFence(const std::shared_ptr<FenceTime>& fence) final;
@@ -72,8 +71,8 @@
             REQUIRES(mMutex);
 
     std::unique_ptr<Clock> const mClock;
-    std::unique_ptr<VSyncTracker> const mTracker;
-    std::unique_ptr<VSyncDispatch> const mDispatch;
+    VSyncTracker& mTracker;
+    VSyncDispatch& mDispatch;
     size_t const mPendingLimit;
 
     mutable std::mutex mMutex;
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 6856612..c5cddf3 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -45,26 +45,6 @@
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
-class VSyncTrackerWrapper : public VSyncTracker {
-public:
-    VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {}
-
-    bool addVsyncTimestamp(nsecs_t timestamp) final {
-        return mTracker->addVsyncTimestamp(timestamp);
-    }
-    nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
-        return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
-    }
-    nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
-    void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
-    void resetModel() final { mTracker->resetModel(); }
-    bool needsMoreSamples() const final { return mTracker->needsMoreSamples(); }
-    void dump(std::string& result) const final { mTracker->dump(result); }
-
-private:
-    std::shared_ptr<VSyncTracker> const mTracker;
-};
-
 class MockClock : public Clock {
 public:
     MOCK_CONST_METHOD0(now, nsecs_t());
@@ -90,29 +70,6 @@
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
-class VSyncDispatchWrapper : public VSyncDispatch {
-public:
-    VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {}
-    CallbackToken registerCallback(std::function<void(nsecs_t, nsecs_t)> const& callbackFn,
-                                   std::string callbackName) final {
-        return mDispatch->registerCallback(callbackFn, callbackName);
-    }
-
-    void unregisterCallback(CallbackToken token) final { mDispatch->unregisterCallback(token); }
-
-    ScheduleResult schedule(CallbackToken token, nsecs_t workDuration,
-                            nsecs_t earliestVsync) final {
-        return mDispatch->schedule(token, workDuration, earliestVsync);
-    }
-
-    CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); }
-
-    void dump(std::string& result) const final { return mDispatch->dump(result); }
-
-private:
-    std::shared_ptr<VSyncDispatch> const mDispatch;
-};
-
 std::shared_ptr<FenceTime> generateInvalidFence() {
     sp<Fence> fence = new Fence();
     return std::make_shared<FenceTime>(fence);
@@ -157,10 +114,8 @@
           : mMockDispatch(std::make_shared<NiceMock<MockVSyncDispatch>>()),
             mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
             mMockClock(std::make_shared<NiceMock<MockClock>>()),
-            mReactor(std::make_unique<ClockWrapper>(mMockClock),
-                     std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
-                     std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit,
-                     false /* supportKernelIdleTimer */) {
+            mReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
+                     kPendingLimit, false /* supportKernelIdleTimer */) {
         ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow));
         ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period));
     }
@@ -745,10 +700,9 @@
 
 TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) {
     // Create a reactor which supports the kernel idle timer
-    auto idleReactor = VSyncReactor(std::make_unique<ClockWrapper>(mMockClock),
-                                    std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
-                                    std::make_unique<VSyncTrackerWrapper>(mMockTracker),
-                                    kPendingLimit, true /* supportKernelIdleTimer */);
+    auto idleReactor =
+            VSyncReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
+                         kPendingLimit, true /* supportKernelIdleTimer */);
 
     bool periodFlushed = true;
     EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(4);