Merge "SafetyNet logging from vendor."
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/Android.bp b/libs/gui/Android.bp
index d1c732b..3521e89 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -121,6 +121,7 @@
],
shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"android.hardware.graphics.common@1.1",
"libbase",
"libsync",
@@ -153,6 +154,7 @@
"BufferHubProducer.cpp",
],
exclude_shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"libbufferhub",
"libbufferhubqueue",
"libpdx_default_transport",
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/Android.bp b/libs/ui/Android.bp
index 956465c..d089bf6 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -77,6 +77,7 @@
],
shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
@@ -93,7 +94,6 @@
"libutils",
"libutilscallstack",
"liblog",
- "libpdx_default_transport", // TODO(b/112338294): Remove this once BufferHub moved to use Binder.
],
export_shared_lib_headers: [
@@ -121,6 +121,7 @@
"libnativewindow_headers",
],
exclude_shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"libpdx_default_transport",
],
},
@@ -148,9 +149,6 @@
"libhardware_headers",
"libui_headers",
],
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
cc_library_headers {
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 1184960..c70f188 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -14,150 +14,190 @@
* limitations under the License.
*/
-// We would eliminate the clang warnings introduced by libdpx.
-// TODO(b/112338294): Remove those once BufferHub moved to use Binder
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wdouble-promotion"
-#pragma clang diagnostic ignored "-Wgnu-case-range"
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#pragma clang diagnostic ignored "-Wpacked"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wswitch-enum"
-#pragma clang diagnostic ignored "-Wundefined-func-template"
-#pragma clang diagnostic ignored "-Wunused-template"
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/bufferhub_rpc.h>
-#pragma clang diagnostic pop
-
#include <poll.h>
#include <android-base/unique_fd.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <log/log.h>
#include <ui/BufferHubBuffer.h>
#include <ui/BufferHubDefs.h>
+#include <utils/Trace.h>
-using android::base::unique_fd;
-using android::dvr::BufferTraits;
-using android::dvr::DetachedBufferRPC;
-using android::dvr::NativeHandleWrapper;
-
-// TODO(b/112338294): Remove PDX dependencies from libui.
-using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
-using android::pdx::default_transport::ClientChannel;
-using android::pdx::default_transport::ClientChannelFactory;
+using ::android::base::unique_fd;
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::frameworks::bufferhub::V1_0::BufferHubStatus;
+using ::android::frameworks::bufferhub::V1_0::BufferTraits;
+using ::android::frameworks::bufferhub::V1_0::IBufferClient;
+using ::android::frameworks::bufferhub::V1_0::IBufferHub;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
namespace android {
-namespace {
-
-// TODO(b/112338294): Remove this string literal after refactoring BufferHub
-// to use Binder.
-static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kHighBitsMask;
-
-} // namespace
-
-BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
-
-BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
- : Client(ClientChannel::Create(std::move(mChannelHandle))) {}
-
-BufferHubClient::~BufferHubClient() {}
-
-bool BufferHubClient::IsValid() const {
- return IsConnected() && GetChannelHandle().valid();
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Create(uint32_t width, uint32_t height,
+ uint32_t layerCount, uint32_t format,
+ uint64_t usage, size_t userMetadataSize) {
+ auto buffer = std::unique_ptr<BufferHubBuffer>(
+ new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
+ return buffer->IsValid() ? std::move(buffer) : nullptr;
}
-LocalChannelHandle BufferHubClient::TakeChannelHandle() {
- if (IsConnected()) {
- return std::move(GetChannelHandle());
- } else {
- return {};
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Import(const native_handle_t* token) {
+ if (token == nullptr) {
+ ALOGE("%s: token cannot be nullptr!", __FUNCTION__);
+ return nullptr;
}
+
+ auto buffer = std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(token));
+ return buffer->IsValid() ? std::move(buffer) : nullptr;
}
BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
- uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
+ uint32_t format, uint64_t usage, size_t userMetadataSize) {
ATRACE_CALL();
- ALOGD("%s: width=%u height=%u layerCount=%u, format=%u usage=%" PRIx64 " mUserMetadataSize=%zu",
- __FUNCTION__, width, height, layerCount, format, usage, mUserMetadataSize);
+ ALOGD("%s: width=%u height=%u layerCount=%u, format=%u "
+ "usage=%" PRIx64 " mUserMetadataSize=%zu",
+ __FUNCTION__, width, height, layerCount, format, usage, userMetadataSize);
- auto status =
- mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
- usage, mUserMetadataSize);
- if (!status) {
- ALOGE("%s: Failed to create detached buffer: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- mClient.Close(-status.error());
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ if (bufferhub.get() == nullptr) {
+ ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+ return;
}
- const int ret = ImportGraphicBuffer();
- if (ret < 0) {
- ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
- mClient.Close(ret);
+ AHardwareBuffer_Desc aDesc = {width, height, layerCount, format,
+ usage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+ HardwareBufferDescription desc;
+ memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+ BufferHubStatus ret;
+ sp<IBufferClient> client;
+ BufferTraits bufferTraits;
+ IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& status, const auto& outClient,
+ const auto& traits) {
+ ret = status;
+ client = std::move(outClient);
+ bufferTraits = std::move(traits);
+ };
+
+ if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), alloc_cb)
+ .isOk()) {
+ ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__);
+ return;
+ } else if (ret != BufferHubStatus::NO_ERROR) {
+ ALOGE("%s: allocateBuffer failed with error %u.", __FUNCTION__, ret);
+ return;
+ } else if (client == nullptr) {
+ ALOGE("%s: allocateBuffer got null BufferClient.", __FUNCTION__);
+ return;
+ }
+
+ const int importRet = initWithBufferTraits(bufferTraits);
+ if (importRet < 0) {
+ ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+ client->close();
+ }
+ mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::BufferHubBuffer(const native_handle_t* token) {
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ if (bufferhub.get() == nullptr) {
+ ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+ return;
+ }
+
+ BufferHubStatus ret;
+ sp<IBufferClient> client;
+ BufferTraits bufferTraits;
+ IBufferHub::importBuffer_cb import_cb = [&](const auto& status, const auto& outClient,
+ const auto& traits) {
+ ret = status;
+ client = std::move(outClient);
+ bufferTraits = std::move(traits);
+ };
+
+ // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership
+ // transfer.
+ if (!bufferhub->importBuffer(hidl_handle(token), import_cb).isOk()) {
+ ALOGE("%s: importBuffer transaction failed!", __FUNCTION__);
+ return;
+ } else if (ret != BufferHubStatus::NO_ERROR) {
+ ALOGE("%s: importBuffer failed with error %u.", __FUNCTION__, ret);
+ return;
+ } else if (client == nullptr) {
+ ALOGE("%s: importBuffer got null BufferClient.", __FUNCTION__);
+ return;
+ }
+
+ const int importRet = initWithBufferTraits(bufferTraits);
+ if (importRet < 0) {
+ ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+ client->close();
+ }
+ mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::~BufferHubBuffer() {
+ // Close buffer client to avoid possible race condition: user could first duplicate and hold
+ // token with the original buffer gone, and then try to import the token. The close function
+ // will explicitly invalidate the token to avoid this.
+ if (mBufferClient != nullptr) {
+ if (!mBufferClient->close().isOk()) {
+ ALOGE("%s: close BufferClient transaction failed!", __FUNCTION__);
+ }
}
}
-BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
- : mClient(std::move(mChannelHandle)) {
- const int ret = ImportGraphicBuffer();
- if (ret < 0) {
- ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
- mClient.Close(ret);
- }
-}
-
-int BufferHubBuffer::ImportGraphicBuffer() {
+int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) {
ATRACE_CALL();
- auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
- if (!status) {
- ALOGE("%s: Failed to import GraphicBuffer: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- return -status.error();
+ if (bufferTraits.bufferInfo.getNativeHandle() == nullptr) {
+ ALOGE("%s: missing buffer info handle.", __FUNCTION__);
+ return -EINVAL;
}
- BufferTraits<LocalHandle> bufferTraits = status.take();
- if (bufferTraits.id() < 0) {
- ALOGE("%s: Received an invalid id!", __FUNCTION__);
- return -EIO;
+ if (bufferTraits.bufferHandle.getNativeHandle() == nullptr) {
+ ALOGE("%s: missing gralloc handle.", __FUNCTION__);
+ return -EINVAL;
}
- // Stash the buffer id to replace the value in mId.
- const int bufferId = bufferTraits.id();
+ int bufferId = bufferTraits.bufferInfo->data[1];
+ if (bufferId < 0) {
+ ALOGE("%s: Received an invalid (negative) id!", __FUNCTION__);
+ return -EINVAL;
+ }
- // Import the metadata.
- LocalHandle metadataHandle = bufferTraits.take_metadata_handle();
- unique_fd metadataFd(metadataHandle.Release());
- mMetadata = BufferHubMetadata::Import(std::move(metadataFd));
+ uint32_t clientBitMask;
+ memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[2], sizeof(clientBitMask));
+ if (clientBitMask == 0U) {
+ ALOGE("%s: Received a invalid client state mask!", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ // Import the metadata. Dup since hidl_handle owns the fd
+ unique_fd ashmemFd(dup(bufferTraits.bufferInfo->data[0]));
+ mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
if (!mMetadata.IsValid()) {
ALOGE("%s: invalid metadata.", __FUNCTION__);
- return -ENOMEM;
+ return -EINVAL;
}
- if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
- ALOGE("%s: metadata buffer too small: %zu, expected: %" PRIu64 ".", __FUNCTION__,
- mMetadata.metadata_size(), bufferTraits.metadata_size());
- return -ENOMEM;
+ uint32_t userMetadataSize;
+ memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[3], sizeof(userMetadataSize));
+ if (mMetadata.user_metadata_size() != userMetadataSize) {
+ ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__,
+ userMetadataSize, mMetadata.user_metadata_size());
+ return -EINVAL;
}
- size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
+ size_t metadataSize = static_cast<size_t>(mMetadata.metadata_size());
if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
return -EINVAL;
@@ -178,24 +218,14 @@
// Import the buffer: We only need to hold on the native_handle_t here so that
// GraphicBuffer instance can be created in future.
- mBufferHandle = bufferTraits.take_buffer_handle();
+ mBufferHandle = std::move(bufferTraits.bufferHandle);
+ memcpy(&mBufferDesc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc));
- // Populate buffer desc based on buffer traits.
- mBufferDesc.width = bufferTraits.width();
- mBufferDesc.height = bufferTraits.height();
- mBufferDesc.layers = bufferTraits.layer_count();
- mBufferDesc.format = bufferTraits.format();
- mBufferDesc.usage = bufferTraits.usage();
- mBufferDesc.stride = bufferTraits.stride();
- mBufferDesc.rfu0 = 0U;
- mBufferDesc.rfu1 = 0U;
-
- // If all imports succeed, replace the previous buffer and id.
mId = bufferId;
- mClientStateMask = bufferTraits.client_state_mask();
+ mClientStateMask = clientBitMask;
// TODO(b/112012161) Set up shared fences.
- ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, id(),
+ ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, mId,
buffer_state_->load(std::memory_order_acquire));
return 0;
}
@@ -225,7 +255,7 @@
int BufferHubBuffer::Post() {
uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
- uint32_t updated_buffer_state = (~mClientStateMask) & kHighBitsMask;
+ uint32_t updated_buffer_state = (~mClientStateMask) & BufferHubDefs::kHighBitsMask;
do {
if (!IsClientGained(current_buffer_state, mClientStateMask)) {
ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
@@ -283,24 +313,42 @@
return 0;
}
-int BufferHubBuffer::Poll(int timeoutMs) {
- ATRACE_CALL();
-
- pollfd p = {mClient.event_fd(), POLLIN, 0};
- return poll(&p, 1, timeoutMs);
+bool BufferHubBuffer::IsValid() const {
+ // TODO(b/68770788): check eventFd once implemented
+ return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
+ mMetadata.IsValid() && mBufferClient != nullptr;
}
-Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
- ATRACE_CALL();
- ALOGD("%s: id=%d.", __FUNCTION__, mId);
+// TODO(b/68770788): implement Poll() once we have event fd
+int BufferHubBuffer::Poll(int /* timeoutMs */) {
+ return -ENOSYS;
+}
- auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
-
- if (!statusOrHandle.ok()) {
- ALOGE("%s: Failed to duplicate buffer (id=%d): %s.", __FUNCTION__, mId,
- statusOrHandle.GetErrorMessage().c_str());
+native_handle_t* BufferHubBuffer::Duplicate() {
+ if (mBufferClient == nullptr) {
+ ALOGE("%s: missing BufferClient!", __FUNCTION__);
+ return nullptr;
}
- return statusOrHandle;
+
+ hidl_handle token;
+ BufferHubStatus ret;
+ IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+ token = std::move(outToken);
+ ret = status;
+ };
+
+ if (!mBufferClient->duplicate(dup_cb).isOk()) {
+ ALOGE("%s: duplicate transaction failed!", __FUNCTION__);
+ return nullptr;
+ } else if (ret != BufferHubStatus::NO_ERROR) {
+ ALOGE("%s: duplicate failed with error %u.", __FUNCTION__, ret);
+ return nullptr;
+ } else if (token.getNativeHandle() == nullptr) {
+ ALOGE("%s: duplicate got null token.", __FUNCTION__);
+ return nullptr;
+ }
+
+ return native_handle_clone(token.getNativeHandle());
}
} // namespace android
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 90dd391..44dfa95 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -17,73 +17,43 @@
#ifndef ANDROID_BUFFER_HUB_BUFFER_H_
#define ANDROID_BUFFER_HUB_BUFFER_H_
-// We would eliminate the clang warnings introduced by libdpx.
-// TODO(b/112338294): Remove those once BufferHub moved to use Binder
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wdouble-promotion"
-#pragma clang diagnostic ignored "-Wgnu-case-range"
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#pragma clang diagnostic ignored "-Wpacked"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wswitch-enum"
-#pragma clang diagnostic ignored "-Wundefined-func-template"
-#pragma clang diagnostic ignored "-Wunused-template"
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#include <pdx/client.h>
-#include <private/dvr/native_handle_wrapper.h>
-#pragma clang diagnostic pop
-
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
#include <android/hardware_buffer.h>
+#include <cutils/native_handle.h>
#include <ui/BufferHubDefs.h>
#include <ui/BufferHubMetadata.h>
namespace android {
-class BufferHubClient : public pdx::Client {
-public:
- BufferHubClient();
- virtual ~BufferHubClient();
- explicit BufferHubClient(pdx::LocalChannelHandle mChannelHandle);
-
- bool IsValid() const;
- pdx::LocalChannelHandle TakeChannelHandle();
-
- using pdx::Client::Close;
- using pdx::Client::event_fd;
- using pdx::Client::GetChannel;
- using pdx::Client::InvokeRemoteMethod;
-};
-
class BufferHubBuffer {
public:
- // Allocates a standalone BufferHubBuffer not associated with any producer consumer set.
+ // Allocates a standalone BufferHubBuffer.
static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
uint32_t layerCount, uint32_t format,
- uint64_t usage, size_t userMetadataSize) {
- return std::unique_ptr<BufferHubBuffer>(
- new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
- }
+ uint64_t usage, size_t userMetadataSize);
- // Imports the given channel handle to a BufferHubBuffer, taking ownership.
- static std::unique_ptr<BufferHubBuffer> Import(pdx::LocalChannelHandle mChannelHandle) {
- return std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(std::move(mChannelHandle)));
- }
+ // Imports the given token to a BufferHubBuffer. Not taking ownership of the token. Caller
+ // should close and destroy the token after calling this function regardless of output.
+ // TODO(b/122543147): use a movable wrapper for token
+ static std::unique_ptr<BufferHubBuffer> Import(const native_handle_t* token);
BufferHubBuffer(const BufferHubBuffer&) = delete;
void operator=(const BufferHubBuffer&) = delete;
+ virtual ~BufferHubBuffer();
+
// Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
- // bufferhubd share the same buffer id.
+ // BufferHub share the same buffer id.
int id() const { return mId; }
- // Returns the buffer description, which is guaranteed to be faithful values from bufferhubd.
+ // Returns the buffer description, which is guaranteed to be faithful values from BufferHub.
const AHardwareBuffer_Desc& desc() const { return mBufferDesc; }
- const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }
+ // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle
+ // after use.
+ native_handle_t* DuplicateHandle() {
+ return native_handle_clone(mBufferHandle.getNativeHandle());
+ }
// Returns the current value of MetadataHeader::buffer_state.
uint32_t buffer_state() {
@@ -96,12 +66,12 @@
size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
- // Returns true if the buffer holds an open PDX channels towards bufferhubd.
- bool IsConnected() const { return mClient.IsValid(); }
+ // Returns true if the BufferClient is still alive.
+ bool IsConnected() const { return mBufferClient->ping().isOk(); }
- // Returns true if the buffer holds an valid native buffer handle that's availble for the client
- // to read from and/or write into.
- bool IsValid() const { return mBufferHandle.IsValid(); }
+ // Returns true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask,
+ // valid metadata and valid buffer client
+ bool IsValid() const;
// Gains the buffer for exclusive write permission. Read permission is implied once a buffer is
// gained.
@@ -124,33 +94,27 @@
// current cycle of the usage of the buffer.
int Release();
- // Returns the event mask for all the events that are pending on this buffer (see sys/poll.h for
- // all possible bits).
- pdx::Status<int> GetEventMask(int events) {
- if (auto* channel = mClient.GetChannel()) {
- return channel->GetEventMask(events);
- } else {
- return pdx::ErrorStatus(EINVAL);
- }
- }
-
// Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
int Poll(int timeoutMs);
- // Creates a BufferHubBuffer client from an existing one. The new client will
- // share the same underlying gralloc buffer and ashmem region for metadata.
- pdx::Status<pdx::LocalChannelHandle> Duplicate();
+ // Creates a token that stands for this BufferHubBuffer client and could be used for Import to
+ // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
+ // gralloc buffer and ashmem region for metadata. Note that the caller owns the token and
+ // should free it after use.
+ // Returns a valid token on success, nullptr on failure.
+ // TODO(b/122543147): use a movable wrapper for token
+ native_handle_t* Duplicate();
private:
BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
uint64_t usage, size_t userMetadataSize);
- BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle);
+ BufferHubBuffer(const native_handle_t* token);
- int ImportGraphicBuffer();
+ int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits);
// Global id for the buffer that is consistent across processes.
- int mId = -1;
+ int mId = 0;
// Client state mask of this BufferHubBuffer object. It is unique amoung all
// clients/users of the buffer.
@@ -159,8 +123,8 @@
// Stores ground truth of the buffer.
AHardwareBuffer_Desc mBufferDesc;
- // Wrapps the gralloc buffer handle of this buffer.
- dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
+ // Wraps the gralloc buffer handle of this buffer.
+ hardware::hidl_handle mBufferHandle;
// An ashmem-based metadata object. The same shared memory are mapped to the
// bufferhubd daemon and all buffer clients.
@@ -170,8 +134,8 @@
std::atomic<uint32_t>* fence_state_ = nullptr;
std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
- // PDX backend.
- BufferHubClient mClient;
+ // HwBinder backend
+ sp<frameworks::bufferhub::V1_0::IBufferClient> mBufferClient;
};
} // namespace android
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/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index a670b3c..665469e 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -31,12 +31,14 @@
cc_test {
name: "GraphicBuffer_test",
header_libs: [
- "libbufferhub_headers",
"libdvr_headers",
"libnativewindow_headers",
],
shared_libs: [
- "libpdx_default_transport",
+ "android.frameworks.bufferhub@1.0",
+ "libcutils",
+ "libhidlbase",
+ "libhwbinder",
"libui",
"libutils",
],
@@ -47,7 +49,6 @@
cc_test {
name: "BufferHub_test",
header_libs: [
- "libbufferhub_headers",
"libdvr_headers",
"libnativewindow_headers",
],
@@ -60,7 +61,6 @@
"libhidlbase",
"libhwbinder",
"liblog",
- "libpdx_default_transport",
"libui",
"libutils"
],
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 69b9590..cd744cd 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,10 +16,9 @@
#define LOG_TAG "BufferHubBufferTest"
-#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
-#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <android/hardware_buffer.h>
#include <cutils/native_handle.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
@@ -29,36 +28,38 @@
namespace {
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::AnyClientPosted;
+using ::android::BufferHubDefs::IsBufferReleased;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::BufferHubDefs::kMetadataHeaderSize;
+using ::testing::IsNull;
+using ::testing::NotNull;
+
const int kWidth = 640;
const int kHeight = 480;
const int kLayerCount = 1;
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::AnyClientPosted;
-using BufferHubDefs::IsBufferReleased;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kFirstClientBitMask;
-using BufferHubDefs::kMetadataHeaderSize;
-using frameworks::bufferhub::V1_0::BufferHubStatus;
-using frameworks::bufferhub::V1_0::IBufferClient;
-using frameworks::bufferhub::V1_0::IBufferHub;
-using hardware::hidl_handle;
-using hardware::graphics::common::V1_2::HardwareBufferDescription;
-using hidl::base::V1_0::IBase;
-using pdx::LocalChannelHandle;
+const AHardwareBuffer_Desc kDesc = {kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+const size_t kUserMetadataSize = 1;
class BufferHubBufferTest : public ::testing::Test {
protected:
void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
};
+bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) {
+ // Not comparing stride because it's unknown before allocation
+ return desc.format == other.format && desc.height == other.height &&
+ desc.layers == other.layers && desc.usage == other.usage && desc.width == other.width;
+}
+
class BufferHubBufferStateTransitionTest : public BufferHubBufferTest {
protected:
void SetUp() override {
@@ -78,91 +79,126 @@
void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
b1ClientMask = b1->client_state_mask();
ASSERT_NE(b1ClientMask, 0U);
- auto statusOrHandle = b1->Duplicate();
- ASSERT_TRUE(statusOrHandle);
- LocalChannelHandle h2 = statusOrHandle.take();
- b2 = BufferHubBuffer::Import(std::move(h2));
+
+ native_handle_t* token = b1->Duplicate();
+ ASSERT_THAT(token, NotNull());
+
+ // TODO(b/122543147): use a movalbe wrapper for token
+ b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+ ASSERT_THAT(b2, NotNull());
+
b2ClientMask = b2->client_state_mask();
ASSERT_NE(b2ClientMask, 0U);
ASSERT_NE(b2ClientMask, b1ClientMask);
}
-TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
+TEST_F(BufferHubBufferTest, CreateBufferFails) {
// Buffer Creation will fail: BLOB format requires height to be 1.
auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
/*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize);
- EXPECT_FALSE(b1->IsConnected());
- EXPECT_FALSE(b1->IsValid());
+ EXPECT_THAT(b1, IsNull());
// Buffer Creation will fail: user metadata size too large.
auto b2 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
/*userMetadataSize=*/std::numeric_limits<size_t>::max());
- EXPECT_FALSE(b2->IsConnected());
- EXPECT_FALSE(b2->IsValid());
+ EXPECT_THAT(b2, IsNull());
// Buffer Creation will fail: user metadata size too large.
const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize;
auto b3 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
userMetadataSize);
- EXPECT_FALSE(b3->IsConnected());
- EXPECT_FALSE(b3->IsValid());
+ EXPECT_THAT(b3, IsNull());
}
-TEST_F(BufferHubBufferTest, CreateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, CreateBuffer) {
auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
EXPECT_TRUE(b1->IsConnected());
EXPECT_TRUE(b1->IsValid());
- EXPECT_NE(b1->id(), 0);
+ EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc));
+ EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
}
-TEST_F(BufferHubBufferTest, DuplicateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
kUserMetadataSize);
- int id1 = b1->id();
- uint32_t bufferStateMask1 = b1->client_state_mask();
- EXPECT_NE(bufferStateMask1, 0U);
+ ASSERT_THAT(b1, NotNull());
EXPECT_TRUE(b1->IsValid());
- EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
- auto statusOrHandle = b1->Duplicate();
- EXPECT_TRUE(statusOrHandle);
+ native_handle_t* token = b1->Duplicate();
+ EXPECT_TRUE(token);
// The detached buffer should still be valid.
EXPECT_TRUE(b1->IsConnected());
EXPECT_TRUE(b1->IsValid());
- // Gets the channel handle for the duplicated buffer.
- LocalChannelHandle h2 = statusOrHandle.take();
- EXPECT_TRUE(h2.valid());
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
- std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
- EXPECT_FALSE(h2.valid());
- ASSERT_TRUE(b2 != nullptr);
+ ASSERT_THAT(b2, NotNull());
EXPECT_TRUE(b2->IsValid());
- EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
- int id2 = b2->id();
- uint32_t bufferStateMask2 = b2->client_state_mask();
- EXPECT_NE(bufferStateMask2, 0U);
+ EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc()));
+ EXPECT_EQ(b1->user_metadata_size(), b2->user_metadata_size());
// These two buffer instances are based on the same physical buffer under the
// hood, so they should share the same id.
- EXPECT_EQ(id1, id2);
+ EXPECT_EQ(b1->id(), b2->id());
// We use client_state_mask() to tell those two instances apart.
- EXPECT_NE(bufferStateMask1, bufferStateMask2);
+ EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
// Both buffer instances should be in released state currently.
EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
+}
- // TODO(b/112338294): rewrite test after migration
- return;
+TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
+ EXPECT_TRUE(b1->IsValid());
+
+ native_handle_t* token = b1->Duplicate();
+ EXPECT_TRUE(token);
+
+ // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid
+ b1.reset();
+
+ // TODO(b/122543147): use a movalbe wrapper for token
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+
+ // Import should fail with INVALID_TOKEN
+ EXPECT_THAT(b2, IsNull());
+}
+
+// nullptr must not crash the service
+TEST_F(BufferHubBufferTest, ImportNullToken) {
+ auto b1 = BufferHubBuffer::Import(nullptr);
+ EXPECT_THAT(b1, IsNull());
+}
+
+// TODO(b/118180214): remove the comment after ag/5856474 landed
+// This test has a very little chance to fail (number of existing tokens / 2 ^ 32)
+TEST_F(BufferHubBufferTest, ImportInvalidToken) {
+ native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1);
+ token->data[0] = 0;
+
+ auto b1 = BufferHubBuffer::Import(token);
+ native_handle_delete(token);
+
+ EXPECT_THAT(b1, IsNull());
}
TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
@@ -357,13 +393,20 @@
std::unique_ptr<BufferHubBuffer> b1 =
BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
ASSERT_EQ(b1->Gain(), 0);
// Create a consumer of the buffer and test if the consumer can acquire the
// buffer if producer posts.
- auto statusOrHandle = b1->Duplicate();
- ASSERT_TRUE(statusOrHandle);
- std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take()));
+ // TODO(b/122543147): use a movalbe wrapper for token
+ native_handle_t* token = b1->Duplicate();
+ ASSERT_TRUE(token);
+
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+
+ ASSERT_THAT(b2, NotNull());
ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
ASSERT_EQ(b1->Post(), 0);
@@ -380,13 +423,20 @@
// Create a consumer of the buffer and test if the consumer can acquire the
// buffer if producer posts.
- auto statusOrHandle = b1->Duplicate();
- ASSERT_TRUE(statusOrHandle);
- std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take()));
+ // TODO(b/122543147): use a movalbe wrapper for token
+ native_handle_t* token = b1->Duplicate();
+ ASSERT_TRUE(token);
+
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+
+ ASSERT_THAT(b2, NotNull());
ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
EXPECT_EQ(b2->Acquire(), 0);
}
} // namespace
+
} // namespace android
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 81ab3ac..5b46454 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -39,7 +39,7 @@
std::unique_ptr<BufferHubBuffer> b1 =
BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
kTestUsage, /*userMetadataSize=*/0);
- EXPECT_NE(b1, nullptr);
+ ASSERT_NE(b1, nullptr);
EXPECT_TRUE(b1->IsValid());
sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1)));
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 487a604..ed5a992 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,7 +5,6 @@
#include <private/dvr/producer_buffer.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
-#include <ui/BufferHubBuffer.h>
#include <ui/BufferHubDefs.h>
#include <mutex>
@@ -20,9 +19,6 @@
return result; \
})()
-using android::BufferHubBuffer;
-using android::GraphicBuffer;
-using android::sp;
using android::BufferHubDefs::AnyClientAcquired;
using android::BufferHubDefs::AnyClientGained;
using android::BufferHubDefs::AnyClientPosted;
@@ -31,19 +27,15 @@
using android::BufferHubDefs::IsClientPosted;
using android::BufferHubDefs::IsClientReleased;
using android::BufferHubDefs::kFirstClientBitMask;
-using android::BufferHubDefs::kMetadataHeaderSize;
using android::dvr::ConsumerBuffer;
using android::dvr::ProducerBuffer;
-using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Status;
const int kWidth = 640;
const int kHeight = 480;
-const int kLayerCount = 1;
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
// Maximum number of consumers for the buffer that only has one producer in the
// test.
const size_t kMaxConsumerCount =
@@ -808,7 +800,7 @@
// TODO(b/112338294) rewrite test after migration
return;
- std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+ /* std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
std::unique_ptr<ConsumerBuffer> c =
ConsumerBuffer::Import(p->CreateConsumer());
@@ -876,49 +868,14 @@
EXPECT_TRUE(d->IsConnected());
EXPECT_TRUE(d->IsValid());
- EXPECT_EQ(d->id(), p_id);
-}
-
-TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) {
- // Buffer Creation will fail: BLOB format requires height to be 1.
- auto b1 = BufferHubBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
- /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
- kUserMetadataSize);
-
- EXPECT_FALSE(b1->IsConnected());
- EXPECT_FALSE(b1->IsValid());
-
- // Buffer Creation will fail: user metadata size too large.
- auto b2 = BufferHubBuffer::Create(
- kWidth, kHeight, kLayerCount, kFormat, kUsage,
- /*user_metadata_size=*/std::numeric_limits<size_t>::max());
-
- EXPECT_FALSE(b2->IsConnected());
- EXPECT_FALSE(b2->IsValid());
-
- // Buffer Creation will fail: user metadata size too large.
- auto b3 = BufferHubBuffer::Create(
- kWidth, kHeight, kLayerCount, kFormat, kUsage,
- /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
- kMetadataHeaderSize);
-
- EXPECT_FALSE(b3->IsConnected());
- EXPECT_FALSE(b3->IsValid());
-}
-
-TEST_F(LibBufferHubTest, TestCreateBufferHubBuffer) {
- auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
- EXPECT_TRUE(b1->IsConnected());
- EXPECT_TRUE(b1->IsValid());
- EXPECT_NE(b1->id(), 0);
+ EXPECT_EQ(d->id(), p_id); */
}
TEST_F(LibBufferHubTest, TestDetach) {
// TODO(b/112338294) rewrite test after migration
return;
- std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
+ /* std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p1.get() != nullptr);
int p1_id = p1->id();
@@ -936,47 +893,5 @@
EXPECT_FALSE(h1.valid());
EXPECT_TRUE(b1->IsValid());
int b1_id = b1->id();
- EXPECT_EQ(b1_id, p1_id);
-}
-
-TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) {
- auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
- int b1_id = b1->id();
- EXPECT_TRUE(b1->IsValid());
- EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
- EXPECT_NE(b1->client_state_mask(), 0U);
-
- auto status_or_handle = b1->Duplicate();
- EXPECT_TRUE(status_or_handle);
-
- // The detached buffer should still be valid.
- EXPECT_TRUE(b1->IsConnected());
- EXPECT_TRUE(b1->IsValid());
-
- // Gets the channel handle for the duplicated buffer.
- LocalChannelHandle h2 = status_or_handle.take();
- EXPECT_TRUE(h2.valid());
-
- std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
- EXPECT_FALSE(h2.valid());
- ASSERT_TRUE(b2 != nullptr);
- EXPECT_TRUE(b2->IsValid());
- EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
- EXPECT_NE(b2->client_state_mask(), 0U);
-
- int b2_id = b2->id();
-
- // These two buffer instances are based on the same physical buffer under the
- // hood, so they should share the same id.
- EXPECT_EQ(b1_id, b2_id);
- // We use client_state_mask() to tell those two instances apart.
- EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
-
- // Both buffer instances should be in gained state.
- EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
- EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
-
- // TODO(b/112338294) rewrite test after migration
- return;
+ EXPECT_EQ(b1_id, p1_id); */
}
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 7997928..9af189a 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);
@@ -3131,7 +3131,9 @@
for (size_t i = 0; i < newHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = newHandles.itemAt(i);
- if (windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) {
+ // Set newFocusedWindowHandle to the top most focused window instead of the last one
+ if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
+ && windowHandle->getInfo()->visible) {
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
@@ -3175,7 +3177,7 @@
}
if (mFocusedDisplayId == displayId) {
- onFocusChangedLocked(newFocusedWindowHandle);
+ onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
}
}
@@ -3293,7 +3295,7 @@
// Sanity check
sp<InputWindowHandle> newFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
- onFocusChangedLocked(newFocusedWindowHandle);
+ onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
if (newFocusedWindowHandle == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
@@ -3374,11 +3376,6 @@
mLooper->wake();
}
-bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
- const sp<InputChannel>& toChannel) {
- return transferTouchFocus(fromChannel->getToken(), toChannel->getToken());
-}
-
bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
if (fromToken == toToken) {
#if DEBUG_FOCUS
@@ -3392,14 +3389,14 @@
sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken);
sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken);
-#if DEBUG_FOCUS
- ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
- fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
-#endif
if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
ALOGW("Cannot transfer focus because from or to window not found.");
return false;
}
+#if DEBUG_FOCUS
+ ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
+ fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
+#endif
if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
#if DEBUG_FOCUS
ALOGD("Cannot transfer focus because windows are on different displays.");
@@ -3860,11 +3857,14 @@
commandEntry->connection = connection;
}
-void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
- sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+ const sp<InputWindowHandle>& newFocus) {
+ sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
+ sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyFocusChangedLockedInterruptible);
- commandEntry->token = token;
+ commandEntry->oldToken = oldToken;
+ commandEntry->newToken = newToken;
}
void InputDispatcher::onANRLocked(
@@ -3926,9 +3926,10 @@
void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
CommandEntry* commandEntry) {
- sp<IBinder> token = commandEntry->token;
+ sp<IBinder> oldToken = commandEntry->oldToken;
+ sp<IBinder> newToken = commandEntry->newToken;
mLock.unlock();
- mPolicy->notifyFocusChanged(token);
+ mPolicy->notifyFocusChanged(oldToken, newToken);
mLock.lock();
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 970632e..49de6f3 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 {
@@ -217,7 +217,7 @@
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
- virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
+ virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -349,9 +349,6 @@
*/
virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
- virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
- const sp<InputChannel>& toChannel) = 0;
-
/* Registers input channels that may be used as targets for input events.
* If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE,
* the channel will receive a copy of all input events form the specific displayId.
@@ -416,8 +413,6 @@
virtual void setInputFilterEnabled(bool enabled);
virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
- virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
- const sp<InputChannel>& toChannel);
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
int32_t displayId);
@@ -633,7 +628,8 @@
uint32_t seq;
bool handled;
sp<InputChannel> inputChannel;
- sp<IBinder> token;
+ sp<IBinder> oldToken;
+ sp<IBinder> newToken;
};
// Generic queue implementation.
@@ -1163,7 +1159,8 @@
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
- void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
+ void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+ const sp<InputWindowHandle>& newFocus);
void onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -1190,7 +1187,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..3edec40 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,7 +63,7 @@
virtual void notifyInputChannelBroken(const sp<IBinder>&) {
}
- virtual void notifyFocusChanged(const sp<IBinder>&) {
+ virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) {
}
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
@@ -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);
@@ -517,7 +515,7 @@
sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
ADISPLAY_ID_DEFAULT);
- // Set focus application.
+ // Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
// Expect one focus window exist in display.
@@ -535,6 +533,32 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
+TEST_F(InputDispatcherTest, SetInputWindow_FocusPriority) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
+
+ // Set focused application.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ // Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
+ windowTop->setFocus();
+ windowSecond->setFocus();
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(windowTop);
+ inputWindowHandles.add(windowSecond);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Top focused window should receive event.
+ windowTop->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+ windowSecond->assertNoEvents();
+}
+
TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
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..e3b7f2f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -167,9 +167,11 @@
// from GLES
const uint32_t mTextureName;
+ bool mRefreshPending{false};
+
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;
@@ -184,8 +186,6 @@
// The texture used to draw the layer in GLES composition mode
mutable renderengine::Texture mTexture;
- bool mRefreshPending{false};
-
Rect getBufferSize(const State& s) const override;
};
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 5a61122..42021d1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -352,6 +352,14 @@
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
+void BufferQueueLayer::fakeVsync() {
+ mRefreshPending = false;
+ bool ignored = false;
+ latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+ usleep(16000);
+ releasePendingBuffer(systemTime());
+}
+
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
@@ -390,10 +398,7 @@
// If this layer is orphaned, then we run a fake vsync pulse so that
// dequeueBuffer doesn't block indefinitely.
if (isRemovedFromCurrentState()) {
- bool ignored = false;
- latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
- usleep(16000);
- releasePendingBuffer(systemTime());
+ fakeVsync();
} else {
mFlinger->signalLayerUpdate();
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index ae0b705..d7c3f6a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -137,6 +137,8 @@
// thread-safe
std::atomic<int32_t> mQueuedFrames{0};
std::atomic<bool> mSidebandStreamChanged{false};
+
+ void fakeVsync();
};
} // namespace android
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;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 1683982..bf925b2 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -67,7 +67,13 @@
}
void EventThreadConnection::requestNextVsync() {
- mEventThread->requestNextVsync(this);
+ ATRACE_NAME("requestNextVsync");
+ mEventThread->requestNextVsync(this, true);
+}
+
+void EventThreadConnection::requestNextVsyncForHWC() {
+ ATRACE_NAME("requestNextVsyncForHWC");
+ mEventThread->requestNextVsync(this, false);
}
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
@@ -184,16 +190,17 @@
}
}
-void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mResetIdleTimer) {
+void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
+ if (mResetIdleTimer && reset) {
+ ATRACE_NAME("resetIdleTimer");
mResetIdleTimer();
}
-
if (mResyncWithRateLimitCallback) {
mResyncWithRateLimitCallback();
}
+ std::lock_guard<std::mutex> lock(mMutex);
+
if (connection->count < 0) {
connection->count = 0;
mCondition.notify_all();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 66f54bd..e110488 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -68,6 +68,9 @@
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t count) override;
void requestNextVsync() override; // asynchronous
+ // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh
+ // in order to update the configs.
+ void requestNextVsyncForHWC();
// count >= 1 : continuous event. count is the vsync rate
// count == 0 : one-shot event that has not fired
@@ -105,7 +108,9 @@
virtual status_t registerDisplayEventConnection(
const sp<EventThreadConnection>& connection) = 0;
virtual void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) = 0;
- virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+ // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
+ virtual void requestNextVsync(const sp<EventThreadConnection>& connection,
+ bool resetIdleTimer) = 0;
};
namespace impl {
@@ -129,7 +134,8 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override;
- void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+ void requestNextVsync(const sp<EventThreadConnection>& connection,
+ bool resetIdleTimer) override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -166,6 +172,9 @@
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
+ // Acquires mutex and requests next vsync.
+ void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex);
+
// TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 36403cc..66f42bb 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -148,6 +148,10 @@
mEvents->requestNextVsync();
}
+void MessageQueue::invalidateForHWC() {
+ mEvents->requestNextVsyncForHWC();
+}
+
void MessageQueue::refresh() {
mHandler->dispatchRefresh();
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 24a3834..0bf00b0 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -91,6 +91,7 @@
virtual void waitMessage() = 0;
virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
virtual void invalidate() = 0;
+ virtual void invalidateForHWC() = 0;
virtual void refresh() = 0;
};
@@ -134,6 +135,9 @@
// sends INVALIDATE message at next VSYNC
void invalidate() override;
+
+ // sends INVALIDATE message at next VSYNC, without resetting the idle timer in the Scheduler
+ void invalidateForHWC();
// sends REFRESH message at next VSYNC
void refresh() override;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c363ba5..fec53af 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -238,6 +238,16 @@
mLayerHistory.incrementCounter();
}
+void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ mExpiredTimerCallback = expiredTimerCallback;
+}
+
+void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ mResetTimerCallback = resetTimerCallback;
+}
+
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
ATRACE_INT("FrameSkipCount", skipCount);
if (mSkipCount != skipCount) {
@@ -314,12 +324,12 @@
// TODO(b/113612090): This are current numbers from trial and error while running videos
// from YouTube at 24, 30, and 60 fps.
if (mean > 14 && mean < 18) {
- ATRACE_INT("FPS", 60);
+ ATRACE_INT("MediaFPS", 60);
} else if (mean > 31 && mean < 34) {
- ATRACE_INT("FPS", 30);
+ ATRACE_INT("MediaFPS", 30);
return;
} else if (mean > 39 && mean < 42) {
- ATRACE_INT("FPS", 24);
+ ATRACE_INT("MediaFPS", 24);
}
}
@@ -328,13 +338,19 @@
mIdleTimer->reset();
ATRACE_INT("ExpiredIdleTimer", 0);
}
+
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mResetTimerCallback) {
+ mResetTimerCallback();
+ }
}
void Scheduler::expiredTimerCallback() {
- // TODO(b/113612090): Each time a timer expired, we should record the information into
- // a circular buffer. Once this has happened a given amount (TBD) of times, we can comfortably
- // say that the device is sitting in idle.
- ATRACE_INT("ExpiredIdleTimer", 1);
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mExpiredTimerCallback) {
+ mExpiredTimerCallback();
+ ATRACE_INT("ExpiredIdleTimer", 1);
+ }
}
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9d7dd4d..3538f31 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -36,6 +36,9 @@
class Scheduler {
public:
+ using ExpiredIdleTimerCallback = std::function<void()>;
+ using ResetIdleTimerCallback = std::function<void()>;
+
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -111,6 +114,10 @@
const std::string layerName);
// Increments counter in the layer history to indicate that SF has started a new frame.
void incrementFrameCounter();
+ // Callback that gets invoked once the idle timer expires.
+ void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
+ // Callback that gets invoked once the idle timer is reset.
+ void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
@@ -173,6 +180,10 @@
// interval, a callback is fired. Set this variable to >0 to use this feature.
int64_t mSetIdleTimerMs = 0;
std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
+
+ std::mutex mCallbackLock;
+ ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
+ ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dc82b32..bd16d64 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -729,6 +729,11 @@
ALOGE("Run StartPropertySetThread failed!");
}
+ if (mUseScheduler) {
+ mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
+ mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
+ }
+
ALOGV("Done initializing");
}
@@ -934,14 +939,45 @@
return display->getActiveConfig();
}
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
+ ATRACE_NAME("setActiveConfigAsync");
+ postMessageAsync(new LambdaMessage([=] { setActiveConfigInternal(displayToken, mode); }));
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+ ATRACE_NAME("setActiveConfigSync");
+ postMessageSync(new LambdaMessage([&] { setActiveConfigInternal(displayToken, mode); }));
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) {
+ Vector<DisplayInfo> configs;
+ getDisplayConfigs(displayToken, &configs);
+ if (mode < 0 || mode >= static_cast<int>(configs.size())) {
+ ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
+ return;
+ }
+
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set active config %d for invalid display token %p", mode,
+ displayToken.get());
+ return;
+ }
if (display->isVirtual()) {
- ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ ALOGW("Attempt to set active config %d for virtual display", mode);
+ return;
+ }
+ int currentDisplayPowerMode = display->getPowerMode();
+ if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
+ // Don't change active config when in AoD.
return;
}
int currentMode = display->getActiveConfig();
if (mode == currentMode) {
+ // Don't update config if we are already running in the desired mode.
return;
}
@@ -950,29 +986,9 @@
display->setActiveConfig(mode);
getHwComposer().setActiveConfig(*displayId, mode);
-}
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
- postMessageSync(new LambdaMessage([&] {
- Vector<DisplayInfo> configs;
- getDisplayConfigs(displayToken, &configs);
- if (mode < 0 || mode >= static_cast<int>(configs.size())) {
- ALOGE("Attempt to set active config %d for display with %zu configs", mode,
- configs.size());
- return;
- }
- const auto display = getDisplayDevice(displayToken);
- if (!display) {
- ALOGE("Attempt to set active config %d for invalid display token %p", mode,
- displayToken.get());
- } else if (display->isVirtual()) {
- ALOGW("Attempt to set active config %d for virtual display", mode);
- } else {
- setActiveConfigInternal(display, mode);
- }
- }));
-
- return NO_ERROR;
+ ATRACE_INT("ActiveConfigMode", mode);
+ resyncToHardwareVsync(true);
}
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1382,6 +1398,49 @@
*compositorTiming = getBE().mCompositorTiming;
}
+void SurfaceFlinger::setRefreshRateTo(float newFps) {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || mBootStage != BootStage::FINISHED) {
+ return;
+ }
+ // TODO(b/113612090): There should be a message queue flush here. Because this esentially
+ // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
+ // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
+ // refresh cycle.
+
+ // Don't do any updating if the current fps is the same as the new one.
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+ const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+ if (currentVsyncPeriod == 0) {
+ return;
+ }
+ // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
+ // floating numbers.
+ const float currentFps = 1e9 / currentVsyncPeriod;
+ if (std::abs(currentFps - newFps) <= 1) {
+ return;
+ }
+
+ auto configs = getHwComposer().getConfigs(*displayId);
+ for (int i = 0; i < configs.size(); i++) {
+ const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
+ if (vsyncPeriod == 0) {
+ continue;
+ }
+ const float fps = 1e9 / vsyncPeriod;
+ // TODO(b/113612090): There should be a better way at determining which config
+ // has the right refresh rate.
+ if (std::abs(fps - newFps) <= 1) {
+ const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
+ if (!display) return;
+ // This is posted in async function to avoid deadlock when getDisplayDevice
+ // requires mStateLock.
+ setActiveConfigAsync(display, i);
+ ATRACE_INT("FPS", newFps);
+ }
+ }
+}
+
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
@@ -1413,7 +1472,7 @@
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- repaintEverything();
+ repaintEverythingForHWC();
}
void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
@@ -5177,6 +5236,11 @@
signalTransaction();
}
+void SurfaceFlinger::repaintEverythingForHWC() {
+ mRepaintEverything = true;
+ mEventQueue->invalidateForHWC();
+}
+
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ac730ab..eb7127e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -311,6 +311,9 @@
// force full composition on all displays
void repaintEverything();
+ // force full composition on all displays without resetting the scheduler idle timer.
+ void repaintEverythingForHWC();
+
surfaceflinger::Factory& getFactory() { return mFactory; }
// The CompositionEngine encapsulates all composition related interfaces and actions.
@@ -502,8 +505,10 @@
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays();
+ // setActiveConfigInternal() posted on a main thread for async execution
+ status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
// called on the main thread in response to setActiveConfig()
- void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode);
+ void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode);
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode);
@@ -763,6 +768,9 @@
void resyncWithRateLimit();
void getCompositorTiming(CompositorTiming* compositorTiming);
private:
+ // Sets the refresh rate to newFps by switching active configs, if they are available for
+ // the desired refresh rate.
+ void setRefreshRateTo(float newFps);
/* ------------------------------------------------------------------------
* Debugging & dumpsys
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index acbed51..2d26bb3 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -200,7 +200,7 @@
TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
// Signal that we want the next vsync event to be posted to the connection
- mThread->requestNextVsync(mConnection);
+ mThread->requestNextVsync(mConnection, false);
// EventThread should immediately request a resync.
EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index bb6e183..48d45fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -37,7 +37,7 @@
MOCK_METHOD1(registerDisplayEventConnection,
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
- MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+ MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index dc8d606..8c113e2 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -35,6 +35,7 @@
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
MOCK_METHOD0(invalidate, void());
+ MOCK_METHOD0(invalidateForHWC, void());
MOCK_METHOD0(refresh, void());
};