Merge "Fix drag and drop (3/3)"
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 849eb44..909bdd7 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -98,9 +98,11 @@
     return binder::Status::ok();
 }
 
-binder::Status DumpstateService::startBugreport(int, int bugreport_mode, int32_t* returned_id) {
-    // TODO(111441001): return a request id here.
-    *returned_id = -1;
+binder::Status DumpstateService::startBugreport(const android::base::unique_fd& /* bugreportFd */,
+                                                const android::base::unique_fd& /* screenshotFd */,
+                                                int bugreport_mode,
+                                                const sp<IDumpstateListener>& /* listener */) {
+    // TODO(b/111441001): Pass in fds & other arguments to DumpOptions.
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
     if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 58095b3..1736ae8 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -20,6 +20,7 @@
 #include <mutex>
 #include <vector>
 
+#include <android-base/unique_fd.h>
 #include <binder/BinderService.h>
 
 #include "android/os/BnDumpstate.h"
@@ -41,7 +42,9 @@
                                bool getSectionDetails,
                                sp<IDumpstateToken>* returned_token) override;
 
-    binder::Status startBugreport(int fd, int bugreport_mode, int32_t* returned_id) override;
+    binder::Status startBugreport(const android::base::unique_fd& bugreportFd,
+                                  const android::base::unique_fd& screenshotFd, int bugreport_mode,
+                                  const sp<IDumpstateListener>& listener) override;
 
   private:
     Dumpstate& ds_;
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 617eab3..ba3e290 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -63,6 +63,12 @@
 
     /*
      * Starts a bugreport in the background.
+     *
+     * @param bugreportFd the file to which the zipped bugreport should be written
+     * @param screenshotFd the file to which screenshot should be written; optional
+     * @param bugreportMode the mode that specifies other run time options; must be one of above
+     * @param listener callback for updates; optional
      */
-    int startBugreport(int fd, int bugreportMode);
+     void startBugreport(FileDescriptor bugreportFd, FileDescriptor screenshotFd, int bugreportMode,
+                         IDumpstateListener listener);
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8a05c43..47c4f62 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1701,7 +1701,7 @@
     printf("*** See dumpstate-board.txt entry ***\n");
 }
 
-static void ShowUsageAndExit(int exit_code = 1) {
+static void ShowUsage() {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
             "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1721,12 +1721,6 @@
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
             "  -v: prints the dumpstate header and exit\n");
-    exit(exit_code);
-}
-
-static void ExitOnInvalidArgs() {
-    fprintf(stderr, "invalid combination of args\n");
-    ShowUsageAndExit();
 }
 
 static void register_sig_handler() {
@@ -2523,17 +2517,18 @@
 
     switch (status) {
         case Dumpstate::RunStatus::OK:
-            return 0;
-            // TODO(b/111441001): Exit directly in the following cases.
+            exit(0);
         case Dumpstate::RunStatus::HELP:
-            ShowUsageAndExit(0 /* exit code */);
-            break;
+            ShowUsage();
+            exit(0);
         case Dumpstate::RunStatus::INVALID_INPUT:
-            ExitOnInvalidArgs();
-            break;
+            fprintf(stderr, "Invalid combination of args\n");
+            ShowUsage();
+            exit(1);
         case Dumpstate::RunStatus::ERROR:
-            exit(-1);
-            break;
+            exit(2);
+        default:
+            fprintf(stderr, "Unknown status: %d\n", status);
+            exit(2);
     }
-    return 0;
 }
diff --git a/include/input/Input.h b/include/input/Input.h
index 037270c..2c4a511 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -220,6 +220,27 @@
     POLICY_FLAG_PASS_TO_USER = 0x40000000,
 };
 
+/**
+ * Classifications of the current gesture, if available.
+ *
+ * The following values must be kept in sync with MotionEvent.java
+ */
+enum class MotionClassification : uint8_t {
+    /**
+     * No classification is available.
+     */
+    NONE = 0,
+    /**
+     * Too early to classify the current gesture. Need more events. Look for changes in the
+     * upcoming motion events.
+     */
+    AMBIGUOUS_GESTURE = 1,
+    /**
+     * The current gesture likely represents a user intentionally exerting force on the touchscreen.
+     */
+    DEEP_PRESS = 2,
+};
+
 /*
  * Pointer coordinate data.
  */
@@ -419,6 +440,8 @@
 
     inline void setButtonState(int32_t buttonState) { mButtonState = buttonState; }
 
+    inline MotionClassification getClassification() const { return mClassification; }
+
     inline int32_t getActionButton() const { return mActionButton; }
 
     inline void setActionButton(int32_t button) { mActionButton = button; }
@@ -582,6 +605,7 @@
             int32_t edgeFlags,
             int32_t metaState,
             int32_t buttonState,
+            MotionClassification classification,
             float xOffset,
             float yOffset,
             float xPrecision,
@@ -635,6 +659,7 @@
     int32_t mEdgeFlags;
     int32_t mMetaState;
     int32_t mButtonState;
+    MotionClassification mClassification;
     float mXOffset;
     float mYOffset;
     float mXPrecision;
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 5ec02b1..f6381f7 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -124,7 +124,9 @@
 
 
 #define CHECK_INTERFACE(interface, data, reply)                         \
-    if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }     \
+    do {                                                                \
+      if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }   \
+    } while (false)                                                     \
 
 
 // ----------------------------------------------------------------------
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 1b69dfd..05655c1 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -23,7 +23,11 @@
         "include_apex",
     ],
 
-    cflags: ["-Wall", "-Wextra", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
 
     srcs: [
         "ibinder.cpp",
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index ee7132f..f0d25f7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -87,6 +87,11 @@
     AStatus_getStatus;
     AStatus_isOk;
     AStatus_newOk;
+    ABinderProcess_joinThreadPool; # apex
+    ABinderProcess_setThreadPoolMaxThreadCount; # apex
+    ABinderProcess_startThreadPool; # apex
+    AServiceManager_addService; # apex
+    AServiceManager_getService; # apex
   local:
     *;
 };
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
index 1f74e43..3529b72 100755
--- a/libs/binder/ndk/scripts/init_map.sh
+++ b/libs/binder/ndk/scripts/init_map.sh
@@ -10,6 +10,10 @@
     grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
     grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
 } | sort | uniq | awk '{ print "    " $0 ";"; }'
+{
+    grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
+    grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
+} | sort | uniq | awk '{ print "    " $0 "; # apex"; }'
 echo "  local:"
 echo "    *;"
 echo "};"
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 369f523..928ef95 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -31,6 +31,7 @@
 
 enum class Tag : uint32_t {
     CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_WITH_SURFACE_PARENT,
     CLEAR_LAYER_FRAME_STATS,
     GET_LAYER_FRAME_STATS,
     LAST = GET_LAYER_FRAME_STATS,
@@ -56,6 +57,18 @@
                                                                             handle, gbp);
     }
 
+    status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height,
+                                     PixelFormat format, uint32_t flags,
+                                     const sp<IGraphicBufferProducer>& parent, int32_t windowType,
+                                     int32_t ownerUid, sp<IBinder>* handle,
+                                     sp<IGraphicBufferProducer>* gbp) override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT,
+                                                                   name, width, height, format,
+                                                                   flags, parent, windowType,
+                                                                   ownerUid, handle, gbp);
+    }
+
     status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
         return callRemote<decltype(
                 &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS,
@@ -86,6 +99,8 @@
     switch (tag) {
         case Tag::CREATE_SURFACE:
             return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
+        case Tag::CREATE_WITH_SURFACE_PARENT:
+            return callLocal(data, reply, &ISurfaceComposerClient::createWithSurfaceParent);
         case Tag::CLEAR_LAYER_FRAME_STATS:
             return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
         case Tag::GET_LAYER_FRAME_STATS:
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6c39d6f..8b9e4d7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -977,6 +977,29 @@
     return s;
 }
 
+sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w,
+                                                                  uint32_t h, PixelFormat format,
+                                                                  uint32_t flags, Surface* parent,
+                                                                  int32_t windowType,
+                                                                  int32_t ownerUid) {
+    sp<SurfaceControl> sur;
+    status_t err = mStatus;
+
+    if (mStatus == NO_ERROR) {
+        sp<IBinder> handle;
+        sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer();
+        sp<IGraphicBufferProducer> gbp;
+
+        err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp, windowType,
+                                               ownerUid, &handle, &gbp);
+        ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
+        if (err == NO_ERROR) {
+            return new SurfaceControl(this, handle, gbp, true /* owned */);
+        }
+    }
+    return nullptr;
+}
+
 status_t SurfaceComposerClient::createSurfaceChecked(
         const String8& name,
         uint32_t w,
@@ -1132,6 +1155,7 @@
     return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
                                                                             timestamp, outStats);
 }
+
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 56ca197..f443df8 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -58,6 +58,16 @@
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
+    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                             PixelFormat format, uint32_t flags,
+                                             const sp<IGraphicBufferProducer>& parent,
+                                             int32_t windowType, int32_t ownerUid,
+                                             sp<IBinder>* handle,
+                                             sp<IGraphicBufferProducer>* gbp) = 0;
+
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0;
 
     /*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e0cbb70..f16f781 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -168,15 +168,27 @@
     );
 
     status_t createSurfaceChecked(
-            const String8& name,// name of the surface
-            uint32_t w,         // width in pixel
-            uint32_t h,         // height in pixel
-            PixelFormat format, // pixel-format desired
+            const String8& name, // name of the surface
+            uint32_t w,          // width in pixel
+            uint32_t h,          // height in pixel
+            PixelFormat format,  // pixel-format desired
             sp<SurfaceControl>* outSurface,
-            uint32_t flags = 0, // usage flags
+            uint32_t flags = 0,               // usage flags
             SurfaceControl* parent = nullptr, // parent
             int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            int32_t ownerUid = -1 // UID of the task
+            int32_t ownerUid = -1    // UID of the task
+    );
+
+    //! Create a surface
+    sp<SurfaceControl> createWithSurfaceParent(
+            const String8& name,       // name of the surface
+            uint32_t w,                // width in pixel
+            uint32_t h,                // height in pixel
+            PixelFormat format,        // pixel-format desired
+            uint32_t flags = 0,        // usage flags
+            Surface* parent = nullptr, // parent
+            int32_t windowType = -1,   // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1      // UID of the task
     );
 
     //! Create a virtual display
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a558970..db86c8e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -234,6 +234,7 @@
         int32_t edgeFlags,
         int32_t metaState,
         int32_t buttonState,
+        MotionClassification classification,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -250,6 +251,7 @@
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
     mButtonState = buttonState;
+    mClassification = classification;
     mXOffset = xOffset;
     mYOffset = yOffset;
     mXPrecision = xPrecision;
@@ -270,6 +272,7 @@
     mEdgeFlags = other->mEdgeFlags;
     mMetaState = other->mMetaState;
     mButtonState = other->mButtonState;
+    mClassification = other->mClassification;
     mXOffset = other->mXOffset;
     mYOffset = other->mYOffset;
     mXPrecision = other->mXPrecision;
@@ -451,6 +454,7 @@
     mEdgeFlags = parcel->readInt32();
     mMetaState = parcel->readInt32();
     mButtonState = parcel->readInt32();
+    mClassification = static_cast<MotionClassification>(parcel->readByte());
     mXOffset = parcel->readFloat();
     mYOffset = parcel->readFloat();
     mXPrecision = parcel->readFloat();
@@ -501,6 +505,7 @@
     parcel->writeInt32(mEdgeFlags);
     parcel->writeInt32(mMetaState);
     parcel->writeInt32(mButtonState);
+    parcel->writeByte(static_cast<int8_t>(mClassification));
     parcel->writeFloat(mXOffset);
     parcel->writeFloat(mYOffset);
     parcel->writeFloat(mXPrecision);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index f33b210..0ddee44 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -1112,6 +1112,7 @@
             msg->body.motion.edgeFlags,
             msg->body.motion.metaState,
             msg->body.motion.buttonState,
+            MotionClassification::NONE,
             msg->body.motion.xOffset,
             msg->body.motion.yOffset,
             msg->body.motion.xPrecision,
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 99f83ba..e4c1514 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -260,7 +260,7 @@
     event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
             AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
-            X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+            MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
             ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
             2, pointerProperties, pointerCoords);
 
@@ -572,8 +572,11 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
+    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
+            0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
+            AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+            0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index af97c34..3c67542 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -90,7 +90,8 @@
 
     MotionEvent* event = new MotionEvent();
     PointerCoords coords;
-    PointerProperties properties[1];
+    constexpr size_t pointerCount = 1;
+    PointerProperties properties[pointerCount];
 
     properties[0].id = DEFAULT_POINTER_ID;
     properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
@@ -98,8 +99,11 @@
     // First sample added separately with initialize
     coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
-    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+    event->initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
+            AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+            0 /*downTime*/, positions[0].time, pointerCount, properties, &coords);
 
     for (size_t i = 1; i < numSamples; i++) {
         coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 1da79a0..f973cba 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -85,4 +85,22 @@
     return false;
 }
 
+status_t SensorPrivacyManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        return IInterface::asBinder(service)->linkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t SensorPrivacyManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        return IInterface::asBinder(service)->unlinkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index 8826595..2546a68 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -34,6 +34,9 @@
     void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
     bool isSensorPrivacyEnabled();
 
+    status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+    status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
 private:
     Mutex mLock;
     sp<hardware::ISensorPrivacyManager> mService;
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index d259fef..069f0dc 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -158,6 +158,29 @@
 static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
 static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
 
+/**
+ * android.frameworks.bufferhub@1.0::BufferTraits.bufferInfo is an opaque handle. See
+ * https://cs.corp.google.com/android/frameworks/hardware/interfaces/bufferhub/1.0/types.hal for
+ * more details about android.frameworks.bufferhub@1.0::BufferTraits.
+ *
+ * This definition could be changed, but implementation of BufferHubService::buildBufferInfo
+ * (frameworks/native/services/bufferhub), VtsHalBufferHubV1_0TargetTest
+ * (frameworks/hardware/interfaces/bufferhub) and BufferHubBuffer::readBufferTraits (libui) will
+ * also need to be updated.
+ *
+ * It's definition should follow the following format:
+ * {
+ *   NumFds = 1,
+ *   NumInts = 3,
+ *   data[0] = Ashmem fd for BufferHubMetadata,
+ *   data[1] = buffer id,
+ *   data[2] = client state bit mask,
+ *   data[3] = user metadata size,
+ * }
+ */
+static constexpr int kBufferInfoNumFds = 1;
+static constexpr int kBufferInfoNumInts = 3;
+
 } // namespace BufferHubDefs
 
 } // namespace android
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index 72d210c..a4b81fe 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -34,6 +34,7 @@
     ],
     shared_libs: [
         "android.frameworks.bufferhub@1.0",
+        "libcrypto",
         "libcutils",
         "libhidlbase",
         "libhidltransport",
@@ -60,6 +61,7 @@
     shared_libs: [
         "android.frameworks.bufferhub@1.0",
         "libbufferhubservice",
+        "libcrypto",
         "libcutils",
         "libhidltransport",
         "libhwbinder",
diff --git a/services/bufferhub/BufferHubIdGenerator.cpp b/services/bufferhub/BufferHubIdGenerator.cpp
index 6444a03..2c12f0e 100644
--- a/services/bufferhub/BufferHubIdGenerator.cpp
+++ b/services/bufferhub/BufferHubIdGenerator.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <bufferhub/BufferHubIdGenerator.h>
+#include <log/log.h>
 
 namespace android {
 namespace frameworks {
@@ -22,20 +23,18 @@
 namespace V1_0 {
 namespace implementation {
 
-constexpr uint32_t BufferHubIdGenerator::kInvalidId;
-
 BufferHubIdGenerator& BufferHubIdGenerator::getInstance() {
     static BufferHubIdGenerator generator;
 
     return generator;
 }
 
-uint32_t BufferHubIdGenerator::getId() {
+int BufferHubIdGenerator::getId() {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
 
     do {
-        if (++mLastId >= std::numeric_limits<uint32_t>::max()) {
-            mLastId = kInvalidId + 1;
+        if (++mLastId >= std::numeric_limits<int>::max()) {
+            mLastId = 0;
         }
     } while (mIdsInUse.find(mLastId) != mIdsInUse.end());
 
@@ -43,15 +42,14 @@
     return mLastId;
 }
 
-bool BufferHubIdGenerator::freeId(uint32_t id) {
+void BufferHubIdGenerator::freeId(int id) {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
     auto iter = mIdsInUse.find(id);
     if (iter != mIdsInUse.end()) {
         mIdsInUse.erase(iter);
-        return true;
+    } else {
+        ALOGW("%s: Cannot free nonexistent id #%d", __FUNCTION__, id);
     }
-
-    return false;
 }
 
 } // namespace implementation
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 54796a2..ad49cd6 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -14,14 +14,18 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <iomanip>
+#include <random>
 #include <sstream>
 
 #include <android/hardware_buffer.h>
 #include <bufferhub/BufferHubService.h>
 #include <cutils/native_handle.h>
 #include <log/log.h>
+#include <openssl/hmac.h>
 #include <system/graphics-base.h>
+#include <ui/BufferHubDefs.h>
 
 using ::android::BufferHubDefs::MetadataHeader;
 using ::android::hardware::Void;
@@ -32,6 +36,13 @@
 namespace V1_0 {
 namespace implementation {
 
+BufferHubService::BufferHubService() {
+    std::mt19937_64 randomEngine;
+    randomEngine.seed(time(nullptr));
+
+    mKey = randomEngine();
+}
+
 Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& description,
                                               const uint32_t userMetadataSize,
                                               allocateBuffer_cb _hidl_cb) {
@@ -54,10 +65,12 @@
     std::lock_guard<std::mutex> lock(mClientSetMutex);
     mClientSet.emplace(client);
 
+    hidl_handle bufferInfo =
+            buildBufferInfo(node->id(), node->AddNewActiveClientsBitToMask(),
+                            node->user_metadata_size(), node->metadata().ashmem_fd());
     BufferTraits bufferTraits = {/*bufferDesc=*/description,
                                  /*bufferHandle=*/hidl_handle(node->buffer_handle()),
-                                 // TODO(b/116681016): return real data to client
-                                 /*bufferInfo=*/hidl_handle()};
+                                 /*bufferInfo=*/bufferInfo};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
              /*bufferTraits=*/bufferTraits);
@@ -66,27 +79,49 @@
 
 Return<void> BufferHubService::importBuffer(const hidl_handle& tokenHandle,
                                             importBuffer_cb _hidl_cb) {
-    if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts != 1) {
+    if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts <= 1) {
         // nullptr handle or wrong format
         _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
                  /*bufferTraits=*/{});
         return Void();
     }
 
-    uint32_t token = tokenHandle->data[0];
+    int tokenId = tokenHandle->data[0];
 
     wp<BufferClient> originClientWp;
     {
-        std::lock_guard<std::mutex> lock(mTokenMapMutex);
-        auto iter = mTokenMap.find(token);
+        std::lock_guard<std::mutex> lock(mTokenMutex);
+        auto iter = mTokenMap.find(tokenId);
         if (iter == mTokenMap.end()) {
-            // Invalid token
+            // Token Id not exist
+            ALOGD("%s: token #%d not found.", __FUNCTION__, tokenId);
             _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
                      /*bufferTraits=*/{});
             return Void();
         }
 
-        originClientWp = iter->second;
+        const std::vector<uint8_t>& tokenHMAC = iter->second.first;
+
+        int numIntsForHMAC = (int)ceil(tokenHMAC.size() * sizeof(uint8_t) / (double)sizeof(int));
+        if (tokenHandle->numInts - 1 != numIntsForHMAC) {
+            // HMAC size not match
+            ALOGD("%s: token #%d HMAC size not match. Expected: %d Actual: %d", __FUNCTION__,
+                  tokenId, numIntsForHMAC, tokenHandle->numInts - 1);
+            _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+                     /*bufferTraits=*/{});
+            return Void();
+        }
+
+        size_t hmacSize = tokenHMAC.size() * sizeof(uint8_t);
+        if (memcmp(tokenHMAC.data(), &tokenHandle->data[1], hmacSize) != 0) {
+            // HMAC not match
+            ALOGD("%s: token #%d HMAC not match.", __FUNCTION__, tokenId);
+            _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+                     /*bufferTraits=*/{});
+            return Void();
+        }
+
+        originClientWp = iter->second.second;
         mTokenMap.erase(iter);
     }
 
@@ -119,10 +154,12 @@
     HardwareBufferDescription bufferDesc;
     memcpy(&bufferDesc, &node->buffer_desc(), sizeof(HardwareBufferDescription));
 
+    hidl_handle bufferInfo =
+            buildBufferInfo(node->id(), clientStateMask, node->user_metadata_size(),
+                            node->metadata().ashmem_fd());
     BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
                                  /*bufferHandle=*/hidl_handle(node->buffer_handle()),
-                                 // TODO(b/116681016): return real data to client
-                                 /*bufferInfo=*/hidl_handle()};
+                                 /*bufferInfo=*/bufferInfo};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
              /*bufferTraits=*/bufferTraits);
@@ -225,9 +262,9 @@
     // Map from bufferId to tokenCount
     std::map<int, uint32_t> tokenCount;
     {
-        std::lock_guard<std::mutex> lock(mTokenMapMutex);
+        std::lock_guard<std::mutex> lock(mTokenMutex);
         for (auto iter = mTokenMap.begin(); iter != mTokenMap.end(); ++iter) {
-            sp<BufferClient> client = iter->second.promote();
+            sp<BufferClient> client = iter->second.second.promote();
             if (client != nullptr) {
                 const std::shared_ptr<BufferNode> node = client->getBufferNode();
                 auto mapIter = tokenCount.find(node->id());
@@ -262,21 +299,35 @@
 }
 
 hidl_handle BufferHubService::registerToken(const wp<BufferClient>& client) {
-    uint32_t token;
-    std::lock_guard<std::mutex> lock(mTokenMapMutex);
+    // Find next available token id
+    std::lock_guard<std::mutex> lock(mTokenMutex);
     do {
-        token = mTokenEngine();
-    } while (mTokenMap.find(token) != mTokenMap.end());
+        ++mLastTokenId;
+    } while (mTokenMap.find(mLastTokenId) != mTokenMap.end());
 
-    // native_handle_t use int[], so here need one slots to fit in uint32_t
-    native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1);
-    handle->data[0] = token;
+    std::array<uint8_t, EVP_MAX_MD_SIZE> hmac;
+    uint32_t hmacSize = 0U;
+
+    HMAC(/*evp_md=*/EVP_sha256(), /*key=*/&mKey, /*key_len=*/kKeyLen,
+         /*data=*/(uint8_t*)&mLastTokenId, /*data_len=*/mTokenIdSize,
+         /*out=*/hmac.data(), /*out_len=*/&hmacSize);
+
+    int numIntsForHMAC = (int)ceil(hmacSize / (double)sizeof(int));
+    native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1 + numIntsForHMAC);
+    handle->data[0] = mLastTokenId;
+    // Set all the the bits of last int to 0 since it might not be fully overwritten
+    handle->data[numIntsForHMAC] = 0;
+    memcpy(&handle->data[1], hmac.data(), hmacSize);
 
     // returnToken owns the native_handle_t* thus doing lifecycle management
     hidl_handle returnToken;
     returnToken.setTo(handle, /*shoudOwn=*/true);
 
-    mTokenMap.emplace(token, client);
+    std::vector<uint8_t> hmacVec;
+    hmacVec.resize(hmacSize);
+    memcpy(hmacVec.data(), hmac.data(), hmacSize);
+    mTokenMap.emplace(mLastTokenId, std::pair(hmacVec, client));
+
     return returnToken;
 }
 
@@ -290,11 +341,31 @@
     }
 }
 
+// Implementation of this function should be consistent with the definition of bufferInfo handle in
+// ui/BufferHubDefs.h.
+hidl_handle BufferHubService::buildBufferInfo(int bufferId, uint32_t clientBitMask,
+                                              uint32_t userMetadataSize, const int metadataFd) {
+    native_handle_t* infoHandle = native_handle_create(BufferHubDefs::kBufferInfoNumFds,
+                                                       BufferHubDefs::kBufferInfoNumInts);
+
+    infoHandle->data[0] = dup(metadataFd);
+    infoHandle->data[1] = bufferId;
+    // Use memcpy to convert to int without missing digit.
+    // TOOD(b/121345852): use bit_cast to unpack bufferInfo when C++20 becomes available.
+    memcpy(&infoHandle->data[2], &clientBitMask, sizeof(clientBitMask));
+    memcpy(&infoHandle->data[3], &userMetadataSize, sizeof(userMetadataSize));
+
+    hidl_handle bufferInfo;
+    bufferInfo.setTo(infoHandle, /*shouldOwn=*/true);
+
+    return bufferInfo;
+}
+
 void BufferHubService::removeTokenByClient(const BufferClient* client) {
-    std::lock_guard<std::mutex> lock(mTokenMapMutex);
+    std::lock_guard<std::mutex> lock(mTokenMutex);
     auto iter = mTokenMap.begin();
     while (iter != mTokenMap.end()) {
-        if (iter->second == client) {
+        if (iter->second.second == client) {
             auto oldIter = iter;
             ++iter;
             mTokenMap.erase(oldIter);
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index da19a6f..5106390 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -30,7 +30,7 @@
 
 // Allocates a new BufferNode.
 BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-                       uint64_t usage, size_t user_metadata_size, uint32_t id)
+                       uint64_t usage, size_t user_metadata_size, int id)
       : mId(id) {
     uint32_t out_stride = 0;
     // graphicBufferId is not used in GraphicBufferAllocator::allocate
@@ -73,12 +73,8 @@
     }
 
     // Free the id, if valid
-    if (id() != BufferHubIdGenerator::kInvalidId) {
-        if (BufferHubIdGenerator::getInstance().freeId(id())) {
-            ALOGI("%s: id #%u is freed.", __FUNCTION__, id());
-        } else {
-            ALOGE("%s: Cannot free nonexistent id #%u", __FUNCTION__, id());
-        }
+    if (mId >= 0) {
+        BufferHubIdGenerator::getInstance().freeId(mId);
     }
 }
 
diff --git a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
index b51fcda..ef7c077 100644
--- a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
+++ b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
@@ -28,30 +28,28 @@
 namespace V1_0 {
 namespace implementation {
 
-// A thread-safe incremental uint32_t id generator.
+// A thread-safe, non-negative, incremental, int id generator.
 class BufferHubIdGenerator {
 public:
-    // 0 is considered invalid
-    static constexpr uint32_t kInvalidId = 0U;
-
     // Get the singleton instance of this class
     static BufferHubIdGenerator& getInstance();
 
-    // Gets next available id. If next id is greater than std::numeric_limits<uint32_t>::max() (2 ^
-    // 32 - 1), it will try to get an id start from 1 again.
-    uint32_t getId();
+    // Gets next available id. If next id is greater than std::numeric_limits<int32_t>::max(), it
+    // will try to get an id start from 0 again.
+    int getId();
 
-    // Free a specific id. Return true on freed, false on not found.
-    bool freeId(uint32_t id);
+    // Free a specific id.
+    void freeId(int id);
 
 private:
     BufferHubIdGenerator() = default;
     ~BufferHubIdGenerator() = default;
 
+    // Start from -1 so all valid ids will be >= 0
+    int mLastId = -1;
+
     std::mutex mIdsInUseMutex;
-    // Start from kInvalidID to avoid generating it.
-    uint32_t mLastId = kInvalidId;
-    std::set<uint32_t> mIdsInUse GUARDED_BY(mIdsInUseMutex);
+    std::set<int> mIdsInUse GUARDED_BY(mIdsInUseMutex);
 };
 
 } // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index 255f329..23e664e 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
 #define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
 
+#include <map>
 #include <mutex>
-#include <random>
+#include <set>
+#include <vector>
 
 #include <android/frameworks/bufferhub/1.0/IBufferHub.h>
 #include <bufferhub/BufferClient.h>
@@ -39,6 +41,8 @@
 
 class BufferHubService : public IBufferHub {
 public:
+    BufferHubService();
+
     Return<void> allocateBuffer(const HardwareBufferDescription& description,
                                 const uint32_t userMetadataSize,
                                 allocateBuffer_cb _hidl_cb) override;
@@ -53,6 +57,10 @@
     void onClientClosed(const BufferClient* client);
 
 private:
+    // Helper function to build BufferTraits.bufferInfo handle
+    hidl_handle buildBufferInfo(int bufferId, uint32_t clientBitMask, uint32_t userMetadataSize,
+                                const int metadataFd);
+
     // Helper function to remove all the token belongs to a specific client.
     void removeTokenByClient(const BufferClient* client);
 
@@ -60,11 +68,19 @@
     std::mutex mClientSetMutex;
     std::set<wp<BufferClient>> mClientSet GUARDED_BY(mClientSetMutex);
 
-    // TODO(b/118180214): use a more secure implementation
-    std::mt19937 mTokenEngine;
-    // The mapping from token to the client creates it.
-    std::mutex mTokenMapMutex;
-    std::map<uint32_t, const wp<BufferClient>> mTokenMap GUARDED_BY(mTokenMapMutex);
+    // Token generation related
+    // A random number used as private key for HMAC
+    uint64_t mKey;
+    static constexpr size_t kKeyLen = sizeof(uint64_t);
+
+    std::mutex mTokenMutex;
+    // The first TokenId will be 1. TokenId could be negative.
+    int mLastTokenId GUARDED_BY(mTokenMutex) = 0;
+    static constexpr size_t mTokenIdSize = sizeof(int);
+    // A map from token id to the token-buffer_client pair. Using token id as the key to reduce
+    // looking up time
+    std::map<int, std::pair<std::vector<uint8_t>, const wp<BufferClient>>> mTokenMap
+            GUARDED_BY(mTokenMutex);
 };
 
 } // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index cf56c33..b7a195b 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -16,15 +16,14 @@
 public:
     // Allocates a new BufferNode.
     BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-               uint64_t usage, size_t user_metadata_size,
-               uint32_t id = BufferHubIdGenerator::kInvalidId);
+               uint64_t usage, size_t user_metadata_size, int id = -1);
 
     ~BufferNode();
 
     // Returns whether the object holds a valid metadata.
     bool IsValid() const { return metadata_.IsValid(); }
 
-    uint32_t id() const { return mId; }
+    int id() const { return mId; }
 
     size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
 
@@ -64,10 +63,10 @@
     // Metadata in shared memory.
     BufferHubMetadata metadata_;
 
-    // A system-unique id generated by bufferhub from 1 to std::numeric_limits<uint32_t>::max().
-    // BufferNodes not created by bufferhub will have id = 0, meaning "not specified".
-    // TODO(b/118891412): remove default id = 0 and update comments after pdx is no longer in use
-    const uint32_t mId = 0;
+    // A system-unique id generated by bufferhub from 0 to std::numeric_limits<int>::max().
+    // BufferNodes not created by bufferhub will have id < 0, meaning "not specified".
+    // TODO(b/118891412): remove default id = -1 and update comments after pdx is no longer in use
+    const int mId = -1;
 
     // The following variables are atomic variables in metadata_ that are visible
     // to Bn object and Bp objects. Please find more info in
diff --git a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
index fe01013..fb6de0d 100644
--- a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
+++ b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
@@ -15,25 +15,28 @@
 };
 
 TEST_F(BufferHubIdGeneratorTest, TestGenerateAndFreeID) {
-    uint32_t id = mIdGenerator->getId();
-    EXPECT_NE(id, BufferHubIdGenerator::kInvalidId);
+    int id = mIdGenerator->getId();
+    EXPECT_GE(id, 0);
 
-    EXPECT_TRUE(mIdGenerator->freeId(id));
-    EXPECT_FALSE(mIdGenerator->freeId(id));
+    mIdGenerator->freeId(id);
 }
 
 TEST_F(BufferHubIdGeneratorTest, TestGenerateUniqueIncrementalID) {
     // 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the
     // resulting IDs should still keep incresing.
-    const size_t kTestSize = 10U;
-    uint32_t ids[kTestSize];
-    for (size_t i = 0UL; i < kTestSize; ++i) {
+    const int kTestSize = 10;
+    int ids[kTestSize];
+    for (int i = 0; i < kTestSize; ++i) {
         ids[i] = mIdGenerator->getId();
-        EXPECT_NE(ids[i], BufferHubIdGenerator::kInvalidId);
+        EXPECT_GE(ids[i], 0);
         if (i >= 1) {
             EXPECT_GT(ids[i], ids[i - 1]);
         }
     }
+
+    for (int i = 0; i < kTestSize; ++i) {
+        mIdGenerator->freeId(ids[i]);
+    }
 }
 
 } // namespace
diff --git a/services/displayservice/include/displayservice/DisplayEventReceiver.h b/services/displayservice/include/displayservice/DisplayEventReceiver.h
index 5d569b6..042a054 100644
--- a/services/displayservice/include/displayservice/DisplayEventReceiver.h
+++ b/services/displayservice/include/displayservice/DisplayEventReceiver.h
@@ -45,7 +45,7 @@
     using FwkReceiver = ::android::DisplayEventReceiver;
 
     struct AttachedEvent : LooperCallback {
-        AttachedEvent(const sp<IEventCallback> &callback);
+        explicit AttachedEvent(const sp<IEventCallback> &callback);
         ~AttachedEvent();
 
         bool detach();
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 18c3ded..cf9d3c7 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -40,6 +40,7 @@
 #include <hardware_legacy/power.h>
 
 #include <android-base/stringprintf.h>
+#include <cutils/properties.h>
 #include <openssl/sha.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
@@ -108,6 +109,19 @@
     return strstr(name, "v4l-touch") == name;
 }
 
+/**
+ * Returns true if V4L devices should be scanned.
+ *
+ * The system property ro.input.video_enabled can be used to control whether
+ * EventHub scans and opens V4L devices. As V4L does not support multiple
+ * clients, EventHub effectively blocks access to these devices when it opens
+ * them. This property enables other clients to read these devices for testing
+ * and development.
+ */
+static bool isV4lScanningEnabled() {
+  return property_get_bool("ro.input.video_enabled", true /* default_value */);
+}
+
 static nsecs_t processEventTimestamp(const struct input_event& event) {
     // Use the time specified in the event instead of the current time
     // so that downstream code can get more accurate estimates of
@@ -237,9 +251,14 @@
     mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
     LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
             DEVICE_PATH, strerror(errno));
-    mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
-    LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
-            VIDEO_DEVICE_PATH, strerror(errno));
+    if (isV4lScanningEnabled()) {
+        mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
+        LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
+                VIDEO_DEVICE_PATH, strerror(errno));
+    } else {
+        mVideoWd = -1;
+        ALOGI("Video device scanning disabled");
+    }
 
     struct epoll_event eventItem;
     memset(&eventItem, 0, sizeof(eventItem));
@@ -1056,9 +1075,11 @@
     if(result < 0) {
         ALOGE("scan dir failed for %s", DEVICE_PATH);
     }
-    result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
-    if (result != OK) {
-        ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+    if (isV4lScanningEnabled()) {
+        result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+        if (result != OK) {
+            ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+        }
     }
     if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
         createVirtualKeyboardLocked();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 8e3aa5f..72b7969 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2691,7 +2691,7 @@
             event.initialize(args->deviceId, args->source, args->displayId,
                     args->action, args->actionButton,
                     args->flags, args->edgeFlags, args->metaState, args->buttonState,
-                    0, 0, args->xPrecision, args->yPrecision,
+                    args->classification, 0, 0, args->xPrecision, args->yPrecision,
                     args->downTime, args->eventTime,
                     args->pointerCount, args->pointerProperties, args->pointerCoords);
 
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 41f7dee..00390a7 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -37,7 +37,7 @@
 #include <unordered_map>
 
 #include "InputListener.h"
-#include "InputReporter.h"
+#include "InputReporterInterface.h"
 
 
 namespace android {
@@ -1185,7 +1185,7 @@
     void traceOutboundQueueLengthLocked(const sp<Connection>& connection);
     void traceWaitQueueLengthLocked(const sp<Connection>& connection);
 
-    sp<InputReporter> mReporter;
+    sp<InputReporterInterface> mReporter;
 };
 
 /* Enqueues and dispatches input events, endlessly. */
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index b4eb370..b349c73 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -71,8 +71,8 @@
 NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
         uint32_t source, int32_t displayId, uint32_t policyFlags,
         int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
-        int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
-        uint32_t pointerCount,
+        int32_t buttonState, MotionClassification classification,
+        int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime,
         const std::vector<TouchVideoFrame>& videoFrames) :
@@ -80,7 +80,7 @@
         displayId(displayId), policyFlags(policyFlags),
         action(action), actionButton(actionButton),
         flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
+        classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
         pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
         videoFrames(videoFrames) {
@@ -95,7 +95,7 @@
         source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags),
+        classification(other.classification), edgeFlags(other.edgeFlags),
         deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
         videoFrames(other.videoFrames) {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 33bf163..2b31f6e 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2834,7 +2834,8 @@
                 NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
-                        metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&releaseArgs);
@@ -2843,7 +2844,7 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
                 displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -2855,7 +2856,8 @@
                 buttonState |= actionButton;
                 NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS,
-                        actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        actionButton, 0, metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&pressArgs);
@@ -2869,7 +2871,8 @@
                 && (mSource == AINPUT_SOURCE_MOUSE)) {
             NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                    metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                    metaState, currentButtonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&hoverArgs);
@@ -2883,7 +2886,7 @@
             NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&scrollArgs);
@@ -3014,8 +3017,8 @@
 
         NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, 0, /* videoFrames */ {});
         getListener()->notifyMotion(&scrollArgs);
@@ -5413,7 +5416,7 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -6338,8 +6341,8 @@
         // Send up.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6352,8 +6355,8 @@
         // Send hover exit.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6368,7 +6371,8 @@
             // Send down.
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
-                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
+                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
@@ -6379,8 +6383,8 @@
         // Send move.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6395,8 +6399,8 @@
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
-                    mCurrentRawState.buttonState, 0,
-                    /* deviceTimestamp */ 0,
+                    mCurrentRawState.buttonState, MotionClassification::NONE,
+                    AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime, /* videoFrames */ {});
@@ -6407,8 +6411,8 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                mCurrentRawState.buttonState, MotionClassification::NONE,
+                AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6429,8 +6433,8 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6497,8 +6501,8 @@
     std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
             source, displayId, policyFlags,
-            action, actionButton, flags, metaState, buttonState, edgeFlags,
-            deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
+            action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
+            edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime, std::move(frames));
     getListener()->notifyMotion(&args);
 }
@@ -7422,9 +7426,9 @@
 
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
             AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
-            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-            0, 0, 0, /* videoFrames */ {});
+            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE,
+            AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+            &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {});
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/inputflinger/InputReporter.cpp b/services/inputflinger/InputReporter.cpp
index cf4220f..8d3153c 100644
--- a/services/inputflinger/InputReporter.cpp
+++ b/services/inputflinger/InputReporter.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
-#include "InputReporter.h"
+#include "InputReporterInterface.h"
 
 namespace android {
 
 // --- InputReporter ---
 
+class InputReporter : public InputReporterInterface {
+public:
+    void reportUnhandledKey(uint32_t sequenceNum) override;
+    void reportDroppedKey(uint32_t sequenceNum) override;
+};
+
 void InputReporter::reportUnhandledKey(uint32_t sequenceNum) {
   // do nothing
 }
@@ -28,7 +34,7 @@
   // do nothing
 }
 
-sp<InputReporter> createInputReporter() {
+sp<InputReporterInterface> createInputReporter() {
   return new InputReporter();
 }
 
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 2442cc0..53247a0 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -99,6 +99,10 @@
     int32_t flags;
     int32_t metaState;
     int32_t buttonState;
+    /**
+     * Classification of the current touch gesture
+     */
+    MotionClassification classification;
     int32_t edgeFlags;
     /**
      * A timestamp in the input device's time base, not the platform's.
@@ -120,7 +124,7 @@
     NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
             int32_t displayId, uint32_t policyFlags,
             int32_t action, int32_t actionButton, int32_t flags,
-            int32_t metaState, int32_t buttonState,
+            int32_t metaState, int32_t buttonState, MotionClassification classification,
             int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime,
diff --git a/services/inputflinger/include/InputReporter.h b/services/inputflinger/include/InputReporterInterface.h
similarity index 74%
rename from services/inputflinger/include/InputReporter.h
rename to services/inputflinger/include/InputReporterInterface.h
index c86dcda..906d7f2 100644
--- a/services/inputflinger/include/InputReporter.h
+++ b/services/inputflinger/include/InputReporterInterface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _UI_INPUT_REPORTER_H
-#define _UI_INPUT_REPORTER_H
+#ifndef _UI_INPUT_REPORTER_INTERFACE_H
+#define _UI_INPUT_REPORTER_INTERFACE_H
 
 #include <utils/RefBase.h>
 
@@ -25,9 +25,9 @@
  * The interface used by the InputDispatcher to report information about input events after
  * it is sent to the application, such as if a key is unhandled or dropped.
  */
-class InputReporter: public virtual RefBase {
+class InputReporterInterface : public virtual RefBase {
 protected:
-    virtual ~InputReporter() { }
+    virtual ~InputReporterInterface() { }
 
 public:
     // Report a key that was not handled by the system or apps.
@@ -35,19 +35,19 @@
     //   - The event was not handled and there is no fallback key; or
     //   - The event was not handled and it has a fallback key,
     //       but the fallback key was not handled.
-    virtual void reportUnhandledKey(uint32_t sequenceNum);
+    virtual void reportUnhandledKey(uint32_t sequenceNum) = 0;
 
     // Report a key that was dropped by InputDispatcher.
     // A key can be dropped for several reasons. See the enum
     // InputDispatcher::DropReason for details.
-    virtual void reportDroppedKey(uint32_t sequenceNum);
+    virtual void reportDroppedKey(uint32_t sequenceNum) = 0;
 };
 
 /*
  * Factory method for InputReporter.
  */
-sp<InputReporter> createInputReporter();
+sp<InputReporterInterface> createInputReporter();
 
 } // namespace android
 
-#endif // _UI_INPUT_REPORTER_H
+#endif // _UI_INPUT_REPORTER_INTERFACE_H
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 26f01b7..704c13a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -160,70 +160,70 @@
         pointerCoords[i].clear();
     }
 
+    // Some constants commonly used below
+    constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+    constexpr int32_t metaState = AMETA_NONE;
+    constexpr MotionClassification classification = MotionClassification::NONE;
+
     // Rejects undefined motion actions.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with undefined action.";
 
     // Rejects pointer down with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too small.";
 
     // Rejects pointer up with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 0, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with 0 pointers.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -233,20 +233,18 @@
 
     // Rejects motion events with invalid pointer ids.
     pointerProperties[0].id = -1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -255,10 +253,9 @@
     // Rejects motion events with duplicate pointer ids.
     pointerProperties[0].id = 1;
     pointerProperties[1].id = 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 2, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -460,7 +457,8 @@
     // Define a valid motion down event.
     event.initialize(DEVICE_ID, source, displayId,
             AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
-            AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+            AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+            /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
             /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
             pointerCoords);
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 9b2cd50..189ae36 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -35,6 +35,7 @@
 using namespace android::hardware::sensors::V1_0::implementation;
 using android::hardware::sensors::V2_0::ISensorsCallback;
 using android::hardware::sensors::V2_0::EventQueueFlagBits;
+using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
 using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
@@ -94,6 +95,8 @@
 SensorDevice::SensorDevice()
         : mHidlTransportErrors(20),
           mRestartWaiter(new HidlServiceRegistrationWaiter()),
+          mEventQueueFlag(nullptr),
+          mWakeLockQueueFlag(nullptr),
           mReconnecting(false) {
     if (!connectHidlService()) {
         return;
@@ -137,6 +140,11 @@
         hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
         mEventQueueFlag = nullptr;
     }
+
+    if (mWakeLockQueueFlag != nullptr) {
+        hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+        mWakeLockQueueFlag = nullptr;
+    }
 }
 
 bool SensorDevice::connectHidlService() {
@@ -198,10 +206,16 @@
                 SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
                 true /* configureEventFlagWord */);
 
+        hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
         hardware::EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
 
+        hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+        hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(),
+                                             &mWakeLockQueueFlag);
+
         CHECK(mSensors != nullptr && mEventQueue != nullptr &&
-                mWakeLockQueue != nullptr && mEventQueueFlag != nullptr);
+                mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
+                mWakeLockQueueFlag != nullptr);
 
         status_t status = StatusFromResult(checkReturn(mSensors->initialize(
                 *mEventQueue->getDesc(),
@@ -512,9 +526,12 @@
 }
 
 void SensorDevice::writeWakeLockHandled(uint32_t count) {
-    if (mSensors != nullptr && mSensors->supportsMessageQueues() &&
-            !mWakeLockQueue->write(&count)) {
-        ALOGW("Failed to write wake lock handled");
+    if (mSensors != nullptr && mSensors->supportsMessageQueues()) {
+        if (mWakeLockQueue->write(&count)) {
+            mWakeLockQueueFlag->wake(asBaseType(WakeLockQueueFlagBits::DATA_WRITTEN));
+        } else {
+            ALOGW("Failed to write wake lock handled");
+        }
     }
 }
 
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index e1024ac..2a69654 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -238,6 +238,7 @@
     std::unique_ptr<WakeLockQueue> mWakeLockQueue;
 
     hardware::EventFlag* mEventQueueFlag;
+    hardware::EventFlag* mWakeLockQueueFlag;
 
     std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
 
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4e4d7dd..4eafeac 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -176,7 +176,7 @@
 
     if (!blackOutLayer) {
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = needsFiltering(renderArea) || isFixedSize();
+        const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -597,8 +597,11 @@
     return true;
 }
 
-bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
-    return mNeedsFiltering || renderArea.needsFiltering();
+bool BufferLayer::needsFiltering() const {
+    const auto displayFrame = getBE().compositionInfo.hwc.displayFrame;
+    const auto sourceCrop = getBE().compositionInfo.hwc.sourceCrop;
+    return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
 }
 
 void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
@@ -623,7 +626,6 @@
      */
     const Rect bounds{computeBounds()}; // Rounds from FloatRect
 
-    ui::Transform t = getTransform();
     Rect win = bounds;
     const int bufferWidth = getBufferSize(s).getWidth();
     const int bufferHeight = getBufferSize(s).getHeight();
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index be16cf5..6eda20d 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -168,8 +168,8 @@
     const uint32_t mTextureName;
 
 private:
-    // needsLinearFiltering - true if this surface's state requires filtering
-    bool needsFiltering(const RenderArea& renderArea) const;
+    // Returns true if this layer requires filtering
+    bool needsFiltering() const;
 
     // drawing
     void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 4f6fb1c..0e447d8 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -95,6 +95,26 @@
                                  ownerUid, handle, gbp, &parent);
 }
 
+status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                         PixelFormat format, uint32_t flags,
+                                         const sp<IGraphicBufferProducer>& parent,
+                                         int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
+                                         sp<IGraphicBufferProducer>* gbp) {
+    if (mFlinger->authenticateSurfaceTexture(parent) == false) {
+        return BAD_VALUE;
+    }
+
+    const auto& layer = (static_cast<MonitoredProducer*>(parent.get()))->getLayer();
+    if (layer == nullptr) {
+        return BAD_VALUE;
+    }
+
+    sp<IBinder> parentHandle = layer->getHandle();
+
+    return createSurface(name, w, h, format, flags, parentHandle, windowType, ownerUid, handle,
+                         gbp);
+}
+
 status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
     sp<Layer> layer = getLayerUser(handle);
     if (layer == nullptr) {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index d0051de..0f5ee4c 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -58,6 +58,12 @@
             sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp);
 
+    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                             PixelFormat format, uint32_t flags,
+                                             const sp<IGraphicBufferProducer>& parent,
+                                             int32_t windowType, int32_t ownerUid,
+                                             sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp);
+
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
 
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;