summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/atrace/atrace.rc7
-rw-r--r--cmds/dumpstate/dumpstate.cpp4
-rw-r--r--cmds/dumpsys/tests/dumpsys_test.cpp1
-rw-r--r--headers/media_plugin/media/openmax/OMX_IndexExt.h1
-rw-r--r--include/android/choreographer.h62
-rw-r--r--include/android/surface_control.h18
-rw-r--r--include/input/Input.h2
-rw-r--r--libs/arect/Android.bp7
-rw-r--r--libs/binder/Android.bp4
-rw-r--r--libs/binder/IServiceManager.cpp19
-rw-r--r--libs/binder/include/binder/IServiceManager.h6
-rw-r--r--libs/dumputils/Android.bp6
-rw-r--r--libs/dumputils/dump_utils.cpp45
-rw-r--r--libs/dumputils/include/dumputils/dump_utils.h2
-rw-r--r--libs/fakeservicemanager/ServiceManager.cpp4
-rw-r--r--libs/fakeservicemanager/ServiceManager.h4
-rw-r--r--libs/gui/SurfaceComposerClient.cpp7
-rw-r--r--libs/gui/WindowInfo.cpp8
-rw-r--r--libs/gui/aidl/android/gui/ISurfaceComposer.aidl5
-rw-r--r--libs/gui/include/gui/WindowInfo.h2
-rw-r--r--libs/gui/tests/EndToEndNativeInputTest.cpp49
-rw-r--r--libs/gui/tests/WindowInfo_test.cpp2
-rw-r--r--libs/input/Input.cpp71
-rw-r--r--libs/shaders/TEST_MAPPING10
-rw-r--r--libs/shaders/shaders.cpp9
-rw-r--r--libs/shaders/tests/Android.bp48
-rw-r--r--libs/shaders/tests/shaders_test.cpp98
-rw-r--r--libs/ui/Android.bp4
-rw-r--r--services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h2
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp6
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp52
-rw-r--r--services/powermanager/WorkSource.cpp12
-rw-r--r--services/powermanager/tests/Android.bp1
-rw-r--r--services/powermanager/tests/WorkSourceTest.cpp46
-rw-r--r--services/surfaceflinger/BufferLayer.cpp2
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp8
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h6
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Output.cpp1
-rw-r--r--services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp10
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp6
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp11
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp2
-rw-r--r--services/surfaceflinger/Layer.cpp35
-rw-r--r--services/surfaceflinger/Layer.h3
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.cpp5
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.h3
-rw-r--r--services/surfaceflinger/Scheduler/OneShotTimer.cpp23
-rw-r--r--services/surfaceflinger/Scheduler/VsyncSchedule.cpp2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp1
-rw-r--r--services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp18
-rw-r--r--services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp34
52 files changed, 720 insertions, 76 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 32ffe142cf..5267b0294c 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -294,12 +294,9 @@ on late-init
write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
-# Set up histogram triggers
- # rss_stat_throttled (bucket size == 512KB)
- chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+ # allow creating event triggers
chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
- write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
- write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+ chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 890c15f895..2b94b71a7f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1648,7 +1648,7 @@ static Dumpstate::RunStatus dumpstate() {
DumpPacketStats();
- RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
+ RunDumpsys("EBPF MAP STATS", {"connectivity", "trafficcontroller"});
DoKmsg();
@@ -2084,7 +2084,7 @@ Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
int timeout_failures = 0;
bool dalvik_found = false;
- const std::set<int> hal_pids = get_interesting_hal_pids();
+ const std::set<int> hal_pids = get_interesting_pids();
struct dirent* d;
while ((d = readdir(proc.get()))) {
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 49c1318945..f0c19b93ec 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -65,6 +65,7 @@ class ServiceManagerMock : public IServiceManager {
const sp<LocalRegistrationCallback>&));
MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
const sp<LocalRegistrationCallback>&));
+ MOCK_METHOD0(getServiceDebugInfo, std::vector<ServiceDebugInfo>());
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 07bd749f6c..0af40dd28e 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -104,6 +104,7 @@ typedef enum OMX_INDEXEXTTYPE {
OMX_IndexConfigLatency, /**< reference: OMX_PARAM_U32TYPE */
OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */
OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */
+ OMX_IndexConfigAndroidTunnelPeekLegacyMode, /**< reference: OMX_CONFIG_BOOLEANTYPE */
OMX_IndexExtOtherEndUnused,
/* Time configurations */
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 63aa7ff6c0..cd8e63dec2 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -16,6 +16,28 @@
/**
* @addtogroup Choreographer
+ *
+ * Choreographer coordinates the timing of frame rendering. This is the C version of the
+ * android.view.Choreographer object in Java.
+ *
+ * As of API level 33, apps can follow proper frame pacing and even choose a future frame to render.
+ * The API is used as follows:
+ * 1. The app posts an {@link AChoreographer_vsyncCallback} to Choreographer to run on the next
+ * frame.
+ * 2. The callback is called when it is the time to start the frame with an {@link
+ * AChoreographerFrameCallbackData} payload: information about multiple possible frame
+ * timelines.
+ * 3. Apps can choose a frame timeline from the {@link
+ * AChoreographerFrameCallbackData} payload, depending on the frame deadline they can meet when
+ * rendering the frame and their desired presentation time, and subsequently
+ * {@link ASurfaceTransaction_setFrameTimeline notify SurfaceFlinger}
+ * of the choice. Alternatively, for apps that do not choose a frame timeline, their frame would be
+ * presented at the earliest possible timeline.
+ * - The preferred frame timeline is the default frame
+ * timeline that the platform scheduled for the app, based on device configuration.
+ * 4. SurfaceFlinger attempts to follow the chosen frame timeline, by not applying transactions or
+ * latching buffers before the desired presentation time.
+ *
* @{
*/
@@ -47,7 +69,8 @@ typedef int64_t AVsyncId;
struct AChoreographerFrameCallbackData;
/**
- * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object, which contains
+ * various methods to extract frame information.
*/
typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
@@ -73,8 +96,9 @@ typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* dat
/**
* Prototype of the function that is called when a new frame is being rendered.
- * It's passed the frame data that should not outlive the callback, as well as the data pointer
- * provided by the application that registered a callback.
+ * It is called with \c callbackData describing multiple frame timelines, as well as the \c data
+ * pointer provided by the application that registered a callback. The \c callbackData does not
+ * outlive the callback.
*/
typedef void (*AChoreographer_vsyncCallback)(
const AChoreographerFrameCallbackData* callbackData, void* data);
@@ -110,7 +134,7 @@ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
__DEPRECATED_IN(29);
/**
- * Power a callback to be run on the next frame. The data pointer provided will
+ * Post a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
*
* Available since API level 29.
@@ -131,8 +155,10 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
uint32_t delayMillis) __INTRODUCED_IN(29);
/**
- * Posts a callback to run on the next frame. The data pointer provided will
+ * Posts a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
+ *
+ * Available since API level 33.
*/
void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
AChoreographer_vsyncCallback callback, void* data)
@@ -189,7 +215,10 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
__INTRODUCED_IN(30);
/**
- * The time in nanoseconds when the frame started being rendered.
+ * The time in nanoseconds at which the frame started being rendered.
+ *
+ * Note that this time should \b not be used to advance animation clocks.
+ * Instead, see AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos().
*/
int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
@@ -201,25 +230,38 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
/**
- * Get index of the platform-preferred FrameTimeline.
+ * Gets the index of the platform-preferred frame timeline.
+ * The preferred frame timeline is the default
+ * by which the platform scheduled the app, based on the device configuration.
*/
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
/**
- * The vsync ID token used to map Choreographer data.
+ * Gets the token used by the platform to identify the frame timeline at the given \c index.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
- * The time in nanoseconds which the frame at given index is expected to be presented.
+ * Gets the time in nanoseconds at which the frame described at the given \c index is expected to
+ * be presented. This time should be used to advance any animation clocks.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
- * The time in nanoseconds which the frame at given index needs to be ready by.
+ * Gets the time in nanoseconds at which the frame described at the given \c index needs to be
+ * ready by in order to be presented on time.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 9a36ecb537..6223ef7f82 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -597,20 +597,20 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction,
__INTRODUCED_IN(31);
/**
- * Sets the frame timeline to use in Surface Flinger.
+ * Sets the frame timeline to use in SurfaceFlinger.
*
- * A frame timeline should be chosen based on what frame deadline the application
- * can meet when rendering the frame and the application's desired present time.
- * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding
- * expected present time.
+ * A frame timeline should be chosen based on the frame deadline the application
+ * can meet when rendering the frame and the application's desired presentation time.
+ * By setting a frame timeline, SurfaceFlinger tries to present the frame at the corresponding
+ * expected presentation time.
*
* To receive frame timelines, a callback must be posted to Choreographer using
- * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the
+ * AChoreographer_postVsyncCallback(). The \c vsyncId can then be extracted from the
* callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId().
*
- * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to
- * the corresponding expected present time and deadline from the frame to be rendered. A stale or
- * invalid value will be ignored.
+ * \param vsyncId The vsync ID received from AChoreographer, setting the frame's presentation target
+ * to the corresponding expected presentation time and deadline from the frame to be rendered. A
+ * stale or invalid value will be ignored.
*/
void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
AVsyncId vsyncId) __INTRODUCED_IN(33);
diff --git a/include/input/Input.h b/include/input/Input.h
index b23a9518f7..e7d68fc349 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -837,6 +837,8 @@ protected:
std::vector<PointerCoords> mSamplePointerCoords;
};
+std::ostream& operator<<(std::ostream& out, const MotionEvent& event);
+
/*
* Focus events.
*/
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 41b34605f7..76e3e66749 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -39,9 +39,16 @@ ndk_headers {
cc_library_headers {
name: "libarect_headers",
+ vendor_available: true,
+ min_sdk_version: "29",
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
export_include_dirs: ["include"],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
}
cc_library_static {
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 63d87dae5a..d8d2cf2652 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -226,6 +226,10 @@ cc_library {
],
afdo: true,
+
+ header_abi_checker: {
+ diff_flags: ["-allow-adding-removing-weak-symbols"],
+ },
}
cc_defaults {
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ea2f8d2274..fd2d86857e 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -99,6 +99,8 @@ public:
status_t unregisterForNotifications(const String16& service,
const sp<AidlRegistrationCallback>& cb) override;
+
+ std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
return mTheRealServiceManager->getInterfaceDescriptor();
@@ -543,6 +545,23 @@ status_t ServiceManagerShim::unregisterForNotifications(const String16& name,
return OK;
}
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDebugInfo() {
+ std::vector<os::ServiceDebugInfo> serviceDebugInfos;
+ std::vector<IServiceManager::ServiceDebugInfo> ret;
+ if (Status status = mTheRealServiceManager->getServiceDebugInfo(&serviceDebugInfos);
+ !status.isOk()) {
+ ALOGW("%s Failed to get ServiceDebugInfo", __FUNCTION__);
+ return ret;
+ }
+ for (const auto& serviceDebugInfo : serviceDebugInfos) {
+ IServiceManager::ServiceDebugInfo retInfo;
+ retInfo.pid = serviceDebugInfo.debugPid;
+ retInfo.name = serviceDebugInfo.name;
+ ret.emplace_back(retInfo);
+ }
+ return ret;
+}
+
#ifndef __ANDROID__
// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
// The internal implementation of the AIDL interface android::os::IServiceManager calls into
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index bb55831ec2..413c97f349 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -134,6 +134,12 @@ public:
virtual status_t unregisterForNotifications(const String16& name,
const sp<LocalRegistrationCallback>& callback) = 0;
+
+ struct ServiceDebugInfo {
+ std::string name;
+ int pid;
+ };
+ virtual std::vector<ServiceDebugInfo> getServiceDebugInfo() = 0;
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
index acda402993..09fbdea0e8 100644
--- a/libs/dumputils/Android.bp
+++ b/libs/dumputils/Android.bp
@@ -26,6 +26,7 @@ cc_library {
shared_libs: [
"libbase",
+ "libbinder",
"libhidlbase",
"liblog",
"libutils",
@@ -33,7 +34,10 @@ cc_library {
srcs: ["dump_utils.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
export_include_dirs: [
"include",
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 29c788bca3..0f1a02a553 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -20,6 +20,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <dumputils/dump_utils.h>
#include <log/log.h>
@@ -52,8 +53,8 @@ static const char* debuggable_native_processes_to_dump[] = {
NULL,
};
-/* list of hal interface to dump containing process during native dumps */
-static const char* hal_interfaces_to_dump[] {
+/* list of hidl hal interface to dump containing process during native dumps */
+static const char* hidl_hal_interfaces_to_dump[] {
"android.hardware.audio@4.0::IDevicesFactory",
"android.hardware.audio@5.0::IDevicesFactory",
"android.hardware.audio@6.0::IDevicesFactory",
@@ -82,6 +83,11 @@ static const char* hal_interfaces_to_dump[] {
NULL,
};
+/* list of hal interface to dump containing process during native dumps */
+static const std::vector<std::string> aidl_interfaces_to_dump {
+ "android.hardware.camera.provider.ICameraProvider",
+};
+
/* list of extra hal interfaces to dump containing process during native dumps */
// This is filled when dumpstate is called.
static std::set<const std::string> extra_hal_interfaces_to_dump;
@@ -104,7 +110,7 @@ static void read_extra_hals_to_dump_from_property() {
// check if interface is included in either default hal list or extra hal list
bool should_dump_hal_interface(const std::string& interface) {
- for (const char** i = hal_interfaces_to_dump; *i; i++) {
+ for (const char** i = hidl_hal_interfaces_to_dump; *i; i++) {
if (interface == *i) {
return true;
}
@@ -130,14 +136,26 @@ bool should_dump_native_traces(const char* path) {
return false;
}
-std::set<int> get_interesting_hal_pids() {
+static void get_interesting_aidl_pids(std::set<int> &pids) {
+ using ServiceDebugInfo = android::IServiceManager::ServiceDebugInfo;
+ auto sm = android::defaultServiceManager();
+ std::vector<ServiceDebugInfo> serviceDebugInfos = sm->getServiceDebugInfo();
+ for (const auto & serviceDebugInfo : serviceDebugInfos) {
+ for (const auto &aidl_prefix : aidl_interfaces_to_dump) {
+ // Check for prefix match with aidl interface to dump
+ if (serviceDebugInfo.name.rfind(aidl_prefix, 0) == 0) {
+ pids.insert(serviceDebugInfo.pid);
+ }
+ }
+ }
+}
+
+static void get_interesting_hidl_pids(std::set<int> &pids) {
using android::hidl::manager::V1_0::IServiceManager;
using android::sp;
using android::hardware::Return;
sp<IServiceManager> manager = IServiceManager::getService();
- std::set<int> pids;
-
read_extra_hals_to_dump_from_property();
Return<void> ret = manager->debugDump([&](auto& hals) {
@@ -146,11 +164,9 @@ std::set<int> get_interesting_hal_pids() {
continue;
}
- if (!should_dump_hal_interface(info.interfaceName)) {
- continue;
+ if (should_dump_hal_interface(info.interfaceName)) {
+ pids.insert(info.pid);
}
-
- pids.insert(info.pid);
}
});
@@ -158,7 +174,14 @@ std::set<int> get_interesting_hal_pids() {
ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
}
- return pids; // whether it was okay or not
+ return;
+}
+
+std::set<int> get_interesting_pids() {
+ std::set<int> interesting_pids;
+ get_interesting_hidl_pids(interesting_pids);
+ get_interesting_aidl_pids(interesting_pids);
+ return interesting_pids;
}
bool IsZygote(int pid) {
diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h
index 25f712733a..7c5329d01b 100644
--- a/libs/dumputils/include/dumputils/dump_utils.h
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -21,7 +21,7 @@
bool should_dump_native_traces(const char* path);
-std::set<int> get_interesting_hal_pids();
+std::set<int> get_interesting_pids();
bool IsZygote(int pid);
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 61e4a98846..6c6d7f3641 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -94,4 +94,8 @@ status_t ServiceManager::unregisterForNotifications(const String16&,
return INVALID_OPERATION;
}
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManager::getServiceDebugInfo() {
+ std::vector<IServiceManager::ServiceDebugInfo> ret;
+ return ret;
+}
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 6d6e008c4f..e0af5d4ba8 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -20,6 +20,7 @@
#include <map>
#include <optional>
+#include <vector>
namespace android {
@@ -58,6 +59,9 @@ public:
status_t unregisterForNotifications(const String16& name,
const sp<LocalRegistrationCallback>& callback) override;
+
+ std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
+
private:
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 501f8cf15c..47d801a78d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1497,6 +1497,13 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe
releaseBufferIfOverwriting(*s);
+ if (buffer == nullptr) {
+ s->what &= ~layer_state_t::eBufferChanged;
+ s->bufferData = nullptr;
+ mContainsBuffer = false;
+ return *this;
+ }
+
std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
bufferData->buffer = buffer;
uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 804ce4fac0..4e966d1393 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -76,7 +76,7 @@ bool WindowInfo::operator==(const WindowInfo& info) const {
info.inputConfig == inputConfig && info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
- info.layoutParamsFlags == layoutParamsFlags;
+ info.layoutParamsFlags == layoutParamsFlags && info.isClone == isClone;
}
status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -124,7 +124,8 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
- parcel->writeStrongBinder(windowToken);
+ parcel->writeStrongBinder(windowToken) ?:
+ parcel->writeBool(isClone);
// clang-format on
return status;
}
@@ -175,7 +176,8 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) {
parcel->read(touchableRegion) ?:
parcel->readBool(&replaceTouchableRegionWithCrop) ?:
parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
- parcel->readNullableStrongBinder(&windowToken);
+ parcel->readNullableStrongBinder(&windowToken) ?:
+ parcel->readBool(&isClone);
// clang-format on
if (status != OK) {
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index a9977b0f45..b31b37bada 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -54,10 +54,11 @@ interface ISurfaceComposer {
*/
void setPowerMode(IBinder display, int mode);
- /* returns display statistics for a given display
+ /**
+ * Returns display statistics for a given display
* intended to be used by the media framework to properly schedule
* video frames */
- DisplayStatInfo getDisplayStats(IBinder display);
+ DisplayStatInfo getDisplayStats(@nullable IBinder display);
/**
* Get transactional state of given display.
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 0e1d25812e..169f7f022b 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -236,6 +236,8 @@ struct WindowInfo : public Parcelable {
void setInputConfig(ftl::Flags<InputConfig> config, bool value);
+ bool isClone = false;
+
void addTouchableRegion(const Rect& region);
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 262987fd27..c6cdeb7706 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -566,6 +566,55 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
bgSurface->expectTap(12, 24);
}
+TEST_F(InputSurfacesTest, touchable_region) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+ surface->mInputInfo.touchableRegion.set(Rect{19, 29, 21, 31});
+
+ surface->showAt(11, 22);
+
+ // A tap within the surface but outside the touchable region should not be sent to the surface.
+ injectTap(20, 30);
+ EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr);
+
+ injectTap(31, 52);
+ surface->expectTap(20, 30);
+}
+
+TEST_F(InputSurfacesTest, input_respects_touchable_region_offset_overflow) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(100, 100);
+
+ // Set the touchable region to the values at the limit of its corresponding type.
+ // Since the surface is offset from the origin, the touchable region will be transformed into
+ // display space, which would trigger an overflow or an underflow. Ensure that we are protected
+ // against such a situation.
+ fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+
+ fgSurface->showAt(100, 100);
+
+ // Expect no crash for overflow. The overflowed touchable region is ignored, so the background
+ // surface receives touch.
+ injectTap(112, 124);
+ bgSurface->expectTap(12, 24);
+}
+
+TEST_F(InputSurfacesTest, input_respects_scaled_touchable_region_overflow) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(0, 0);
+
+ fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+ fgSurface->showAt(0, 0);
+
+ fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+ // Expect no crash for overflow.
+ injectTap(12, 24);
+ fgSurface->expectTap(6, 12);
+}
+
// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index c51b244c50..99658ccd4b 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -71,6 +71,7 @@ TEST(WindowInfo, Parcelling) {
i.applicationInfo.name = "ApplicationFooBar";
i.applicationInfo.token = new BBinder();
i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD;
+ i.isClone = true;
Parcel p;
i.writeToParcel(&p);
@@ -101,6 +102,7 @@ TEST(WindowInfo, Parcelling) {
ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
ASSERT_EQ(i.applicationInfo, i2.applicationInfo);
+ ASSERT_EQ(i.isClone, i2.isClone);
}
TEST(InputApplicationInfo, Parcelling) {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index fe1754c78b..13ca9ecd35 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -22,7 +22,9 @@
#include <inttypes.h>
#include <string.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <cutils/compiler.h>
#include <gui/constants.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
@@ -542,7 +544,14 @@ void MotionEvent::setCursorPosition(float x, float y) {
}
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
- return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
+ if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
+ LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for " << *this;
+ }
+ const size_t position = getHistorySize() * getPointerCount() + pointerIndex;
+ if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
+ LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << *this;
+ }
+ return &mSamplePointerCoords[position];
}
float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
@@ -555,7 +564,18 @@ float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
size_t pointerIndex, size_t historicalIndex) const {
- return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
+ if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
+ LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for " << *this;
+ }
+ if (CC_UNLIKELY(historicalIndex < 0 || historicalIndex > getHistorySize())) {
+ LOG(FATAL) << __func__ << ": Invalid historical index " << historicalIndex << " for "
+ << *this;
+ }
+ const size_t position = historicalIndex * getPointerCount() + pointerIndex;
+ if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
+ LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << *this;
+ }
+ return &mSamplePointerCoords[position];
}
float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
@@ -903,6 +923,53 @@ PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source,
return out;
}
+std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
+ out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction());
+ if (event.getActionButton() != 0) {
+ out << ", actionButton=" << std::to_string(event.getActionButton());
+ }
+ const size_t pointerCount = event.getPointerCount();
+ for (size_t i = 0; i < pointerCount; i++) {
+ out << ", id[" << i << "]=" << event.getPointerId(i);
+ float x = event.getX(i);
+ float y = event.getY(i);
+ if (x != 0 || y != 0) {
+ out << ", x[" << i << "]=" << x;
+ out << ", y[" << i << "]=" << y;
+ }
+ int toolType = event.getToolType(i);
+ if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ out << ", toolType[" << i << "]=" << toolType;
+ }
+ }
+ if (event.getButtonState() != 0) {
+ out << ", buttonState=" << event.getButtonState();
+ }
+ if (event.getClassification() != MotionClassification::NONE) {
+ out << ", classification=" << motionClassificationToString(event.getClassification());
+ }
+ if (event.getMetaState() != 0) {
+ out << ", metaState=" << event.getMetaState();
+ }
+ if (event.getEdgeFlags() != 0) {
+ out << ", edgeFlags=" << event.getEdgeFlags();
+ }
+ if (pointerCount != 1) {
+ out << ", pointerCount=" << pointerCount;
+ }
+ if (event.getHistorySize() != 0) {
+ out << ", historySize=" << event.getHistorySize();
+ }
+ out << ", eventTime=" << event.getEventTime();
+ out << ", downTime=" << event.getDownTime();
+ out << ", deviceId=" << event.getDeviceId();
+ out << ", source=" << inputEventSourceToString(event.getSource());
+ out << ", displayId=" << event.getDisplayId();
+ out << ", eventId=" << event.getId();
+ out << "}";
+ return out;
+}
+
// --- FocusEvent ---
void FocusEvent::initialize(int32_t id, bool hasFocus) {
diff --git a/libs/shaders/TEST_MAPPING b/libs/shaders/TEST_MAPPING
new file mode 100644
index 0000000000..ad6514d201
--- /dev/null
+++ b/libs/shaders/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "librenderengine_test"
+ },
+ {
+ "name": "libshaders_test"
+ }
+ ]
+}
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 62745dc8d5..f80e93f6f8 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -469,12 +469,17 @@ std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(
float currentDisplayLuminanceNits, float maxLuminance, AHardwareBuffer* buffer,
aidl::android::hardware::graphics::composer3::RenderIntent renderIntent) {
std::vector<tonemap::ShaderUniform> uniforms;
- if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
+
+ const ui::Dataspace inputDataspace = linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN
+ ? linearEffect.inputDataspace
+ : linearEffect.fakeInputDataspace;
+
+ if (inputDataspace == linearEffect.outputDataspace) {
uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue<mat4>(mat4())});
uniforms.push_back(
{.name = "in_xyzToRgb", .value = buildUniformValue<mat4>(colorTransform)});
} else {
- ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace);
+ ColorSpace inputColorSpace = toColorSpace(inputDataspace);
ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
uniforms.push_back({.name = "in_rgbToXyz",
.value = buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ()))});
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
new file mode 100644
index 0000000000..cf671bcb7a
--- /dev/null
+++ b/libs/shaders/tests/Android.bp
@@ -0,0 +1,48 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+ name: "libshaders_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "shaders_test.cpp",
+ ],
+ header_libs: [
+ "libtonemap_headers",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.composer3-V1-ndk",
+ "android.hardware.graphics.common@1.2",
+ "libnativewindow",
+ ],
+ static_libs: [
+ "libarect",
+ "libgmock",
+ "libgtest",
+ "libmath",
+ "libshaders",
+ "libtonemap",
+ "libui-types",
+ ],
+}
diff --git a/libs/shaders/tests/shaders_test.cpp b/libs/shaders/tests/shaders_test.cpp
new file mode 100644
index 0000000000..d45fb246c7
--- /dev/null
+++ b/libs/shaders/tests/shaders_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "shaders/shaders.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <math/mat4.h>
+#include <tonemap/tonemap.h>
+#include <ui/ColorSpace.h>
+#include <cmath>
+
+namespace android {
+
+using testing::Contains;
+using testing::HasSubstr;
+
+struct ShadersTest : public ::testing::Test {};
+
+namespace {
+
+MATCHER_P2(UniformEq, name, value, "") {
+ return arg.name == name && arg.value == value;
+}
+
+template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
+std::vector<uint8_t> buildUniformValue(T value) {
+ std::vector<uint8_t> result;
+ result.resize(sizeof(value));
+ std::memcpy(result.data(), &value, sizeof(value));
+ return result;
+}
+
+} // namespace
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_selectsNoOpGamutMatrices) {
+ shaders::LinearEffect effect =
+ shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+
+ mat4 colorTransform = mat4::scale(vec4(.9, .9, .9, 1.));
+ auto uniforms =
+ shaders::buildLinearEffectUniforms(effect, colorTransform, 1.f, 1.f, 1.f, nullptr,
+ aidl::android::hardware::graphics::composer3::
+ RenderIntent::COLORIMETRIC);
+ EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
+ EXPECT_THAT(uniforms,
+ Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(colorTransform))));
+}
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_selectsGamutTransformMatrices) {
+ shaders::LinearEffect effect =
+ shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
+ .outputDataspace = ui::Dataspace::DISPLAY_P3,
+ .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+
+ ColorSpace inputColorSpace = ColorSpace::sRGB();
+ ColorSpace outputColorSpace = ColorSpace::DisplayP3();
+ auto uniforms =
+ shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
+ aidl::android::hardware::graphics::composer3::
+ RenderIntent::COLORIMETRIC);
+ EXPECT_THAT(uniforms,
+ Contains(UniformEq("in_rgbToXyz",
+ buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ())))));
+ EXPECT_THAT(uniforms,
+ Contains(UniformEq("in_xyzToRgb",
+ buildUniformValue<mat4>(mat4(outputColorSpace.getXYZtoRGB())))));
+}
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_respectsFakeInputDataspace) {
+ shaders::LinearEffect effect =
+ shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
+ .outputDataspace = ui::Dataspace::DISPLAY_P3,
+ .fakeInputDataspace = ui::Dataspace::DISPLAY_P3};
+
+ auto uniforms =
+ shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
+ aidl::android::hardware::graphics::composer3::
+ RenderIntent::COLORIMETRIC);
+ EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
+ EXPECT_THAT(uniforms, Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(mat4()))));
+}
+
+} // namespace android
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index a9380c6e79..d138495036 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -243,6 +243,10 @@ cc_library_shared {
],
afdo: true,
+
+ header_abi_checker: {
+ diff_flags: ["-allow-adding-removing-weak-symbols"],
+ },
}
cc_library_headers {
diff --git a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
index 57338f4c91..2affb60a0c 100644
--- a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
+++ b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
@@ -49,6 +49,8 @@ typedef struct {
// negative duration.
uint32_t error_count;
+ // Needed to make 32-bit arch struct size match 64-bit BPF arch struct size.
+ uint32_t padding0;
} UidTrackingInfo;
typedef struct {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4d25c5947b..5e9427ad87 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2507,7 +2507,7 @@ void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) {
}
void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
- if (!mDragState) {
+ if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId) {
return;
}
@@ -4765,9 +4765,11 @@ void InputDispatcher::setInputWindowsLocked(
// If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We
// could just clear the state here.
- if (mDragState &&
+ if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId &&
std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) ==
windowHandles.end()) {
+ ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str());
+ sendDropWindowCommandLocked(nullptr, 0, 0);
mDragState.reset();
}
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 91a666c699..df4307101f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -6407,6 +6407,58 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
mSecondWindow->consumeMotionMove();
}
+TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
+ performDrag();
+
+ // Update window of second display.
+ sp<FakeWindowHandle> windowInSecondary =
+ new FakeWindowHandle(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
+ mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
+
+ // Let second display has a touch state.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(SECOND_DISPLAY_ID)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(100))
+ .build()));
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN,
+ SECOND_DISPLAY_ID, 0 /* expectedFlag */);
+ // Update window again.
+ mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
+
+ // Move on window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->assertNoEvents();
+
+ // Move to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(true, 150, 50);
+ mSecondWindow->consumeDragEvent(false, 50, 50);
+
+ // drop to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
diff --git a/services/powermanager/WorkSource.cpp b/services/powermanager/WorkSource.cpp
index 1006a0666f..64a5499084 100644
--- a/services/powermanager/WorkSource.cpp
+++ b/services/powermanager/WorkSource.cpp
@@ -28,9 +28,16 @@ status_t WorkSource::readFromParcel(const android::Parcel *parcel) {
return BAD_VALUE;
}
int32_t num;
+ int32_t workChainCount;
status_t ret = parcel->readInt32(&num)
?: parcel->readInt32Vector(&mUids)
- ?: parcel->readString16Vector(&mNames);
+ ?: parcel->readString16Vector(&mNames)
+ ?: parcel->readInt32(&workChainCount);
+
+ if (ret == OK && workChainCount > 0) {
+ // We don't yet support WorkChains in native WorkSources.
+ return BAD_VALUE;
+ }
return ret;
}
@@ -43,7 +50,8 @@ status_t WorkSource::writeToParcel(android::Parcel *parcel) const {
return parcel->writeInt32(mUids.size())
?: parcel->writeInt32Vector(mUids)
- ?: parcel->writeString16Vector(mNames);
+ ?: parcel->writeString16Vector(mNames)
+ ?: parcel->writeInt32(-1);
}
} // namespace android::os
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index 2d1558a33f..962784cbae 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -31,6 +31,7 @@ cc_test {
"PowerHalWrapperAidlTest.cpp",
"PowerHalWrapperHidlV1_0Test.cpp",
"PowerHalWrapperHidlV1_1Test.cpp",
+ "WorkSourceTest.cpp",
],
cflags: [
"-Wall",
diff --git a/services/powermanager/tests/WorkSourceTest.cpp b/services/powermanager/tests/WorkSourceTest.cpp
new file mode 100644
index 0000000000..bb9164ac57
--- /dev/null
+++ b/services/powermanager/tests/WorkSourceTest.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <optional>
+#define LOG_TAG "PowerHalLoaderTest"
+
+#include <android-base/logging.h>
+#include <android/WorkSource.h>
+#include <binder/Parcel.h>
+#include <gtest/gtest.h>
+
+#include <future>
+
+using namespace android;
+using namespace testing;
+
+TEST(WorkSourceTest, Parcel) {
+ std::vector<int32_t> uids = {1, 2};
+ using Names = std::vector<std::optional<String16>>;
+ std::optional<Names> names = std::make_optional<Names>({std::make_optional(String16("name"))});
+ os::WorkSource ws{uids, names};
+
+ Parcel p;
+ ws.writeToParcel(&p);
+ p.setDataPosition(0);
+
+ os::WorkSource otherWs;
+ otherWs.readFromParcel(&p);
+
+ EXPECT_EQ(ws, otherWs);
+ EXPECT_EQ(uids, otherWs.getUids());
+ EXPECT_EQ(names, otherWs.getNames());
+}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f8c53c338e..d9c89cd821 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -358,8 +358,6 @@ void BufferLayer::onPostComposition(const DisplayDevice* display,
// composition.
if (!mBufferInfo.mFrameLatencyNeeded) return;
- mAlreadyDisplayedThisCompose = false;
-
// Update mFrameEventHistory.
finalizeFrameEventHistory(glDoneFence, compositorTiming);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1a5b925b13..3875f151cb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -34,6 +34,8 @@
#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
+#define EARLY_RELEASE_ENABLED false
+
namespace android {
using PresentState = frametimeline::SurfaceFrame::PresentState;
@@ -79,10 +81,10 @@ void BufferStateLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFen
// For example we can only use it if all the displays are client comp, and we need
// to merge all the client comp fences. We could do this, but for now we just
// disable the optimization when a layer is composed on multiple displays.
- if (mAlreadyDisplayedThisCompose) {
+ if (mClearClientCompositionFenceOnLayerDisplayed) {
mLastClientCompositionFence = nullptr;
} else {
- mAlreadyDisplayedThisCompose = true;
+ mClearClientCompositionFenceOnLayerDisplayed = true;
}
// The previous release fence notifies the client that SurfaceFlinger is done with the previous
@@ -373,7 +375,7 @@ bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>&
addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX);
mDrawingState.bufferSurfaceFrameTX.reset();
}
- } else if (mLastClientCompositionFence != nullptr) {
+ } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
mLastClientCompositionFence,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2e7a377feb..e65aa7393c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -147,6 +147,8 @@ public:
bool hasProtectedLayers() const;
+ bool hasSolidColorLayers() const;
+
private:
CachedSet() = default;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 29d33662ab..5aec7c2e88 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -248,6 +248,12 @@ public:
bool isProtected() const {
return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
}
+
+ bool hasSolidColorCompositionType() const {
+ return getOutputLayer()->getLayerFE().getCompositionState()->compositionType ==
+ aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
+ }
+
float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; }
void dump(std::string& result) const;
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index aac478de40..c3385a8a8b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1300,6 +1300,7 @@ std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
const auto& layerState = layer->getState();
const auto* layerFEState = layer->getLayerFE().getCompositionState();
auto& layerFE = layer->getLayerFE();
+ layerFE.setWasClientComposed(nullptr);
const Region clip(viewportRegion.intersect(layerState.visibleRegion));
ALOGV("Layer: %s", layerFE.getDebugName());
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 5ffbb7ff91..1bb9d0eb63 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -377,6 +377,7 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t
auto requestedCompositionType = outputIndependentState->compositionType;
if (requestedCompositionType == Composition::SOLID_COLOR && state.overrideInfo.buffer) {
+ // this should never happen, as SOLID_COLOR is skipped from caching, b/230073351
requestedCompositionType = Composition::DEVICE;
}
@@ -416,7 +417,12 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer,
if (outputDependentState.overrideInfo.buffer != nullptr) {
displayFrame = outputDependentState.overrideInfo.displayFrame;
- sourceCrop = displayFrame.toFloatRect();
+ sourceCrop =
+ FloatRect(0.f, 0.f,
+ static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+ ->getWidth()),
+ static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+ ->getHeight()));
}
ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top,
@@ -790,7 +796,7 @@ std::vector<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionList() co
// framebuffer space of the override buffer to layer space.
const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
- const Rect boundaries = transform.transform(getState().overrideInfo.displaySpace.getContent());
+ const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
LayerFE::LayerSettings settings;
settings.geometry = renderengine::Geometry{
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index d15b0a7646..641b806aec 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -388,6 +388,12 @@ bool CachedSet::hasProtectedLayers() const {
[](const Layer& layer) { return layer.getState()->isProtected(); });
}
+bool CachedSet::hasSolidColorLayers() const {
+ return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
+ return layer.getState()->hasSolidColorCompositionType();
+ });
+}
+
void CachedSet::dump(std::string& result) const {
const auto now = std::chrono::steady_clock::now();
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 0918510eef..1062b700dd 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -316,7 +316,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
- .displayFrame = mNewCachedSet->getBounds(),
+ .displayFrame = mNewCachedSet->getTextureBounds(),
.dataspace = mNewCachedSet->getOutputDataspace(),
.displaySpace = mNewCachedSet->getOutputSpace(),
.damageRegion = Region::INVALID_REGION,
@@ -356,7 +356,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers
state.overrideInfo = {
.buffer = currentLayerIter->getBuffer(),
.acquireFence = currentLayerIter->getDrawFence(),
- .displayFrame = currentLayerIter->getBounds(),
+ .displayFrame = currentLayerIter->getTextureBounds(),
.dataspace = currentLayerIter->getOutputDataspace(),
.displaySpace = currentLayerIter->getOutputSpace(),
.damageRegion = Region(),
@@ -498,6 +498,13 @@ void Flattener::buildCachedSets(time_point now) {
}
}
+ for (const CachedSet& layer : mLayers) {
+ if (layer.hasSolidColorLayers()) {
+ ATRACE_NAME("layer->hasSolidColorLayers()");
+ return;
+ }
+ }
+
std::vector<Run> runs = findCandidateRuns(now);
std::optional<Run> bestRun = findBestRun(runs);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 7038e8cda1..5290bd9cba 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -940,7 +940,7 @@ const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 8
84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
-const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{1002, 1003, 1004, 20044};
+const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f};
const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
Rect{1005, 1006, 1007, 1008}};
const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b1de9665d5..be16942d40 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2194,6 +2194,37 @@ Rect Layer::getInputBounds() const {
return getCroppedBufferSize(getDrawingState());
}
+// Applies the given transform to the region, while protecting against overflows caused by any
+// offsets. If applying the offset in the transform to any of the Rects in the region would result
+// in an overflow, they are not added to the output Region.
+static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
+ const std::string& debugWindowName) {
+ // Round the translation using the same rounding strategy used by ui::Transform.
+ const auto tx = static_cast<int32_t>(t.tx() + 0.5);
+ const auto ty = static_cast<int32_t>(t.ty() + 0.5);
+
+ ui::Transform transformWithoutOffset = t;
+ transformWithoutOffset.set(0.f, 0.f);
+
+ const Region transformed = transformWithoutOffset.transform(r);
+
+ // Apply the translation to each of the Rects in the region while discarding any that overflow.
+ Region ret;
+ for (const auto& rect : transformed) {
+ Rect newRect;
+ if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
+ __builtin_add_overflow(rect.top, ty, &newRect.top) ||
+ __builtin_add_overflow(rect.right, tx, &newRect.right) ||
+ __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
+ ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
+ debugWindowName.c_str());
+ continue;
+ }
+ ret.orSelf(newRect);
+ }
+ return ret;
+}
+
void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
Rect tmpBounds = getInputBounds();
if (!tmpBounds.isValid()) {
@@ -2256,7 +2287,8 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDi
info.transform = inputToDisplay.inverse();
// The touchable region is specified in the input coordinate space. Change it to display space.
- info.touchableRegion = inputToDisplay.transform(info.touchableRegion);
+ info.touchableRegion =
+ transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName);
}
void Layer::fillTouchOcclusionMode(WindowInfo& info) {
@@ -2391,6 +2423,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp
// If the layer is a clone, we need to crop the input region to cloned root to prevent
// touches from going outside the cloned area.
if (isClone()) {
+ info.isClone = true;
if (const sp<Layer> clonedRoot = getClonedRoot()) {
const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3988e51f84..24abad9b45 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -620,6 +620,7 @@ public:
void setWasClientComposed(const sp<Fence>& fence) override {
mLastClientCompositionFence = fence;
+ mClearClientCompositionFenceOnLayerDisplayed = false;
}
const char* getDebugName() const override;
@@ -1035,7 +1036,7 @@ protected:
mutable bool mDrawingStateModified = false;
sp<Fence> mLastClientCompositionFence;
- bool mAlreadyDisplayedThisCompose = false;
+ bool mClearClientCompositionFenceOnLayerDisplayed = false;
private:
virtual void setTransformHint(ui::Transform::RotationFlags) {}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index cbea77e8fb..639ba5a3f1 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -177,6 +177,11 @@ void EventThreadConnection::onFirstRef() {
}
binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
+ std::scoped_lock lock(mLock);
+ if (mChannel.initCheck() != NO_ERROR) {
+ return binder::Status::fromStatusT(NAME_NOT_FOUND);
+ }
+
outChannel->setReceiveFd(mChannel.moveReceiveFd());
outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
return binder::Status::ok();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index c406478c17..adb96fd462 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -112,7 +112,8 @@ public:
private:
virtual void onFirstRef();
EventThread* const mEventThread;
- gui::BitTube mChannel;
+ std::mutex mLock;
+ gui::BitTube mChannel GUARDED_BY(mLock);
std::vector<DisplayEventReceiver::Event> mPendingEvents;
};
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 9c6e56dfa8..3c8dc64f10 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -118,16 +118,17 @@ void OneShotTimer::loop() {
auto triggerTime = mClock->now() + mInterval;
state = TimerState::WAITING;
while (true) {
- mWaiting = true;
- constexpr auto zero = std::chrono::steady_clock::duration::zero();
- // Wait for mInterval time to check if we need to reset or drop into the idle state.
- struct timespec ts;
- calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
- int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
- if (result && errno != ETIMEDOUT && errno != EINTR) {
- std::stringstream ss;
- ss << "sem_clockwait failed (" << errno << ")";
- LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+ // Wait until triggerTime time to check if we need to reset or drop into the idle state.
+ if (const auto triggerInterval = triggerTime - mClock->now(); triggerInterval > 0ns) {
+ mWaiting = true;
+ struct timespec ts;
+ calculateTimeoutTime(triggerInterval, &ts);
+ int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+ if (result && errno != ETIMEDOUT && errno != EINTR) {
+ std::stringstream ss;
+ ss << "sem_clockwait failed (" << errno << ")";
+ LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+ }
}
mWaiting = false;
@@ -136,7 +137,7 @@ void OneShotTimer::loop() {
break;
}
- if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) {
+ if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= 0ns) {
triggerTimeout = true;
state = TimerState::IDLE;
break;
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index e611658bfd..3a918a1660 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <scheduler/Fps.h>
#include <scheduler/Timer.h>
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 97d8aef88a..6a17cd8881 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6747,6 +6747,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
clientCompositionDisplay.orientation = rotation;
clientCompositionDisplay.outputDataspace = dataspace;
+ clientCompositionDisplay.currentLuminanceNits = displayBrightnessNits;
clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
clientCompositionDisplay.renderIntent =
static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(renderIntent);
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 027a15e3f6..a6d7f5834f 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -465,4 +465,22 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) {
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, SetBuffer_OverwriteBuffersWithNull) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Create transaction with a buffer.
+ Transaction transaction;
+ transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ releaseCallback->getCallback());
+
+ // Call setBuffer on the same transaction with a null buffer.
+ transaction.setBuffer(layer, nullptr, std::nullopt, 0, releaseCallback->getCallback());
+
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 597e5e71a2..aafc323a9b 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -130,6 +130,40 @@ TEST_F(OneShotTimerTest, DISABLED_resetBackToBackTest) {
EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
+// TODO(b/186417847) This test is new and passes locally, but may be flaky
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackSlowAdvanceTest) {
+ fake::FakeClock* clock = new fake::FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
+ mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<fake::FakeClock>(clock));
+ mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+ mIdleTimer->reset();
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+
+ clock->advanceTime(200us);
+ mIdleTimer->reset();
+
+ // Normally we would check that the timer callbacks weren't invoked here
+ // after resetting the timer, but we need to precisely control the timing of
+ // this test, and checking that callbacks weren't invoked requires non-zero
+ // time.
+
+ clock->advanceTime(1500us);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1100us).has_value());
+ mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+ mIdleTimer->stop();
+ clock->advanceTime(2ms);
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+}
+
TEST_F(OneShotTimerTest, startNotCalledTest) {
fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,